advice for restful design?
I h开发者_运维技巧ave a question regarding the best way to structure a restful design for a particular part of an app I am working on.
Some background on the app:
User has_one :settings_for_email
There is a profile_controller, which has a show action.. Something like:
def show
@user = current_user
end
Initially this was setup so that the form would post back to the profile controller.. something like:
<% form_for profile_path(@user) do |f| %>
<% f.fields_for :settings_for_email do |s| %>
<% ... form fields ... %>
<% end %>
<% end %>
And the profile_controller's update action did something like this:
def update
@user = User.find(params[:id])
@user.settings_for_email.update_attributes(params[:user][:settings_for_email])
end
....
I did not like this because it has a vulnerability that allows the user record being edited to be changed... Changing that to be @user = current_user, didn't make much sense to me because it's an update action requiring an ID of somekind.. So going to either /profile/123 or profile/456 would yield the same user record (since it would be using current_user, params[:id] would be superfluous).. That seems weird to me.
As a side note, I needed a controller action to reset the user's email settings to their defaults.
So, what I ended up doing was making a new route:
resource :settings_for_email, :only => :create do
post :reset, :on => :member
end
and then creating a settings_for_email_controller:
#settings_for_email_controller.rb
def create
current_user.settings_for_email.update_attributes(params[:settings_for_email_controller])
redirect_to profile_url
end
def reset
current_user.reset_settings_for_email!
redirect_to profile_url
end
...
But then I wondered, can this be improved in any way?
If I truly wanted to make this 100% restful, would it be best to do:
#update_settings_for_email_controller:
def create
current_user.settings_for_email.update_attributes(params[:settings_for_email_controller])
redirect_to profile_url
end
#reset_settings_for_email_controller:
def create
current_user.reset_settings_for_email!
redirect_to profile_url
end
I am on the fence about this, because it seems a little silly to have two controllers for this.. But I couldn't think of a better way to do it. Again, using update requires an id, and so does destroy. I was originally thinking it would be nice to use the destroy action to perform the "reset", but-- again.. it would involve a wasted id parameter. So I thought I'd ask here what you guys think for this sort of thing?
I think you're mixing things up a bit: There are two users here. There's the user whose details need changing, and then there's the user who does the actual changing. Commonly, they would be one and the same, but not always, for example: an admin may need to reset some user's password.
The id of the user record being changed is what should go into the REST interface, and User.find params[:id]
should take care of that just fine.
The user doing the changing has to do with authentication (ensuring that this user is who she claims she is) and authorization (is that use allowed to make that change?). That's the user you get when calling current_user
. Gems like devise help with that.
In general, your controller actions should get the current_user
, and the target user, ensure that the current user is authorized to perform the action on the target user (because they're the same user, current user is admin or whatever other logic you have in your application) and only then perform that action.
精彩评论