Melanie C. wrote:
Hi,
I’ve created a Rails application and am having a problem listing by a
particular category in an associated table. I followed the instructions
found at the O’Reilly tutorial
(Radar – O’Reilly) but
have not had success. Can anyone please outline a better set of
instructions than in the “Showing Recipes in a Category” section? Thank
you for your time!
[Just in case this is what you are stuck on, did you miss the <% end %>
required to match the <% if … %> added in recipe/list.rhtml? If that’s
not the answer, read on.]
Assuming everything was still working at the end of page 2, here’s a
breakdown of what is added in “Showing Recipes in a Category”:
-
The user needs to be able to choose which category to focus on. This
is enabled by turning the category name, displayed in the list, into a
link. It was
<%= recipe.category.name %>
and it becomes
<%= link_to recipe.category.name,
:action => “list”,
:category => “#{recipe.category.name}” %>
This is a link to the “list” action in the current controller, and it
also provides a “category” parameter whose value is the name of the
category of the recipe.
[I don’t know why Curt used “#{recipe.category.name}”
rather than recipe.category.name - either works for me.]
If you just make this change to the recipe list.rhtml, the list should
still work, the link should show, and when you hover over it (or view
its source in the browser) you should see a URL like
http://127.0.0.1:3000/recipe/list?category=Snacks
…but if you click on it, you should still see the whole list,
because nothing has been done to capture that parameter and use it to
filter the list.
-
In the RecipeController, the following line is added to the list
method:
@category = @params[‘category’]
This captures the value of the “category” parameter from the HTTP
request, and puts it in the @category instance variable of the
RecipeController instance handling the request. If there is no
“category” parameter - as when you list all recipes - @category will be
nil.
Rails “magically” makes all the controller’s instance variables
available to the view.
The whole of the list method is now:
def list
@category = @params[‘category’]
@recipes = Recipe.find_all
end
When the list action has executed, Rails will (by default) use a
template of the same name (list.rhtml) to render the response.
As well as putting the category name (or nil) in @category, the action
has put an array of all the recipes in @recipes.
If you make this change, everything should still work, but the list will
still show all the recipes.
[In a real application, which might have thousands of recipes, you would
expect the filtering by category to be done in the database query, but
Curt has kept the original Recipe.find_all and put the filtering in the
view.]
[In the year since this article was published there have been many
changes in Rails, and corresponding changes in recommended programming
style. These days you would write:
def list
@category = params[‘category’]
@recipes = Recipe.find(:all)
end
…but the old forms still work, for backwards compatibility.]
- The final change is to filter the list in the view, if @categories is
not nil. In the recipes list.rhtml, the control structure
<% @recipes.each do |recipe| %>
…
<% end %>
becomes
<% @recipes.each do |recipe| %>
<% if (@category == nil) || (@category == recipe.category.name)%>
…
<% end %>
<% end %>
So a recipe is only displayed as a row in the list if its category name
is the same as @category, or if @category is nil.
Oh - Curt didn’t point out in his description that the <% if … %>
needs a corresponding <% end %> - perhaps that was your problem.
I hope this helps - if not, please tell us more about the symptoms.
Justin