attr_accessor和attr_accessible之间的区别


235

在Rails中,attr_accessor和之间有什么区别attr_accessible?据我了解,using attr_accessor用于为该变量创建getter和setter方法,以便我们可以像Object.variable或那样访问变量Object.variable = some_value

我读到这attr_accessible使外界可以访问该特定变量。有人可以告诉我有什么区别吗


4
您是正确的,attr_accessor它用于生成getter和setter方法。请参阅我对上一个问题的回答,以获取有关以下内容的相当全面的解释attr_accessiblestackoverflow.com/questions/2652907/…如果此后需要其他任何详细信息,请更新您的问题。
mikej 2010年

2
除非您使用protected_attributes gem,否则Rails 4不再支持attr_accessible,这是根据stackoverflow.com/questions/17371334/…的最佳答案(2014
emery

Answers:


258

attr_accessor是一个进行getter和setter的Ruby方法。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白色列出可以批量分配的那些东西。


2
为什么不在attr_accessibleRails文档中?api.rubyonrails.org
Chloe

19
看起来Rails4有一种新的处理方式。看到这个答案:stackoverflow.com/questions/17371334/...
保罗·鲁贝尔

1
由于强大的参数有替代使用的attr_accessible edgeguides.rubyonrails.org/...
伊姆兰·艾哈迈德

173

这个线程和google上的许多人都很好地解释attr_accessible了一个白名单,该白名单指定了允许批量更新的属性白名单(对象模型的所有属性同时在一起),这主要是(也是唯一的)保护您的应用程序来自“大规模任务”海盗攻击。

这在Rails官方文档中进行了解释:批量分配

attr_accessor是一个Ruby代码,用于(快速)在类中创建setter和getter方法。就这样。

现在,缺少的解释是,当您以某种方式在(Rails)模型与数据库表之间创建链接时,您永远,永远,永远不需要attr_accessor在模型中创建setter和getter以便能够修改您的表的记录。

这是因为您的模型从ActiveRecord::Base类继承了所有方法,该类已经为您定义了基本的CRUD访问器(创建,读取,更新,删除)。这在官方文档的Rails模型和此处的覆盖默认访问器中进行了解释(向下滚动到“覆盖默认访问器”一章)

举例来说:我们有一个名为“ users”的数据库表,其中包含三列“ firstname”,“ lastname”和“ role”:

SQL指令:

CREATE TABLE users (
  firstname string,
  lastname string
  role string
);

我假设您config.active_record.whitelist_attributes = true在config / environment / production.rb中设置了该选项,以保护您的应用程序免受大量分配攻击。此处说明:批量分配

您的Rails模型将与以下模型完美配合:

class User < ActiveRecord::Base

end

但是,您将需要在控制器中分别更新用户的每个属性,以使表单的View起作用:

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

现在,为了减轻您的生活负担,您不想为用户模型制作复杂的控制器。因此,您将attr_accessible在Class模型中使用特殊方法:

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列表中,因为您不允许用户自己设置角色(例如admin)。您可以自己在另一个特殊的管理员视图上执行此操作。

尽管您的用户视图未显示“角色”字段,但盗版者可以轻松地发送HTTP POST请求,该请求在params哈希中包含“角色”。缺少的“角色”属性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在控制器的某个位置对属性进行有针对性的使用,以发送电子邮件或执行任何您想做的事情。

执行a时,ActiveRecord不会在您的表中保存“ peekaboo”属性,user.save因为她在模型中看不到任何与此名称匹配的列。


48

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要保证大量分配的安全性。


2
您有错字,在代码段后应该说attr_accesible
Chubas 2010年

写得很好,我喜欢上课的例子。额外的(假)奖励积分,包括对的解释:as
伊恩·沃恩

通过ActiveRecord :: Base扩展模型。class User < ActiveRecord::Base
2013年

18

attr_accessor是红宝石代码,在数据库中没有列但仍要在表单中显示字段时使用。允许这样做的唯一方法是,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,这意味着我不希望任何人被允许批量分配给该字段。它很可能成为数据库中的一个字段,您不希望任何人闲逛。像状态栏之类的。


2
因此,您是说如果我在迁移中创建了字段,然后使用attr_accessible使它们可用,那么就不需要创建getter和setter了吗?但是,如果该字段不在数据库中,那么attr_accessible怎么不会像getter / setter一样起作用?如果我添加一行“ has_secure_password”,则attr_accessible足以允许getter / setter进行:password和:password_confirmation,即使它们不在数据库中也是如此。非常困惑;)
十倍2012年


2

快速简洁的区别概述:

attr_accessor是在类中创建读写访问器的简便方法。如果您的数据库中没有列,但仍想在表单中显示字段,则使用它。该字段 “virtual attribute”在Rails模型中。

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

attr_accessible 用于标识可通过控制器方法访问的属性,从而使属性可用于批量分配。它仅允许访问您指定的属性,其余部分则拒绝。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.