【问题标题】:nil value reaching ActiveRecord validation despite correct value passed to constructor尽管将正确的值传递给构造函数,但 nil 值达到 ActiveRecord 验证
【发布时间】:2014-05-05 15:57:14
【问题描述】:

尽管我认为正确的参数值在控制器中被列入白名单并传递给模型的构造函数,但模型对象的验证失败。我做错了什么?

OuterModel has_one Location 通过locatable。后者是使用accepts_nested_attributes_for 创建的,并且只验证:country 属性:

(编辑:我发现了错误,它被代码隐藏了,我最初在这里为了简化而省略了代码。请参阅下面的答案)

class OuterModel < Parent
  has_one :location, as: locatable
  accepts_nested_attributes_for :location
end

class Parent < ActiveRecord::Base
  after_create :create_location
end

class Location < ActiveRecord::Base
  belongs_to :locatable, polymorphic: true
  validates :country, inclusion: {in: ["US", "CA"]}
end

控制器:

class OuterModelsController < ApplicationController
  def create
    @outer = OuterModel.new(outer_params)
    if @outer.save 
      byebug #debug here
      redirect_to outer_path(@outer)
    end
  end

  def outer_params
    params.require(:outer).permit(:name, :type, 
      location_attributes: [:country, :state, :city])
  end
end

使用 byebug 我看到 @outer.save 调用已满足,但由于验证错误,嵌套的位置对象未持久化:

(byebug) @outer.persisted? #true
(byebug) @outer.location.persisted? #false
(byebug) @outer.location.valid? #false
(byebug) @outer.location.country #nil
(byebug) @outer.id #6372
(byebug) @outer.location.errors
<ActiveModel::Errors:0x007f1f33c1eae0 
  @base=#<Location id: nil, city: nil, country: nil, state: nil, locatable_id: 6732, locatable_type: "OuterModel", created_at: nil, updated_at: nil>, 
  @messages={:country=>["is not included in the list"]}>

但是,控制器的 outer_params 方法似乎将正确的哈希发送到 OuterModel.new

{"name"=>"A name",
 "type"=>"OuterModel", 
 "location_attributes"=>{
    "city"=>"South Deionview", "country"=>"US", "state"=>"IL"
 }
}

那么为什么在调用保存之后Location.countrynil,为什么验证失败?

编辑:日志文件(非常简化)pastebin here。似乎正确的值正在作为 SQL 的一部分发送

【问题讨论】:

  • 你能把提交表单时生成的日志贴出来吗?
  • @Babar pastebin 添加
  • @outer.location.errors 返回什么?
  • 是的,请检查返回的错误消息
  • 当我写下这个问题时,因为我认为问题在于控制器代码中的参数散列正确,因此从我粘贴的代码中简化了父类。没有人立即发现问题这一事实让我有信心考虑其他选择……谢谢!

标签: ruby validation activerecord ruby-on-rails-4


【解决方案1】:

答案在于 OuterModel 的父级,它有一个 after_create 挂钩来创建位置。在上面的源代码中添加了父类。

Location 对象最初是由accepts_nested_attributes_for 正确创建的(根据所有来自日志记录的证据),但随后 after_create 挂钩将其替换为未通过验证的空 Location 对象。

【讨论】:

    猜你喜欢
    • 2018-05-09
    • 2020-02-14
    • 1970-01-01
    • 1970-01-01
    • 2022-08-14
    • 2015-03-29
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多