RESTful Rails with Associations explored
I’ve recently switched to EdgeRails for Rails 1.2 RC1, and decided to try out the resource_scaffold to create RESTful classes. There’s not that much documentation on this so far, so I thought I’d combine using these with creating habtm associations. What follows is a walkthrough of the initial creation of a has_and_belongs_to_many association and the changes required to get it to do what I want within the scaffold_resource RESTful framework.
First of all, some MVC creation. I like the fact that tests are now generated by the scaffold_resource, but be warned that if you modify your migrations, you also need to change the test/fixtures/*.yml files to reflect the changes. Otherwise, your unit tests will start to error. We’re going to be using the extension to scaffold_resource and generate a string “name” for both tables, which will also generate the fixture unit test for that column.
cd blog
script/generate scaffold_resource user name:string
script/generate scaffold_resource tag name:string
script/generate migration create_tags_users
class CreateTagsUsers < ActiveRecord::Migration
def self.up
create_table :tags_users, :id=>false do |t|
t.column :tag_id, :integer
t.column :user_id, :integer
end
end
def self.down
drop_table :tags_users
end
end
Don’t forget the :id=>false (unless you know what you are doing, that is).
Next, modify the models to point to each other. app/models/tag.rb and app/models/user.rb become:
class Tag < ActiveRecord::Base
has_and_belongs_to_many :users
end
and
class User < ActiveRecord::Base
has_and_belongs_to_many :tags
end
At this point, I like to run the migrate and the tests which were created by the scaffold_resource.
Ok. For app/views/users the following become the new views
index.rhtml
<h1>Listing users</h1>
<table>
<tr>
<th>Name</th>
<th>Tags</th>
</tr>
<% for user in @users %>
<tr>
<td><%=h user.name %></td>
<td>
<% for tag in user.tags %>
<%= tag.name %><br />
<% end %>
</td>
<td><%= link_to 'Show', user_path(user) %></td>
<td><%= link_to 'Edit', edit_user_path(user) %></td>
<td><%= link_to 'Destroy', user_path(user), :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
</table>
<br />
<%= link_to 'New user', new_user_path %>
new.rhtml
<h1>New user</h1>
<%= error_messages_for :user %>
<% form_for(:user, :url => users_path) do |f| %>
<p>
<b>Name</b><br />
<%= f.text_field :name %>
</p>
<p>
<b>Tags</b><br />
<% for tag in @tags %>
<br />
<input type="checkbox"
id="<%=tag.id%>"
name="tag_ids[]"
value="<%=tag.id%>"
>
<%=tag.name%>
<% end %>
</p>
<p>
<%= submit_tag "Create" %>
</p>
<% end %>
<%= link_to 'Back', users_path %>
show.rhtml
<p>
<b>Name:</b>
<%=h @user.name %>
</p>
<p>
<b>Tags:</b>
<% for tag in @user.tags %>
<%= tag.name %><br />
<% end %>
</p>
<%= link_to 'Edit', edit_user_path(@user) %> |
<%= link_to 'Back', users_path %>
and finally, edit.rhtml
<h1>Editing user</h1>
<%= error_messages_for :user %>
<% form_for(:user, :url => user_path(@user), :html => { :method => :put }) do |f| %>
<p>
<b>Name</b><br />
<%= f.text_field :name %>
</p>
<p>
<b>Tags</b><br />
<% for tag in @tags %>
<br />
<input type="checkbox"
id="<%=tag.id%>"
name="tag_ids[]"
value="<%=tag.id%>"
<%if @user.tags.include? tag%>checked="checked"<%end%>
>
<%=tag.name%>
<% end %>
</p>
<p>
<%= submit_tag "Update" %>
</p>
<% end %>
<%= link_to 'Show', user_path(@user) %> |
<%= link_to 'Back', users_path %>
So not that much different to the CRUD scaffolding. I’m going to experiment more with this, and also with the through :class approach of handling associations, which I believe looks to have some strong advantages (not the least of which being that it gives you a join class rather than a join table).
Trackbacks
Use this link to trackback from your own site.
Comments
You must be logged in to leave a response.