attr_accessor 和 attr_accessible 的区别

Posted

技术标签:

【中文标题】attr_accessor 和 attr_accessible 的区别【英文标题】:Difference between attr_accessor and attr_accessible 【发布时间】:2011-03-09 08:42:30 【问题描述】:

在 Rails 中,attr_accessorattr_accessible 有什么区别?据我了解,使用attr_accessor 用于为该变量创建getter 和setter 方法,以便我们可以访问Object.variableObject.variable = some_value 之类的变量。

我读到attr_accessible 使外部世界可以访问该特定变量。 谁能告诉我有什么区别

【问题讨论】:

你说得对,attr_accessor 用于生成 getter 和 setter 方法。请参阅我对上一个问题的回答,以获得对attr_accessible 的相当全面的解释:***.com/questions/2652907/…,然后如果您需要任何其他具体细节,请更新您的问题。 attr_accessible 在 Rails 4 中不再受支持,除非您使用 protected_attributes gem,根据***.com/questions/17371334/… 的最佳答案(2014 年 7 月) 【参考方案1】:

attr_accessor 是一个 Ruby 方法,它可以创建一个 getter 和一个 setter。 attr_accessible 是一种 Rails 方法,允许您将值传递给质量分配:new(attrs)update_attributes(attrs)

这是一个集体作业:

Order.new( :type => 'Corn', :quantity => 6 )

您可以想象订单也可能有折扣代码,例如:price_off。如果您不将:price_off 标记为attr_accessible,则可以阻止恶意代码这样做:

Order.new( :type => 'Corn', :quantity => 6, :price_off => 30 )

即使您的表单没有:price_off 的字段,如果它在您的模型中,默认情况下也是可用的。这意味着精心制作的 POST 仍然可以设置它。使用attr_accessible 将那些可以批量分配的东西列入白名单。

【讨论】:

为什么Rails 文档中没有attr_accessible? api.rubyonrails.org 看起来 Rails4 有一种新的做事方式。看到这个答案:***.com/questions/17371334/… 因为强参数已经取代了attr_accessibleedgeguides.rubyonrails.org/…的使用【参考方案2】:

这个帖子和谷歌上的很多人都很好地解释了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”属性,因为她在她的模型中看不到任何与此名称匹配的列。

【讨论】:

【参考方案3】:

attr_accessor 是一个 Ruby 方法,它为您提供同名实例变量的 setter 和 getter 方法。所以相当于

class MyModel
  def my_variable
    @my_variable
  end
  def my_variable=(value)
    @my_variable = value
  end
end

attr_accessible 是一种 Rails 方法,用于确定可以在批量赋值中设置哪些变量。

当您提交表单时,如果您有 MyModel.new params[:my_model] 之类的内容,那么您希望拥有更多控制权,这样人们就无法提交您不希望他们提交的内容。

您可以使用attr_accessible :email,这样当有人更新他们的帐户时,他们就可以更改他们的电子邮件地址。但是您不会这样做attr_accessible :email, :salary,因为这样一个人可以通过提交表单来设置他们的薪水。换句话说,他们可以通过破解方式获得加薪。

这类信息需要明确处理。仅将其从表单中删除是不够的。有人可以使用 firebug 将元素添加到表单中以提交薪水字段。他们可以使用内置的 curl 向控制器更新方法提交新的薪水,他们可以创建一个脚本来提交包含该信息的帖子。

所以attr_accessor 是关于创建存储变量的方法,attr_accessible 是关于批量赋值的安全性。

【讨论】:

你打错字了,代码块后面应该写成attr_accesible 写得很好,我喜欢课堂上的例子。包含:as 的解释的额外(假)奖励积分! 模型由 ActiveRecord::Base 扩展。 class User &lt; ActiveRecord::Base【参考方案4】:

attr_accessor 是 ruby​​ 代码,当您的数据库中没有列但仍想在表单中显示字段时使用。允许这样做的唯一方法是attr_accessor :fieldname,如果需要,您可以在您的视图或模型中使用此字段,但主要是在您的视图中。

让我们考虑下面的例子

class Address
    attr_reader :street
    attr_writer :street  
    def initialize
        @street = ""
    end
end

这里我们使用attr_reader可读属性)和attr_writer可写属性)进行访问。但是我们可以使用attr_accessor 实现相同的功能。简而言之,attr_accessor 提供对 getter 和 setter 方法的访问。

所以修改后的代码如下

class Address
    attr_accessor :street  
    def initialize
        @street = ""
    end
end

attr_accessible 允许您列出要允许批量分配的所有列。与此相反的是attr_protected,这意味着我不希望任何人被允许批量分配到这个字段。它很可能会成为您数据库中的一个字段,您不希望任何人在其中胡闹。例如状态字段等。

【讨论】:

那么你是说如果我在迁移中创建了字段,然后使用 attr_accessible 使它们可用,就不需要创建 getter 和 setter?但是如果该字段不在数据库中,为什么 attr_accessible 不像 getter/setter 那样工作?如果我包含一行“has_secure_password”,那么 attr_accessible 就足以允许 getter/setter 访问 :password 和 :password_confirmation,即使它们不在数据库中。很困惑;)【参考方案5】:

两句话:

attr_accessorgetter, setter 方法。 而attr_accessible 是说特定属性是否可访问。而已。


我想补充一点,我们应该使用Strong parameter 而不是attr_accessible 来防止大规模分配。

干杯!

【讨论】:

【参考方案6】:

快速简洁的差异概述:

attr_accessor 是一种创建读写访问器的简单方法 你的班。当您的数据库中没有列时使用它, 但仍想在表单中显示一个字段。这个领域是一个 “virtual attribute” 在 Rails 模型中。

虚拟属性 – 与数据库中的列不对应的属性。

attr_accessible 用于标识可访问的属性 通过您的控制器方法使属性可用于 mass-assignment.. 它只允许访问您指定的属性 指定,否认其余部分。

【讨论】:

以上是关于attr_accessor 和 attr_accessible 的区别的主要内容,如果未能解决你的问题,请参考以下文章

ruby 类 - attr_accessor

ruby 类 - attr_accessor

ruby 类 - attr_accessor

如何为动态实例变量设置 attr_accessor?

在 Rails 中,有没有办法指定您希望 attr_accessor 成为的类型,并使用内置的 Rails 验证对其进行验证?

这行 Ruby 代码在做啥? [复制]