I am not sure what the proper Rails 3 way to do this is. I want to have filter criteria fields at the top of my index view that will filter the data.
What I have below works for filtering my list, but I also want the filter fields to be re-populated with what the current filter is, and I can't figure out how to do that. The method I got working below also doesn't feel like the "right" way to accomplish this, since it relies on things like passing empty string to the field helper methods in my view.
Controller:
def index
@animals = Animal.by_color(params[':color']).by_age(params[':age']).paginate(:page => params[:page])
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @animals }
end
end
View:
<h1>Listing Animals</h1>
Filter By:
<%= form_for(:animal, :url => { :action => "index" }, :html => {:method => :get} ) do |f| %>
<div>
Color: <%= text_field'', ':color', :size => 10 ) %>
Age: <%= text_field('', ':age') %>
<%= f.submit "Filter List" %>
</div>
<% end %>
<%= will_paginate %>
...
I am using the scope methods in my Model, which work very slick. I am just fuzzy about how the Controller "params" method and the View methods "form_for", "text_field" map to each other. Any ideas on how to refactor this and also get my filter fields populated when the list is currently filtered?
Solution!
开发者_开发百科Controller:
def index
@search = Animal.new(params[:animal])
@animals = Animal.by_color(@search.color)...
....
View:
<%= form_for(@search, :url => { :action => "index" }, :html => {:method => :get} ) do |f| %>
<%= f.text_field(:color)
The form population works by creating the @search object in my contorller (in addition to my main animals object). Then using form_for to create a for around it.
What you want is a "query by example", which would work roughly like this in controller:
@filter = Animal.new(params[:filter])
@animals = @filter.get_scope.paginate(:page => params[:page])
and in the controller you could do a form_for
on that example record, but I am not aware of any
modern Rails plugins that do exactly that. There certainly should be something like this though, look thoroughly. I bet you could write something similar in a couple of hours though (just grab the attributes hash of your filter record into the :conditions
of the scope, rougly like so - NOT TESTED THOUGH):
def get_scope
# remove all nill attrs
non_default_attrs = self.attributes
self.columns.each do | col |
# Ignore columns that have default values
non_default_attrs.delete(col.name) if non_default_attrs[col.name] == column.default
# Ignore columns whose values are nils
non_default_attrs.delete(col.name) if non_default_attrs[col.name].nil?
end
where(non_default_attrs.symbolize_keys)
end
controller
@search = params[:animal]
@animals = Animal.by_color(params[:color]).by_age(params[:age]).paginate(:page => params[:page])
views
<h1>Listing Animals</h1>
Filter By:
<%= form_tag animals_path do %>
<div>
Color: <%= text_field_tag 'color', :size => 10 %>
Age: <%= text_field_tag 'age' %>
<%= submit_tag "Filter List" %>
</div>
<% end %>
<%= will_paginate %>
精彩评论