Rails Devise attr_accessible problem

1.6k views Asked by At

Im trying to add devise authorization to my rails 3 app. Its all going well except Im also trying to follow this tutorial to dynamically set attr_accessible for role_ids only for admin users (I dont want regular users changing their role, but an admin should be able to do so)... the problem is, the railscast tutorial approach assumes I have access to change the controller behavior when in fact devise is handling all that under the hood.

Please Help

2

There are 2 answers

0
Arrel On BEST ANSWER

You can subclass the Devise controllers, you just have to generate the views and move them to the correct place. Check out "Configuring views" and "Configuring controllers" in the Devise readme.

I ended up adding role_ids to attr_accessible, then subclassing the RegistrationsController and adding a before_filter to remove that param for non-admins.

class Users::RegistrationsController < Devise::RegistrationsController
  before_filter :remove_admin_params, :only => [:create, :update]

protected
  # disable setting the role_ids value unless an admin is doing the edit.
  def remove_admin_params
    params[:user].delete(:role_ids) unless current_user.try(:admin?)
  end
end

Just make sure to add the registration views to /app/views/users/registrations/.

0
jpgeek On

The best way I found to handle this is from RailsCast 237. It is more verbose than Arrel's answer, but it does not force you to add role (or other fields) to attr_accessible.

Add the following method in an initializer:

class ActiveRecord::Base
  attr_accessible
  attr_accessor :accessible

  private

  def mass_assignment_authorizer(role = :default)
    if accessible == :all
      self.class.protected_attributes # hack
    else
      # super returns a whitelist object
      super + (accessible || [])
    end
  end
end

Then in your controller, you can do:

user.accessible = :role if can? :set_role, resource

This call, unfortunately, has to be made after the user (or whatever) object has been instantiated. That means that you would have to subclass the controller, and call this after the resource instantiation in update and create.

This is for Rails 3.2. In earlier versions I believe the method mass_assignment_authorizer does not take a parameter. The attr_accessible with no values sets a fail-safe application wide denial for mass assignment. This can also be done in the application.rb file with

config.active_record.whitelist_attributes = true