在 Rails 4 中如何使用 attr_accessible?

Posted

技术标签:

【中文标题】在 Rails 4 中如何使用 attr_accessible?【英文标题】:How is attr_accessible used in Rails 4? 【发布时间】:2013-06-26 14:50:11 【问题描述】:

attr_accessible 似乎不再适用于我的模型。

在 Rails 4 中允许批量分配的方法是什么?

【问题讨论】:

【参考方案1】:

Rails 4 现在使用 strong parameters。

现在在控制器中保护属性。这是一个例子:

class PeopleController < ApplicationController
  def create
    Person.create(person_params)
  end

  private

  def person_params
    params.require(:person).permit(:name, :age)
  end
end

不再需要在模型中设置attr_accessible

处理accepts_nested_attributes_for

为了使用带有强参数的accepts_nested_attribute_for,您需要指定哪些嵌套属性应列入白名单。

class Person
  has_many :pets
  accepts_nested_attributes_for :pets
end

class PeopleController < ApplicationController
  def create
    Person.create(person_params)
  end

  # ...

  private

  def person_params
    params.require(:person).permit(:name, :age, pets_attributes: [:name, :category])
  end
end

关键字是不言自明的,但以防万一,您可以找到有关强参数in the Rails Action Controller guide的更多信息。

注意:如果您仍想使用attr_accessible,您需要将protected_attributes 添加到您的Gemfile。否则,您将面临RuntimeError

【讨论】:

文档没有说attr_accessible需要被删除。如果我们保留它会发生什么? 如果您不对 Gemfile 进行一些调整,将会出现错误。 RuntimeError in MicropostsController#index 'attr_accessible' is extracted out of Rails into a gem. Please use new recommended protection model for params(strong_parameters) or add 'protected_attributes' to your Gemfile to use old one. 很好的解释。然而,在实践中,这似乎使 Rails 从胖模型、瘦控制器等转向瘦模型,以及真正臃肿的控制器。你必须为每个实例编写所有这些东西,它读起来不太好,而且嵌套似乎很痛苦。模型系统中旧的 attr_accessible/attr_accessor 没有损坏,不需要修复。在这种情况下,一篇博文变得太受欢迎了。 您不必在控制器中处理允许的参数。事实上,这违反了单一责任原则。看看下面的博文edelpero.svbtle.com/strong-parameters-the-right-way 如此花哨且频繁更改的 API,再加上新发现的迂腐,在又一次痛苦的 Rails 升级中浪费了许多开发人员时间:-(【参考方案2】:

如果你更喜欢 attr_accessible,你也可以在 Rails 4 中使用它。 你应该像 gem 一样安装它:

gem 'protected_attributes'

之后,您可以像在 Rails 3 中一样在模型中使用 attr_accessible

另外,我认为这是最好的方法——使用表单对象来处理批量赋值,保存嵌套对象,你也可以这样使用 protected_attributes gem

class NestedForm
   include  ActiveModel::MassAssignmentSecurity
   attr_accessible :name,
                   :telephone, as: :create_params
   def create_objects(params)
      SomeModel.new(sanitized_params(params, :create_params))
   end
end

【讨论】:

当您使用“强参数”时,您会在控制器层过滤参数,我认为这并不是所有应用程序的最佳选择。对我来说,过滤参数的最佳方法是使用附加层。我们可以使用'protected_attributes' gem 来编写这一层【参考方案3】:

Rails 5 的更新:

gem 'protected_attributes' 

似乎不再起作用了。但是给:

gem 'protected_attributes_continued'

试一试。

【讨论】:

【参考方案4】:

我们可以使用

params.require(:person).permit(:name, :age)

如果 person 是模型,您可以在方法 person_params 上传递此代码,并在 create 方法或 else 方法中使用 params[:person]

【讨论】:

【参考方案5】:

1) 通过将这一行添加到应用程序的 Gemfile 中,更新 Devise 以便它可以处理 Rails 4.0:

gem 'devise', '3.0.0.rc' 

然后执行:

$ bundle

2) 将 attr_accessible 的旧功能再次添加到 rails 4.0

尽量使用attr_accessible,不要注释掉。

将此行添加到应用程序的 Gemfile:

gem 'protected_attributes'

然后执行:

$ bundle

【讨论】:

【参考方案6】:

我不得不将 Rails 应用程序从 3.2 迁移到 6.1,所以即使 gem 'protected_attributes' 也不是一个选项。我很欣赏在控制器中使用 require().permit() 的参数,但我不想从模型中重新键入或剪切和粘贴所有这些属性,所以我决定改用这个初始化代码(放在一个文件中)在配置/初始化程序中):

# fix attr_accessible in an initializer
# wrap ActionController::Parameters code in singleton method defined
# from attr_accessible so controller code can call class method
# to get permitted parameter list
# e.g. model: class A < ActiveRecord::Base,
# controller calls A.permit_attr(params)
# lots simpler than moving all attr_accessible definitions to controllers
# bug: fails if more than one attr_accessible statement

def (ActiveRecord::Base).attr_accessible *fields
  puts "attr_accessible:"+self.name+":permitted_params fields=#fields.inspect"
  define_singleton_method("permit_attr")  |params|
    # may have subclasses where attr_accessible is in superclass
    # thus must require by subclass name so should calculate require at runtime
    rq = self.name.downcase.to_sym
    puts "...permit_attr:self=#rq permit(#fields.inspect)"
    params.require(rq).permit(fields)
  

end

为了防止出现多个 attr_accessible 声明,在定义方法之前,添加

raise "error: model can only have one attr_accessible declaration" if defined? permit_attr

【讨论】:

以上是关于在 Rails 4 中如何使用 attr_accessible?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Rails 4 中使用关注点

Rails 4:如何在 Rails 中使用 JQuery 禁用基于复选框值的文本字段

Rails 4 - 如何在 /config/environments/production.rb 文件中使用常量?

如何在Rails 4中清理原始SQL

如何在 rails 4.2.1 中使用 jquery-addresspicker

如何在带有 Rails 4.2 的专用调试端口上使用工头启动 Rails?