Displaying a subset of items from an association

Posted by blackrat on December 16, 2006

As of this post I have two classes joined by have_and_belongs_to_many (habtm), and I figured that I’d like to be able to click on an entry in one and have a subset index of the other appear. Not an uncommon task and used by tags and blogs everywhere. Rather than search for a snippet, I thought I’d give it a go myself first.What I came up with surprised me with it’s simplicity and may not be the most expedient manner, but seems to be a neat and easy extension of the index method.

The obvious way was to add an entry to the list of actions which can be applied to a tag item. A simple addition of a “Show Users” link pointing to the Users controller and passing a tag_id parameter was the starting point for this.

Opening up app/views/tags/index.rhtml, we can add a user_path with :tag_id=>tag as the parameter. This will translate to http://localhost:3000/users?tag_id=x.


<h1>Listing tags</h1>

<table>
  <tr>
    <th>Name</th>
  </tr>

<% for tag in @tags %>
  <tr>
    <td><%=h tag.name %></td>
    <td><%= link_to 'Users', user_path(:tag_id=>tag) %></td>
    <td><%= link_to 'Show', tag_path(tag) %></td>
    <td><%= link_to 'Edit', edit_tag_path(tag) %></td>
    <td><%= link_to 'Destroy', tag_path(tag), :confirm => 'Are you sure?', :method => :delete %></td>
  </tr>
  <% end %>
</table>
<br />
<%= link_to 'New tag', new_tag_path %>

This will then allow the following in the index view of the users controller.

  # GET /users
  # GET /users.xml
  def index
    @tag=Tag.find(params[:tag_id]) if params[:tag_id]
    @users = @tag.users || throw rescue User.find(:all)

    respond_to do |format|
      format.html # index.rhtml
      format.xml  { render : xml => @users.to_xml }
    end
  end

Note the unusual throw rescue construct. Since @tag.users would throw an exception, as well as having a nil possibility, this is the dryest form of getting the original User.find(:all) executed on error. I mainly wanted to see if this would work, and it does! I’m really starting to like what you can do with Ruby.

Trackbacks

Use this link to trackback from your own site.

Comments

You must be logged in to leave a response.