Module: ActiveModel::MassAssignmentSecurity::ClassMethods

Defined in:
lib/active_model/mass_assignment_security.rb

Overview

Mass assignment security provides an interface for protecting attributes from end-user assignment. For more complex permissions, mass assignment security may be handled outside the model by extending a non-ActiveRecord class, such as a controller, with this behavior.

For example, a logged in user may need to assign additional attributes depending on their role:

class AccountsController < ApplicationController
  include ActiveModel::MassAssignmentSecurity

  attr_accessible :first_name, :last_name
  attr_accessible :first_name, :last_name, :plan_id, :as => :admin

  def update
    ...
    @account.update_attributes(account_params)
    ...
  end

  protected

  def account_params
    role = admin ? :admin : :default
    sanitize_for_mass_assignment(params[:account], role)
  end

end

Configuration options

  • mass_assignment_sanitizer - Defines sanitize method. Possible values are:

    • :logger (default) - writes filtered attributes to logger

    • :strict - raise ActiveModel::MassAssignmentSecurity::Error on any protected attribute update

You can specify your own sanitizer object eg. MySanitizer.new. See ActiveModel::MassAssignmentSecurity::LoggerSanitizer for example implementation.

Instance Method Summary collapse

Instance Method Details

#accessible_attributes(role = :default) ⇒ Object



191
192
193
# File 'lib/active_model/mass_assignment_security.rb', line 191

def accessible_attributes(role = :default)
  accessible_attributes_configs[role]
end

#active_authorizersObject Also known as: active_authorizer



195
196
197
# File 'lib/active_model/mass_assignment_security.rb', line 195

def active_authorizers
  self._active_authorizer ||= protected_attributes_configs
end

#attr_accessible(*args) ⇒ Object

Specifies a white list of model attributes that can be set via mass-assignment.

Like attr_protected, a role for the attributes is optional, if no role is provided then :default is used. A role can be defined by using the :as option.

This is the opposite of the attr_protected macro: Mass-assignment will only set attributes in this list, to assign to the rest of attributes you can use direct writer methods. This is meant to protect sensitive attributes from being overwritten by malicious users tampering with URLs or forms. If you’d rather start from an all-open default and restrict attributes as needed, have a look at attr_protected.

class Customer
  include ActiveModel::MassAssignmentSecurity

  attr_accessor :name, :credit_rating

  attr_accessible :name
  attr_accessible :name, :credit_rating, :as => :admin

  def assign_attributes(values, options = {})
    sanitize_for_mass_assignment(values, options[:as]).each do |k, v|
      send("#{k}=", v)
    end
  end
end

When using the :default role:

customer = Customer.new
customer.assign_attributes({ "name" => "David", "credit_rating" => "Excellent", :last_login => 1.day.ago }, :as => :default)
customer.name          # => "David"
customer.credit_rating # => nil

customer.credit_rating = "Average"
customer.credit_rating # => "Average"

And using the :admin role:

customer = Customer.new
customer.assign_attributes({ "name" => "David", "credit_rating" => "Excellent", :last_login => 1.day.ago }, :as => :admin)
customer.name          # => "David"
customer.credit_rating # => "Excellent"

Note that using Hash#except or Hash#slice in place of attr_accessible to sanitize attributes provides basically the same functionality, but it makes a bit tricky to deal with nested attributes.



174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/active_model/mass_assignment_security.rb', line 174

def attr_accessible(*args)
  options = args.extract_options!
  role = options[:as] || :default

  self._accessible_attributes = accessible_attributes_configs.dup

  Array.wrap(role).each do |name|
    self._accessible_attributes[name] = self.accessible_attributes(name) + args
  end

  self._active_authorizer = self._accessible_attributes
end

#attr_protected(*args) ⇒ Object

Attributes named in this macro are protected from mass-assignment whenever attributes are sanitized before assignment. A role for the attributes is optional, if no role is provided then :default is used. A role can be defined by using the :as option.

Mass-assignment to these attributes will simply be ignored, to assign to them you can use direct writer methods. This is meant to protect sensitive attributes from being overwritten by malicious users tampering with URLs or forms. Example:

class Customer
  include ActiveModel::MassAssignmentSecurity

  attr_accessor :name, :credit_rating

  attr_protected :credit_rating, :last_login
  attr_protected :last_login, :as => :admin

  def assign_attributes(values, options = {})
    sanitize_for_mass_assignment(values, options[:as]).each do |k, v|
      send("#{k}=", v)
    end
  end
end

When using the :default role:

customer = Customer.new
customer.assign_attributes({ "name" => "David", "credit_rating" => "Excellent", :last_login => 1.day.ago }, :as => :default)
customer.name          # => "David"
customer.credit_rating # => nil
customer.    # => nil

customer.credit_rating = "Average"
customer.credit_rating # => "Average"

And using the :admin role:

customer = Customer.new
customer.assign_attributes({ "name" => "David", "credit_rating" => "Excellent", :last_login => 1.day.ago }, :as => :admin)
customer.name          # => "David"
customer.credit_rating # => "Excellent"
customer.    # => nil

To start from an all-closed default and enable attributes as needed, have a look at attr_accessible.

Note that using Hash#except or Hash#slice in place of attr_protected to sanitize attributes provides basically the same functionality, but it makes a bit tricky to deal with nested attributes.



111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/active_model/mass_assignment_security.rb', line 111

def attr_protected(*args)
  options = args.extract_options!
  role = options[:as] || :default

  self._protected_attributes = protected_attributes_configs.dup

  Array.wrap(role).each do |name|
    self._protected_attributes[name] = self.protected_attributes(name) + args
  end

  self._active_authorizer = self._protected_attributes
end

#attributes_protected_by_defaultObject



200
201
202
# File 'lib/active_model/mass_assignment_security.rb', line 200

def attributes_protected_by_default
  []
end

#mass_assignment_sanitizer=(value) ⇒ Object



204
205
206
207
208
209
210
# File 'lib/active_model/mass_assignment_security.rb', line 204

def mass_assignment_sanitizer=(value)
  self._mass_assignment_sanitizer = if value.is_a?(Symbol)
    const_get(:"#{value.to_s.camelize}Sanitizer").new(self)
  else
    value
  end
end

#protected_attributes(role = :default) ⇒ Object



187
188
189
# File 'lib/active_model/mass_assignment_security.rb', line 187

def protected_attributes(role = :default)
  protected_attributes_configs[role]
end