I’m working on an application (on Edge Rails) that has a really long
user
profile page - viewed, of course, with a GET to /users/:id.
The editing side of things needs to be broken up into four
logically-grouped screens - say, contact info, work history, education,
and
personal info. These screens are essentially update-only - their “show”
counterpart is the whole profile at /users/:id. And the update can only
be
performed by current_user, so the :id is superfluous.
There is no Create function, and there is no Delete function.
So far, I see only two choices:
-
Don’t use RESTful routes at all. Change the GET to /users/show/:id,
and
do the updates with POSTs to /users/edit_contact_info,
/users/edit_education, etc. Put it all in users_controller. This is
the
path I’ve been taking, but it loses some of the simply_helpful magic.
-
Create RESTful routes, and manually draw them in routes.rb. This
seems
brittle, and I have to lie about (e.g.) “contact_info” belonging to the
collection instead of the member, since I don’t want the :id in the URL.
Plus, I think that means each of the four mini-edit pages has to go in
its
own, one-action controller! Ugly.
Is there a third way?
Jay L.
Sure. The Rails implementation of REST allows you to extend the
RESTful routes with a similar concept to choice #2 but without
“lying.”
Say you want a unique url that updates only the contact_info of a
user. You can extend the user routes in routes.rb like this:
map.resources :users, :member=>{:update_contact_info_of=>:post}
What this says is that there should be a url for an individual user
resource (a member of the users collection) with an action mapping
to “update_contact_info_of” that accepts only POST data. Just in case
it’s not obvious, :member is a hash for defining actions for
individual resources, keyed by the name of an action and with a value
of the allowed http methods (:get, :put, :post, :delete, :any).
By extending the users routes in that way, the form_for that wraps the
contact info can looks like this:
<% form_for :user, update_contact_info_of_user_path(@user) do |f| %>
…
<% end %>
HTH,
AndyV
On Aug 21, 2007, at 8:59 AM, AndyV wrote:
of the allowed http methods (:get, :put, :post, :delete, :any).
To me, this smells like RPC. There’s a verb in your URL, “update”.
You don’t need that, you’ve already said you’re updating because of PUT.
What I would do is define a singleton resource for profile.
map.resource :profile
The view for that profile is broken up, I gather from the original
question, into multiple forms. They can all PUT to the same
reasource, though, /profile. There’s nothing that says a PUT/update
has to include ALL the data for the resource.
Personally, I would add extra bits onto my profile resource, so a GET
of /profile/contact_info would show the view for editing the contact
info and /profile/work_history would show the view for editing the
work history.
Rails routing is extremely flexible. There is almost never a “has to
go somewhere I don’t want it to” with Rails routing.
HTH,
Michael
See below…
Michael D. Ivey wrote:
it’s not obvious, :member is a hash for defining actions for
You could also
map.resources :users, :collection => {:contact_info => :put}