【问题标题】:Rails 4 strong parameters failing when creating instances in rails console在 Rails 控制台中创建实例时,Rails 4 强参数失败
【发布时间】:2013-04-04 07:37:05
【问题描述】:

可能在这里做了一些愚蠢的事情,但这是我的基本千篇一律的类:

class League < ActiveRecord::Base

    private
      def league_params
        params.require(:full_name).permit!
      end

end

当创建一个新的 League 实例时:

2.0.0-p0 :001 > l = League.new(full_name: 'foo', short_name: 'bar')
WARNING: Can't mass-assign protected attributes for League: full_name, short_name

我到底做错了什么?这是 Rails 4.0.0.beta1 构建 + Ruby 2.0

** 更新 **

我现在意识到强参数现在在控制器中而不是在模型中强制执行。原来的问题仍然存在。如果在控制器级别允许它们,如果我在 Rails 控制台中创建实例,如何正确地将属性列入白名单?在这种情况下我是否还需要使用attr_accessible 从而完全复制试图“修复”的强参数?

【问题讨论】:

  • 您可以发布您的 Gemfile 吗?还有你模型中的代码?
  • @randombits 你从 rails3 升级你的项目了吗?

标签: ruby-on-rails ruby ruby-on-rails-4 strong-parameters


【解决方案1】:

两件事。 league_params 定义在控制器中,而不是模型中。 params.require() 应该包含需要出现在参数中的模型的名称,而不是属性。属性存在检查仍应在模型验证中。在使用 permit! 之前,请确保您确实希望允许访问 League 模型中的所有属性。所以,它应该是这样的:

class LeaguesController < ApplicationController

  private
    def league_params
      params.require(:league).permit!
    end

end

更新:

是的,如果您希望在直接访问模型时限制属性,您需要切换回在模型中使用attr_accessible。该功能已移至此 gem:https://github.com/rails/protected_attributes

我认为如果您直接在控制台中使用模型,则不需要保护属性,因为您确切知道正在输入的内容。由于控制台对您的应用程序具有完全访问权限,因此对整个数据库进行管理就像恶意分配属性一样容易。

【讨论】:

  • 如果 League 没有在控制器中创建怎么办?在这种特殊情况下,我在控制台中创建它。
  • 那么你就不需要使用允许的参数了。允许的参数用于防止用户输入数据。
  • 那么我还是需要求助于 attr_accessible?
【解决方案2】:

strong参数attr_accessible都存在的基本安全原因是模型中的某些属性不应被允许更改,除非它是您的代码的明确意图。

他们之间的细微差别是他们工作的透视形式。

StrongParameters 专注于用例:每个控制器的操作都可以根据任何条件进行微调以允许或禁止某些参数。完全的灵活性。

attr_accessible 采用不同的视角。它不是专注于用例,而是专注于角色。例如,根据用户的角色,某些属性可以更改或不更改。


StrongParameters的使用方法是在参数哈希上应用requirepermit关键字。

require 声明在 params 散列中必须存在一个键。如果没有这样的键,require 将引发异常。

permit 声明一个字段是允许的。任何不允许的键都将从哈希中删除,因此不会通过批量分配的方式传递给模型。

型号

class League
   attr_protected :final_price  # Nobody can mass-assign the final price
   attr_accessible :winner_name, :as => :jury
end

还有控制器

class LeaguesController < ApplicationController

这两个动作使用StrongParameters

  # A common user can create a league
  def create
    league = League.new(league_params)
    league.final_price = 1000
    league.save
    redirect_to(league)
  end

  # But only the admin can publish a league
  def publish_league
     league = League.find(params[:id]
     league.update_attributes(league_params_as_admin)
  end

这个使用 attr_accessible

  def publish_the_winner
    league = League.find(params[:id]
    # We would expect the current_user.role to return :jury.
    league.assign_attributes(params[:league], :as => current_user.role)
  end

  private
    def league_params
      params.require(:league).permit(:name)
    end

    def league_params_as_admin
      params.require(:league).permit(:name, :status)
    end 

end

根据我的经验:

使用强参数的灵活性来微调可以在每个控制器中批量分配的属性。

使用 attr_accesible 的无所不在确保某些属性无论如何都不能被大量分配。例如,在 Resque 任务中,您可以将用户输入作为参数传递。您可以使用 attr_accesible 检查是否有一些属性没有批量分配。

更多信息:

http://api.rubyonrails.org/classes/ActiveModel/MassAssignmentSecurity/ClassMethods.html

https://github.com/rails/strong_parameters

【讨论】:

    【解决方案3】:

    如果您直接调用模型,那么是的,它会回避您在控制器中实现的任何逻辑。

    但是,您可以从控制台调用您的控制器,然后在那里实现的 StrongParameters 将生效。

    How do I call controller/view methods from the console in Rails?

    【讨论】:

      【解决方案4】:

      即使您运行的是 Rails 4,白名单似乎仍处于活动状态。您是否从 Rails 3 应用升级到 Rails 4?你的config/application.rb 里有这个吗?

      config.active_record.whitelist_attributes = true
      

      仔细检查所有模型上的强参数是否有效。如果是,您可以将此设置更改为false

      另外,请仔细检查您的模型中是否没有 attr_accessible

      【讨论】:

      • 我不是该主题的作者,但谢谢。当我将项目从 Rails3 升级到 Rails4 时,显示了此消息。但是,如果我使用相同的代码(即使在配置中)创建 Rails 4 项目,则不会显示消息。不知道为什么,好像是个小bug。
      • 无法透明升级,需要开发人员协助。相信原贴一定加了protected_attributes gem,否则会报错。 (也许错误告诉你安装那个gem,我面前没有合适的电脑来检查)。升级到 Rails 4 的最佳方法是首先使用 strong_parameters gem 并检查所有控制器和模型以新的方式工作,只有在升级 Rails gem 之后。
      • Rails 4 项目中的配置真的一样吗?我猜提到的配置行丢失或设置为 false。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-22
      • 1970-01-01
      • 1970-01-01
      • 2013-12-07
      • 1970-01-01
      • 2013-11-21
      相关资源
      最近更新 更多