Rails 5中具有多态关联的嵌套属性

Sir*_*lot 4 ruby-on-rails

我创建了一个Address具有多态关联模型,我想救它,虽然客户端模型嵌套的属性,但我得到Address addressable must exist@client.errors.

楷模:

class Client < ApplicationRecord
  has_one :address, as: :addressable, dependent: :destroy
  accepts_nested_attributes_for :address, :allow_destroy => true
end

class Address < ApplicationRecord
  belongs_to :addressable, polymorphic: true
end
Run Code Online (Sandbox Code Playgroud)

控制器:

class ClientsController < ApplicationController

  def new
    @client = Client.new
    @client.create_address
  end

  def create
    @client = Client.new(client_params)

    if @client.save
      ...
    else
      ...
    end
  end

  private
  def client_params
    params.require(:client).permit(:first_name ,:last_name, :company, address_attributes: [:line1, :line2, :line3, :city, :state_province, :postal_code, :country])
  end    
end
Run Code Online (Sandbox Code Playgroud)

mtr*_*lle 6

您应该inverse_of在您的belongs_to关系上添加密钥,例如在您的Address班级上:

class Address < ApplicationRecord
  belongs_to :addressable, polymorphic: true, inverse_of: :addressable
end
Run Code Online (Sandbox Code Playgroud)

这将正确保存嵌套地址,因为 Rails 现在将正确知道要在addressable.

optional除非确实是可选的,否则不要使用该密钥addressable


小智 5

 belongs_to :xx, polymorphic: true, optional: true
Run Code Online (Sandbox Code Playgroud)

  • 虽然这段代码可能有助于解决问题,但它没有解释_why_和/或_how_它回答了这个问题.提供这种额外的背景将大大提高其长期教育价值.请[编辑]您的答案以添加解释,包括适用的限制和假设. (6认同)

Але*_*щук 2

optional: true 
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,您可以通过分两步中断控制器中的创建来保持强制关系。

def client_params
  params.require(:client).permit(:first_name ,:last_name, :company)
end

def address_params 
 params.require(:client).require( :address_attributes).permit(:line1, :line2, :line3, :city, :state_province, :postal_code, :country )
end

def create
  @client = Client.new(client_params)

  if @client.save
   @client.create_address( address_params )
  ...
Run Code Online (Sandbox Code Playgroud)

这可能看起来更难看,但它可以让关系更安全。

  • 当分成两个操作时,@client 保存成功而地址创建失败时会发生什么?我们肯定希望两者同时失败并向表单返回错误,而不是只保存一个错误? (2认同)