attr_accessor是Ruby语言的内置方法,此方法是为变量自动生成get set方法,从而可以省去一堆重复的get set方法。
attr_accessible和attr_protected是rails框架提供的方法,使用的场景是如下的情况:
收到表单,传统的方式是这样的:
user = User.new
user.user_name = params["user[user_name]"]
user.password = params["user[password]"]
这个代码违法了DRY原则,所以rails支持用下面的方式来快速创建对象:
user = User.new params[:user]
通过CoC,此时会自动把params中的user_name和password赋值给user对象的对应属性。这样,不管user有多少个属性,只需要一行代码就搞定。
user = User.new params[:user],这种赋值方式,rails这帮guy就骑了个名字叫做 mass assignment
但是这个同时带来另外一个问题,User的某些属性不希望通过浏览器的方式(有可能是通过手动编写的程序提交表单,而不是通过浏览器的form)来修改,比如:user.is_admin,这样如果有人恶意通过程序来调用此接口,就会出现安全漏洞,把自己升级为管理员。
为了避免这样的情况,rails提供了两个方法(attr_accessible和attr_protected),用来限制哪些属性可以通过这种方式更新,哪些属性不能这样。
attr_accessible相当于是白名单,定义哪些属性可以被mass assignment(大量赋值)
attr_protected相当于是黑名单,定义哪些属性不可以被mass assignment
Mass assignemet是個Rails專屬,因為太方便而造成的安全性議題。ActiveRecord物件在新建或修改時,可以直接傳入一個Hash來設定屬性(這功能叫做Mass assignment):
def create
params[:user] #=> {:name => “ow3ned”, :is_admin => true}
@user = User.create(params[:user])
end
def update
@user = User.update_attributes(params[:user])
end
但是如果這個Model包含一些敏感屬性,例如此例中is_admin是個辨別是否是管理員的Boolean值,它不應該讓使用者可以修改。這時候我們就必須用attr_protected或attr_accessible方法來保護這些屬性:
class User < ActiveRecord::Base
attr_protected :is_admin
end
使用attr_protected
是黑名單,在Mass assignment時就會略過這個is_admin
這個屬性。或是使用attr_accessible
則是白名單,在Mass assignment時只會設定這些屬性:
class User < ActiveRecord::Base
attr_accessible :name
end
這些被保護的屬性如果要給值,你就必須手動來了,而且通常會在不同的Controller,例如只會出現在後台管理中:
params[:user] #=> {:name => "ow3ned", :is_admin => true}
@user = User.new(params[:user])
@user.is_admin #=> false # not mass-assigned
@user.is_admin = true
@user.is_admin #=> true