6.5. Filtering by
Category
Displaying all unused photos might seem
acceptable right now, but we have only nine photos. If there were
900, it would quickly become unusable. So, our final feature in
this chapter will be to display only the unused photos in a
particular category.
The first thing to do in our controller is get a
list of all categories that can populate the drop-down selection
box. Edit photos/app/controllers/slideshows_controller.rb,
and add this line to the end of the
edit method:
@all_categories = Category.find(:all, :order=>"name")
This line retrieves a list of categories that
can populate a drop-down selection box that the user will use to
display only those unused photos that are in the selected
category.
Now, edit photos/app/views/slideshows/edit.rhtml,
and add this right after the
'Play this Slideshow' line:
<p>
<label for="category_id">Filter "Unused Photos" on this Category</label><br/>
<%= collection_select(:category, :id, @all_categories, :id, :long_name) %>
<%= observe_field(:category_id,
:frequency => 2.0,
:update => 'slideshow-photos',
:url => { :action => 'change_filter'},
:with => 'category_id' ) %>
</p>
The collection_select helper is
normally used inside an HTML form, but here we are using it because
it conveniently knows how to display a collection in a drop-down
box. It will never be submitted as part of a form.
As shown, the observe_field helper
checks the category drop-down box for changes every two seconds.
When a change is detected, an Ajax request is fired off to the
change_filter method, which returns new HTML (that has
been appropriately filtered) to replace the
slideshow-photos .
The Category model class automatically
shows a collection of all photos that are in a particular category.
However, we need to get a collection of photos that are in a given
category and in all of its child categories.
Edit photos/app/models/category.rb, and add this
method:
def photos_including_child_categories
result = photos.clone
children.each do |c|
c.photos_including_child_categories.each {|p|
result << p if not result.include? p}
end
result
end
This method recursively collects a list of all
photos in its own category and all of its child categories. You can
use this in to get the list of unused photos to display.
In the meantime, edit photos/app/controllers/slideshows_controller.rb
to add the change_filter
method:
def change_filter
slideshow_id = session[:slideshow].id
category_id = params[:category_id] || 1
session[:category_id] = category_id
@slideshow = Slideshow.find(slideshow_id)
session[:slideshow] = @slideshow
@photos = unused_photos(@slideshow)
render_partial 'photo_picker'
end
This method stores the chosen category
id in the session hash, retrieves a new list of unused
photos, and then renders the photo_picker. Notice the bold
code line in the previous code. This line tries to retrieve the
category id from the request parameters. If there aren't
any parameters, params[:category_id] returns nil,
and the || operator returns the rightmost argument ("1" in
this case).
Also, in this slideshow controller, we need to
update the method that retrieves the unused photos to pay attention
to the category setting. Do so by editing the
unused_photos method; then replace the line all_photos
= Photo.find(:all) with the following:
category_id = session[:category_id] || 1
session[:category_id] = category_id
category = Category.find(category_id)
all_photos = category.photos_including_child_categories
We're done; we've added category filtering! Fire
up your browser, and try it (you may need to assign some categories
to some unused photos). Now it looks like
"#rubyrails-chp-6-fig-7">Figure 6-7.
We've come a long way in a very short time. With
fewer than 200 lines of code, we've added drag-and-drop capability
to add and reorder slides. We've also added the core capability to
actually show a slideshow. Ajax made our application much easier to
use and more attractive. Next, we'll look into testing this
application.
 |