attr_accessor和attr_accessible之间的区别

fel*_*lix 235 ruby ruby-on-rails

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

我读到这attr_accessible使得该特定变量可供外界使用.有人可以告诉我这是什么区别

Pau*_*bel 256

attr_accessor是一个生成getter和setter的Ruby方法.attr_accessible是一个Rails方法,允许您将值传递给质量赋值:new(attrs)update_attributes(attrs).

这是一个质量任务:

Order.new({ :type => 'Corn', :quantity => 6 })
Run Code Online (Sandbox Code Playgroud)

你可以想象订单也可能有折扣代码:price_off.如果您没有标记,:price_off因为attr_accessible您阻止恶意代码执行此操作:

Order.new({ :type => 'Corn', :quantity => 6, :price_off => 30 })
Run Code Online (Sandbox Code Playgroud)

即使您的表单没有字段:price_off,如果它在您的模型中,它默认可用.这意味着精心设计的POST仍然可以设置它.使用attr_accessible白色列出可以批量分配的东西.

  • 看起来Rails4有一种新的做事方式.请参阅此答案:http://stackoverflow.com/questions/17371334/how-is-attr-accessible-used-in-rails-4 (19认同)
  • 为什么Rails文档中没有`attr_accessible`?http://api.rubyonrails.org/ (2认同)

Dou*_*las 173

很多人在这个帖子和google上解释得很清楚,它attr_accessible指定了允许批量更新的属性白名单(对象模型的所有属性同时在一起)这主要是(并且仅)保护你的应用程序从"大规模任务"海盗利用.

这在官方Rails文档:Mass Assignment中进行了解释

attr_accessor是一个ruby代码(快速)在类中创建setter和getter方法.就这样.

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

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

比如说:我们有一个名为"users"的数据库表,其中包含三列"firstname","lastname"和"role":

SQL说明:

CREATE TABLE users (
  firstname string,
  lastname string
  role string
);
Run Code Online (Sandbox Code Playgroud)

我假设您config.active_record.whitelist_attributes = true在config/environment/production.rb中设置了选项,以保护您的应用程序免受Mass assignment exploit.这在此解释:质量分配

您的Rails模型将完美适用于以下模型:

class User < ActiveRecord::Base

end
Run Code Online (Sandbox Code Playgroud)

但是,您需要在控制器中单独更新用户的每个属性,以使表单的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
Run Code Online (Sandbox Code Playgroud)

现在为了简化您的生活,您不希望为您的用户模型制作复杂的控制器.因此,您将attr_accessible在Class模型中使用特殊方法:

class User < ActiveRecord::Base

  attr_accessible :firstname, :lastname

end
Run Code Online (Sandbox Code Playgroud)

所以你可以使用"高速公路"(质量分配)来更新:

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
Run Code Online (Sandbox Code Playgroud)

您没有将"角色"属性添加到attr_accessible列表中,因为您不允许用户自己设置角色(例如admin).您可以在另一个特殊的管理视图上自己完成.

虽然您的用户视图未显示"角色"字段,但盗版者可以轻松地在params哈希中发送包含"角色"的HTTP POST请求.缺少的"角色"属性attr_accessible是为了保护您的应用程序.

您仍然可以自己修改user.role属性,如下所示,但不能同时修改所有属性.

@user.role = DEFAULT_ROLE
Run Code Online (Sandbox Code Playgroud)

你为什么要用这个attr_accessor

好吧,如果您的用户表单显示一个不在您的users表中作为列的字段.

例如,假设您的用户视图显示"请告诉管理员 - 我在这里"字段.您不希望将此信息存储在表中.你只是希望Rails发送一封电子邮件警告你一个"疯狂";-)用户订阅了.

为了能够使用此信息,您需要将其临时存储在某处.比在user.peekaboo属性中恢复更容易吗?

因此,您将此字段添加到模型中:

class User < ActiveRecord::Base

  attr_accessible :firstname, :lastname
  attr_accessor :peekaboo

end
Run Code Online (Sandbox Code Playgroud)

因此,您将能够user.peekaboo在控制器中的某个位置对该属性进行有根据的使用,以发送电子邮件或执行您想要的任何操作.

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


Jos*_*eek 48

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

class MyModel
  def my_variable
    @my_variable
  end
  def my_variable=(value)
    @my_variable = value
  end
end
Run Code Online (Sandbox Code Playgroud)

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

当你提交一个表格,并且你有类似的东西时,MyModel.new params[:my_model]你想要有更多的控制权,这样人们就无法提交你不想要的东西.

您可以这样attr_accessible :email做,当有人更新他们的帐户时,他们可以更改他们的电子邮件地址.但你不会这样做,attr_accessible :email, :salary因为一个人可以通过表格提交来设定他们的工资.换句话说,他们可以破解他们的加薪方式.

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

因此attr_accessor,关于创建存储变量的方法,以及attr_accessible关于批量分配的安全性.

  • 你有一个拼写错误,在代码块后它应该说'attr_accesible` (2认同)

sk1*_*712 18

attr_accessor是ruby代码,当您在数据库中没有列但仍希望在表单中显示字段时使用.允许此操作的唯一方法是attr_accessor :fieldname,您可以在视图或模型中使用此字段(如果需要),但主要在视图中.

让我们考虑以下示例

class Address
    attr_reader :street
    attr_writer :street  
    def initialize
        @street = ""
    end
end
Run Code Online (Sandbox Code Playgroud)

这里我们使用attr_reader(可读属性)和attr_writer(可写属性)来访问目的.但我们可以使用相同的功能attr_accessor.简而言之,attr_accessor提供对getter和setter方法的访问.

所以修改后的代码如下

class Address
    attr_accessor :street  
    def initialize
        @street = ""
    end
end
Run Code Online (Sandbox Code Playgroud)

attr_accessible允许您列出要允许批量分配的所有列.与此相反的是attr_protected,这个字段意味着我不希望任何人被允许进行质量分配.很可能它会成为你数据库中的一个字段,你不希望任何人在一起工作.像状态字段等.

  • 所以你是说如果我在迁移中创建了字段,然后使用attr_accessible使它们可用,那么就没有必要创建一个getter和setter?但是如果该字段不在数据库中,那么attr_accessible如何不像getter/setter?如果我包含一行"has_secure_password",则attr_accessible足以允许getter/setter:password和:password_confirmation,即使它们不在数据库中.非常困惑 ;) (2认同)