【问题标题】:Rails merge (and manual assignment) assigning nilRails 合并(和手动分配)分配 nil
【发布时间】:2018-08-14 19:17:31
【问题描述】:

我正在尝试使用 Rails 5.1 中的强参数在控制器中创建一个模型(对于 strong_params,有些东西与以前的有所不同)。但是,当我检查参数时,合并的参数不存在,并且我得到一个 ForbiddenAttributesError 跟踪到下面的 Model.new 行。模型中唯一的事情是验证所有属性的存在。

class ModelController < ApplicationController
  before_action :application_controller_action

  def create
    @model = Model.new(strong_params)
    if @model.valid?
      result = @model.save
    else
      render html: 'MODEL NOT VALID'
    end
    render html: 'DONE'
  end

  private
    def strong_params
      # attr_1 and attr_2 are set in the application controller and are available here.
      params.require(:model).permit(:name, :attribute_1, :attribute_2).merge(attribute_1: @attr_1, attribute_2: @attr_2)
      # Inserting the following two lines causes a ForbiddenAttributesError
      puts params.inspect  # DOES NOT INCLUDE @attr_1 and/or @attr_2
      return params
    end

我可能做错了什么,因为我什至尝试将强参数放入具有属性的模型中(我之前可以检查),但它仍然失败,因为模型中 attr_1 和 attr_2 的验证失败。

def create
  puts @user.inspect  (not nil)
  @model = Model.new(name: strong_params[:name], attribute_1: @attr_1, attribute_2: @attr_2)

更新:

好的,我在故障排除中遇到了一些奇怪的错误。似乎合并无法正常工作,但我确信它是在某一时刻。

我检查的第一件事是@attr_1 和@attr_2,它们肯定已经设置好了。

出于故障排除的目的,我将应用程序 before_action 简化为:

def application_before_action
  @attr_1 = Model.first
  @attr_2 = Model.last

使用上面的代码,检查 params 对象,然后在 require().permit() 之后返回它,我得到了 ForbiddenAttributesError(没有说明是什么)。如果我删除这些行,我会从模型中得到一个缺少属性的错误,指出缺少 @attr_1 和 @attr_2。

更新 2

更改了问题的标题,因为我可能在故障排除过程中感到困惑。我认为问题只是合并分配了 nil ......但奇怪的是(我自己最初)建议的手动分配和这里的另一个答案。属性键在那里,但它们被分配为零。另外,请注意我的示例使用的是单个模型,而实际上有两个模型,模型 1 和模型 2。我正在将 Model1 中的值分配给 Model2。

这里是错误的更好演示:

def create
    puts '0:'
    puts @model1.inspect
    puts '1:'
    puts strong_params.inspect
    @model2 = Model2.new(strong_params) do |m|
      m.user_id = @attr_1
      m.account_number = @attr_2
    end
    puts '3:'
    puts @model2.inspect

    if @model2.valid?
      result = @model2.save
      render html: 'SUCCESS' and return
    else
      render html: @model2.errors.full_messages and return
    end
end

控制台输出:

0:
#<Model1 id: 29, attribute_1: 'test_value_1', attribute_2: 'test_value_2', created_at: "2018-08-15 03:55:08", updated_at: "2018-08-15 04:05:01">
1:
<ActionController::Parameters {"name"=>"test_name", "attribute_1"=>nil, "attribute_2"=>nil} permitted: true>
3:
#<Model2 id: nil, name: 'test_name', attribute_1: nil, attribute_2: nil, created_at: nil, updated_at: nil>

显然nil id和timestamps是因为模型还没有保存。

html model2.errors.full_messages 为:["attribute_1 can't be blank", "attribute_2 can't be blank"]

解决方案

之前来自纯 ruby​​ 环境,我误认为 ActiveRecord 模型的默认访问器。删除访问器似乎已经解决了问题。

【问题讨论】:

  • @attr_1@attr_2 来自哪里? :application_controller_action防御在哪里?
  • strong_params 只是一种常规方法。在您在代码中调用 strong_params 之前,它不会被执行。我认为问题在于application_controller_action 从未执行过(或者它没有设置@attr_1@attr_2)。你考虑过吗?
  • @user58446 我假设您在控制器中收到name,但您如何获得@attr_1@attr_2。它们也是请求的一部分吗?
  • 抱歉,正在忙于故障排除。请看更新。 attr_1 和 attr_2 不是请求的一部分,它们在 before_action (在应用程序控制器中)中设置,并且“打算”添加到 params 哈希中。奇怪的是,它甚至不允许我手动创建对象而不使用哈希。禁用强参数会阻止这种情况发生吗?
  • @user58446 如果您在允许它们之后第二次覆盖属性,则根本没有理由允许它们。我会把它们排除在外。此外,您说@attr_1@attr_2 肯定是在设置中。然而,这并不意味着他们不能是nil。如果没有条目,即使 Model.firstModel.last 也可以返回 nil。你在赋值之前检查过@attr_1@attr_2的值吗?

标签: ruby-on-rails strong-parameters ruby-on-rails-5.1 rails-models


【解决方案1】:

您可以一一分配奇数值,而不是胡乱处理 params 哈希:

class ModelController < ApplicationController
  before_action :application_controller_action

  def create
    @model = Model.new(strong_params) do |m|
      m.attribute_1 = @attr_1
      m.attribute_2 = @attr_2
    end

    if @model.valid?
      result = @model.save
    else
      render html: 'MODEL NOT VALID'
    end
    # don't do this it will just give a double render error
    render html: 'DONE'
  end

  private

   private
    def strong_params
      params.require(:model).permit(:name, :attribute_1, :attribute_2)
    end
end

一般来说,这是一种更易读的方式,例如将参数与会话中的值合并。

您的强参数方法不起作用的原因是它在所有可能的方面都被破坏了。要点是您没有返回列入白名单和合并的参数哈希。你要归还整个shebang。

您似乎还误以为.require.permit.merge 改变了原始哈希值——它们没有——它们返回一个新的哈希值(实际上是一个 ActionContoller::Parameters 实例) .

def strong_params
  # attr_1 and attr_2 are set in the application controller and are available here.
  permitted = params.require(:model).permit(:name, :attribute_1, :attribute_2)
        .merge(attribute_1: @attr_1, attribute_2: @attr_2)
  puts permitted.inspect
  permitted # return is implicit
end

或者只是:

def strong_params
  # attr_1 and attr_2 are set in the application controller and are available here.
  params.require(:model).permit(:name, :attribute_1, :attribute_2)
        .merge(attribute_1: @attr_1, attribute_2: @attr_2)
end

【讨论】:

  • 感谢您的诚实:“您的强参数方法不起作用的原因是它在所有可能的方面都被彻底破坏了。”我以为我只是按照这里的例子加上一个合并:edgeapi.rubyonrails.org/classes/ActionController/…。无论如何,您使用该块的示例不起作用。我仍然有效吗?错误:[“attribute_1 不能为空”,“attribute_2 不能为空”]。我可以在使用 @attrs 之前检查它们,并且它们肯定已经设置好了。感谢您指出我没有从 require().permit() 赋值的错误。
  • 另外,我确实为所有涉及的属性设置了 attr_accessors...为模型属性_1 和属性_2 写入,并为另一个读取。
  • 查看上次更新以更好地演示问题。这可能很简单,但我不知道从哪里开始调查。
  • @user58446:“但我不知道从哪里开始调查” - 调查@attr_1/@attr_2 的实际值。它们似乎是模型实例而不是简单的原语?在这种情况下,尝试像这样持久化它们:m.attr1_id = @attr_1.id。如果一切正常,应该做同样的事情,但如果该对象为 nil,则会崩溃。
  • 您不想将attr_accessor 用于数据库支持的属性,因为它会覆盖 ActiveRecord 创建的 setter/getter。我有点迷失从这里去哪里,因为你真的一团糟,我真的不明白你想要完成什么。
【解决方案2】:

您可以在合并之前转换为哈希

params.require(:model).permit(:name).to_h.merge(attribute_1: @attr_1, attribute_2: @attr_2)

您必须非常确定您正在分配非用户输入,否则您将否定强参数的目的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    相关资源
    最近更新 更多