I have a field on my User model that is protected because it determines clearance level. So it should be left protected and not mass-assignable. So even though attributes are protected by default in 3.2, that is actually the behavior I want.

However, on one controller method, I want to allow a manager to assign this field, for instance on user creation or user update.

How do I allow the assignment of that attribute for specific controller actions?

For example, I have my controller:

# app/controllers/admin/users_controller.rb

def create
    @user = User.new(params[:user])
# ...
end

Now what I would do is exclude clearance from params[:user], but it seems to get filtered out and raise and exception even before that line is reached (I tried putting a debugger right before that line and even comment it out, it still raised an exception).

Where do protected attributes get caught, if not when calling User#new?

有帮助吗?

解决方案

The Rails way to do this would be to assign the attributes without protection or to use an admin role:

@user = User.new
@user.assign_attributes(params[:user], :without_protection => true)
@user.save

However, I found this to be a little tedious so I wrote a gem called sudo_attributes that gives (in my opinion) a better API:

@user = User.sudo_new(params[:user])
@user.save

It mimics all of the Rails instantiation, creation, and updating methods (new, build, create, create!, update_attributes, etc).

其他提示

In the past, I favored giving this kind of operation its own contained method, that only sets this value:

# app/controllers/admin/users_controller.rb

def full_clearance
  User.find(params[:id]).update_attribute(:clearance, 'full')
end

def restricted_clearance
  User.find(params[:id]).update_attribute(:clearance, 'restricted')
end

Now looking at the Rails way Beerlington mentioned, I'd rather use roles, to give that particular action access to the clearance attribute:

# /app/models/user.rb

attr_accessible :attributes_accessible_by_default, ..., :clearance, :as => :manager

# app/controllers/admin/users_controller.rb

def create
    @user = User.new(params[:user].merge(:as => :manager)
# ...
end

In that case it's even possible, to give access based on a role attribute on the user:

# app/controllers/admin/users_controller.rb

def create
    @user = User.new(params[:user].merge(:as => current_user.role.to_sym)
# ...
end

but that might lead to errors being raised again.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top