I am rebuilding one of my favorite intranet apps in Rails. I use a lot
of access control - not just on model-level, but down to specific fields
inside one model.
For example:
User A is allowed to modify the field "Meeting.modulex", because he is
member of a certain group
User B is not allowed to modify the same field.
Three things sping into my mind at this:
a) The standard CRUD setup actually uses the view to dictate, which
fields, a user may edit (which of course could be compromised)
b) The model validation scheme only cares about filling the fields with
valid values
c) There is a convention saying that the controller should be "thin",
and the model "fat"
I am very much in doubt, where i should place my Access control. On one
hand it is easier to put it into the controller, since it sometimes
spans multiple models. On the other hand, this isn't very DRY.
I am interested in hearing how other users have tackled this problem.
For those of us too lazy to figure it out, it belongs in the
acl_system2 plugin
I took a look at acl_system2. If I understand it correctly, it creates
access-control on the controller. Thereby signifying, that
access-limitation to specific model-fields should be placed in the
controller.
The approach that we'd typically take would be to only render the
input field for the secretary. That could mean either:
- Views for Users in the secretary role have some conditional logic
that renders the 'show_on_screen' field
- A unique view specifically tasked for 'show_on_screen' is created
and only Users in the secretary role are given access
In either case, the #update action can remain the same.
Obviously that approach is not bulletproof. Someone who _really_
wants to set the value could find a way to hack an http request with
the appropriate attributes. If you want to lock it down even tighter,
you could work along the lines of creating a method to update the
attributes that takes roles into account, and then invoke that method
from the controller (where the user is in context as Mark explains
above). It probably makes sense to wrap the method in using
alias_method_chain:
class Meeting
def update_attributes_with_role(role, attributes={})
attributes.each_pair{|attr, val| attributes.delete(:attr)
unless ...authorized...}
update_attributes_without_role attributes
end
alias_method_chain :update_attributes, :role
...
Andy: My intial concern _was_ exactly that I wanted to guard against
phony HTML-forms, where the user has added the extra field himself. So
just rendering the view without "show_on_screen" attribute would not be
enough IMHO.
I didn't know this aliass_method_chain - nice touch. I will research
this some more. Thank you.
Andy: My intial concern _was_ exactly that I wanted to guard against
phony HTML-forms, where the user has added the extra field himself. So
just rendering the view without "show_on_screen" attribute would not
be
enough IMHO.