rails attr_accessible attr_protected

Posted by wxianfeng Mon, 13 Dec 2010 14:07:00 GMT

环境:ruby 1.9.2 + rails 3.0.3 + ubuntu 10.10

我们经常在 用户注册 验证 的时候 会用到 attr_accessible , 那么有什么作用呢?

问题重现:

用户注册的时候 需要 填写 login , name , password , confirm_password

User:

attr_accessible :login, :email, :password, :password_confirmation

后台传参:

Parameters: {"utf8"=>"", "authenticity_token"=>"r+rfq6Wcu/64ZvkMOi6kPE1k6NHELDi99GmaehGFA4g=", "user"=>{"login"=>"wwwwww", "email"=>"ww@ww.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Sign up"}

顺利通过

User:

attr_accessible  :email, :password, :password_confirmation
 Parameters: {"utf8"=>"", "authenticity_token"=>"r+rfq6Wcu/64ZvkMOi6kPE1k6NHELDi99GmaehGFA4g=", "user"=>{"login"=>"qqqqqq", "email"=>"qq@qq.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Sign up"}

报错:

    * Login can't be blank
    * Login is too short (minimum is 3 characters)
    * Login use only letters, numbers, and .-_@ please.

为什么?

attr_accessible 是为了安全性考虑的,表单提交是 通过 attributes= 的块赋值 , 放在 attr_accessible 中的属性 才可以 通过块赋值,块就是指 “user”=>{"login"=>"qqqqqq", “email”=>"qq@qq.com", “password”=>"[FILTERED]", “password_confirmation”=>"[FILTERED]"} 后台 直接

user = User.new(params[:user]) 
user.save!

如果不加 attr_accessible 的话,用户可以 构造 参数 ,模拟表单提交 ,例如你的表里 status = 1 表示已经激活,admin = 1 表示 管理员 , 那么用户提交 :

"user"=>{"login"=>"wwwwww", "email"=>"ww@ww.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]",admin=>'1',status=>"1"}

自动就激活 和 变成管理员,

所以 重要字段 , 这是必须要考虑的..

那么 attr_protected 又是干什么的,它和 attr_accessible 相反 , attr_protected 是黑名单,attr_protected 保护的属性,都不可以通过块赋值,attr_accessible 是白名单,保护的属性可以 通过块赋值

rails 中自带 demo:

attr_accessible:

require 'active_model'

class Customer
  include ActiveModel::MassAssignmentSecurity

  attr_accessor :name, :credit_rating
  attr_accessible :name

  def attributes=(values)
    sanitize_for_mass_assignment(values).each do |k, v|
       send("#{k}=", v)
    end
  end
end

customer = Customer.new
customer.attributes = { :name => "David", :credit_rating => "Excellent" }
p customer.name          # => "David"
p customer.credit_rating # => nil

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

attr_protected:

require 'active_model'
class Customer
  include ActiveModel::MassAssignmentSecurity

  attr_accessor :name, :credit_rating
  attr_protected :credit_rating

  def attributes=(values)
    sanitize_for_mass_assignment(values).each do |k, v|
      send("#{k}=", v)
    end
  end
end

customer = Customer.new
customer.attributes = { "name" => "David", "credit_rating" => "Excellent" }
customer.name          # => "David"
customer.credit_rating # => nil

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

模拟 attributes = 赋值,可以看出 attr_accessible 和 attr_protected 正好 相反

see:

http://www.javaeye.com/topic/161256