这个帖子和谷歌上的很多人都很好地解释了attr_accessible指定了一个允许批量更新的属性白名单(一个对象模型的所有属性同时在一起)
这主要(且仅)是为了保护您的应用程序免受“批量分配”盗版攻击。
官方 Rails 文档对此进行了解释:Mass Assignment
attr_accessor 是一个 ruby 代码,用于(快速)在类中创建 setter 和 getter 方法。就是这样。
现在,缺少的解释是,当您以某种方式在 (Rails) 模型与数据库表之间创建链接时,您永远、永远、永远不需要在模型中使用 attr_accessor 来按顺序创建 setter 和 getter以便能够修改表的记录。
这是因为您的模型继承了 ActiveRecord::Base 类的所有方法,该类已经为您定义了基本的 CRUD 访问器(创建、读取、更新、删除)。
这在Rails Model 和Overwriting default accessor 的官方文档中进行了解释(向下滚动到“覆盖默认访问器”一章)
例如:我们有一个名为“users”的数据库表,其中包含“firstname”、“lastname”和“role”三列:
SQL 指令:
CREATE TABLE users (
firstname string,
lastname string
role string
);
我假设您在 config/environment/production.rb 中设置了选项 config.active_record.whitelist_attributes = true 以保护您的应用程序免受 Mass assignment 攻击。这在这里解释:Mass Assignment
您的 Rails 模型将与下面的模型完美配合:
class User < ActiveRecord::Base
end
但是,您需要在控制器中分别更新用户的每个属性才能使表单的视图正常工作:
def update
@user = User.find_by_id(params[:id])
@user.firstname = params[:user][:firstname]
@user.lastname = params[:user][:lastname]
if @user.save
# Use of I18 internationalization t method for the flash message
flash[:success] = t('activerecord.successful.messages.updated', :model => User.model_name.human)
end
respond_with(@user)
end
现在,为了让您的生活更轻松,您不想为您的 User 模型制作复杂的控制器。
因此,您将在 Class 模型中使用 attr_accessible 特殊方法:
class User < ActiveRecord::Base
attr_accessible :firstname, :lastname
end
所以你可以使用“高速公路”(质量分配)来更新:
def update
@user = User.find_by_id(params[:id])
if @user.update_attributes(params[:user])
# Use of I18 internationlization t method for the flash message
flash[:success] = t('activerecord.successful.messages.updated', :model => User.model_name.human)
end
respond_with(@user)
end
您没有将“角色”属性添加到attr_accessible 列表中,因为您不允许您的用户自行设置其角色(如管理员)。您自己在另一个特殊的管理视图上执行此操作。
尽管您的用户视图没有显示“角色”字段,但盗版者可以轻松发送在参数哈希中包含“角色”的 HTTP POST 请求。 attr_accessible 上缺少的“角色”属性是为了保护您的应用程序不受此影响。
您仍然可以像下面这样单独修改您的 user.role 属性,但不能同时修改所有属性。
@user.role = DEFAULT_ROLE
你到底为什么要使用attr_accessor?
好吧,这是在您的用户表单将用户表中不存在的字段显示为列的情况下。
例如,假设您的用户视图显示“请告诉管理员我在这里”字段。
您不想将此信息存储在您的表中。您只希望 Rails 向您发送一封电子邮件,警告您有一个“疯狂”的 ;-) 用户订阅了。
为了能够使用此信息,您需要将其临时存储在某个地方。
有什么比在 user.peekaboo 属性中恢复它更容易的呢?
所以你将这个字段添加到你的模型中:
class User < ActiveRecord::Base
attr_accessible :firstname, :lastname
attr_accessor :peekaboo
end
因此,您将能够在控制器中的某处合理使用user.peekaboo 属性来发送电子邮件或做任何您想做的事情。
当您执行user.save 时,ActiveRecord 不会在您的表中保存“peekaboo”属性,因为她在她的模型中看不到任何与此名称匹配的列。