环境: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: