0

I am creating a search tab where users can search restaurants with a certain type. I have 3 models: Restaurant, Type, and RestaurantType. Since one restaurant can have multiple types, I created a RestaurantType relations table.

How can I create such search tab?

The StackOverflow question I found closest to this was the following: ActiveRecord query through multiple joins, but it does not cover all I need. That said, I am still very new to Rails and maybe just need a more guided answer.

restaurant.rb

has_many :types, :through => :restaurant_types

type.rb

has_many :restaurants, :through => :restaurant_types

restaurant_type.rb

belongs_to :restaurant
belongs_to :type

restaurants_controller.rb (index action) (I'm also implementing search by name, which is an attribute of Restaurant)

@restaurants = Restaurant.joins(restaurant_type: :type).where 
    ("cast(type_id as text) LIKE ?", "%#{params[:type]}%")
@restaurants = @restaurants.where("restaurant_name LIKE ?", 
    "%#{params[:restaurant_name]}%").paginate(:page => params[:page], 
    :per_page => 8)

restaurants/index.html.erb (only the search part)

<%= form_tag(restaurants_path, :method => 'get') do %>
    <%= text_field_tag :restaurants_name, params[:restaurants_name], :placeholder => "Name" %>
    <%= select_tag :restaurant_type_id, options_for_select(Type.all.map{ |t| [t.type_name, t.id] }) %>
    <%= submit_tag "Search" %>
<% end %>

Notes:

  1. I added the "has_many ... :through => ..." associations manually after the migrations, and don't know if they count in this case.
  2. I am getting the following error when I reach the index: "Association named 'restaurant_type' was not found on Restaurant", which refers to the third line in my index page.

-

LOOKS NASTY, BUT SOLVED IT

restaurants_controller.rb

def index

    @types = RestaurantType.where("type_id LIKE ?", "%#{params[:type_id]}%")
    array = []
    @types.each do |t|
        @restaurant = Restaurant.find(t.restaurant_id)
        array.push(@restaurant)
    end
    @restaurant = WillPaginate::Collection.create(1, 6, array.length) do |pager|
      pager.replace array
    end
end

restaurants/index.html.erb (part of the form_tag)

<%= select_tag :type_id, options_for_select(Type.all.map{ |t| [t.type_name, t.id] }) %>

-

ANOTHER EDIT -- WORKS BETTER AND TOGETHER WITH OTHER SEARCH PARAMETERS

if (params[:type_id].to_f > 0)
    array = []
    RestaurantType.where("type_id = #{ params[:type_id] } ").each do |t|
        array.push(t.school_id)
    end
    @restaurants = Restaurant.where("restaurant_name LIKE ? AND cast(city_id as text) LIKE ? AND id in (?)", "%#{ params[:restaurant_name] }%", 
       "%#{params[:city_id]}%", array).paginate(:page => params[:page], :per_page => 6)

else
    @restaurants = Restaurant.where("restaurant_name LIKE ? AND cast(city_id as text) LIKE ?", "%#{params[:restaurant_name]}%", 
       "%#{params[:city_id]}%").paginate(:page => params[:page], :per_page => 6)
end
Community
  • 1
  • 1

2 Answers2

0

I think the error is coming from the join in restaurants_controller:

@restaurants = Restaurant.joins(restaurant_type: :type).where("cast(type_id as text) LIKE ?", "%#{params[:type]}%")

You must use the exact same name as you specified in the model...in this case, 'restaurant_types' instead of 'restaurant_type'.

However, you have already created the associations between your models in the model files, so you do not need to use a join. You can search this way:

@restaurants = Type.find(params[:restaurant_type_id]).restaurant.where('restaurant_name like ?', "%#{params[:restaurant_name]}%")

I would change the association in type.rb to:

has_many :restaurants, :through => :restaurant_types

Then the method to find restaurants from a type would be plural, and more intuitive.

chester
  • 297
  • 2
  • 13
0

I decided to create an array with all the restaurants with the selected Type. The algorithm goes over each object (restaurant_type) with the selected type, pushes it into an array, and paginates the array on the index.

It may take longer, but asymptotic analysis suggests T(n) is multiplied by a constant, which isn't that big a deal.

And thank you to the dude who answered here about paginating arrays: Paginating an Array in Ruby with Will_Paginate

restaurants_controller.rb

def index

    @types = RestaurantType.where("type_id LIKE ?", "%#{params[:type_id]}%")
    array = []
    @types.each do |t|
        @restaurant = Restaurant.find(t.restaurant_id)
        array.push(@restaurant)
    end
    @restaurant = WillPaginate::Collection.create(1, 6, array.length) do |pager|
      pager.replace array
    end
end

restaurants/index.html.erb (part of the form_tag)

<%= select_tag :type_id, options_for_select(Type.all.map{ |t| [t.type_name, t.id] }) %>

-

ANOTHER EDIT -- WORKS BETTER AND TOGETHER WITH OTHER SEARCH PARAMETERS

if (params[:type_id].to_f > 0)
    array = []
    RestaurantType.where("type_id = #{ params[:type_id] } ").each do |t|
        array.push(t.school_id)
    end
    @restaurants = Restaurant.where("restaurant_name LIKE ? AND cast(city_id as text) LIKE ? AND id in (?)", "%#{ params[:restaurant_name] }%", 
       "%#{params[:city_id]}%", array).paginate(:page => params[:page], :per_page => 6)

else
    @restaurants = Restaurant.where("restaurant_name LIKE ? AND cast(city_id as text) LIKE ?", "%#{params[:restaurant_name]}%", 
       "%#{params[:city_id]}%").paginate(:page => params[:page], :per_page => 6)
end
Community
  • 1
  • 1