Bagzli
Bagzli

Reputation: 6569

rails pass value from drop down

What would be the most efficient way of accomplishing the following: Grab a value from a drop down and pass it with a search function into model.

Here is the html for search:

<p>
  <%= text_field_tag :search, params[:search] %>
  <%= submit_tag "Search", :name => nil %>
</p>

Here is the code in controller:

def index
  @trucks = Truck.search(params[:search])

  respond_to do |format|
  format.html # index.html.erb
  format.json { render json: @trucks }
end

end

Here is the model

def self.search(search)
  if search
    where('truck_no LIKE ?', "%#{search}%")
  else
    scoped

end

In the model I have 'truck_no LIKE ?'

I would like it to become column_name + ' LIKE ?' where I pass in the column name through the method parameter. How would I setup my drop down list in the html and pass it all the way to the controller? What is the best way of accomplishing this?

Edit: forgot to mention, the drop down should display things like Truck Number, but pass in the value truck_no

Upvotes: 2

Views: 2683

Answers (1)

MrYoshiji
MrYoshiji

Reputation: 54882

Here is the base for you:

# view
<p>
  <%= text_field_tag :search, params[:search] %>
  <%= select_tag :search_column, options_for_select(Truck.column_names, params[:search_column]) %>
  <%= submit_tag "Search", :name => nil %>
</p>

# controller
def index
  @trucks = Truck.search(params[:search], params[:search_column])

# model
def self.search(keyword, column_name)
  if self.column_names.include?(column_name.to_s)
    where("trucks.#{column_name} LIKE ?", "%#{keyword}%")
  else
    scoped
  end
end

There is several improvements you can do here:

  • Add the translation to the select_field_tag to see the translated attributes
  • Add a class method that will return only the columns you want to be "searchable"
  • Use the ActiveRecord's method sanitize to make sure the column_name is safe

I can help you with the improvements if you need.


Class Method returning the searchable columns:

Here we have a choice, should we get all the columns and take off some of them? OR should we just select the one we want? The first option implies that if you add an attribute to the model, it will be by default added to the options, unless you take it off. The reverse will happen with the second option:

# model
# This method should return the columns defined in the `wanted_columns` array
def self.searchable_columns
  wanted_columns = ['name', 'description', 'etc' ]
  self.column_names.select{ |column| wanted_column.include?(column) }
end
# This method will return the columns NOT IN the `unwanted_columns` array
def self.searchable_columns
  unwanted_column = ['id', 'created_at', 'updated_at']
  self.column_names.reject{ |column| unwanted_column.include?(column) }
end

# view
<%= select_tag :search_column, options_for_select(Truck.searchable_columns, params[:search_column]) %>

Display the translation and not the column name

# model
# This method return an array of arrays formatted like following:
# [ ['Name', 'name'], ['Truck Number', 'truck_no'] ]
def self.translated_searchable_columns
  columns = self.searchable_columns
  result = columns.map{ |column| [Truck.human_attribute_name(column.to_sym), column] }
  result
end

# view
<%= select_tag :search_column, options_for_select(Truck.translated_searchable_columns, params[:search_column]) %>

Upvotes: 5

Related Questions