嵌套关联不保存
Nested association not saving
我有一个客户的嵌套关联。设置是这样的:
- 一个客户有一个地址
- 一个地址有 physical_address
- 地址有 postal_addrsss
地址模型
belongs_to :customer, optional: true # Yes, optional
has_one :physical_address, dependent: :destroy
has_one :postal_address, dependent: :destroy
accepts_nested_attributes_for :physical_address
accepts_nested_attributes_for :postal_address
邮政地址模型
# same for physical_address.rb
belongs_to :address
客户控制员:
def create
@customer = current_user.customers.build(customer_params)
if @customer.save
return puts "customer saves"
end
puts @customer.errors.messages
#redirect_to new_customer_path
render :new
end
private
def customer_params
params.require(:customer).permit(
address_attributes: address_params
)
end
def address_params
return ([
postal_address_attributes: shared_address_params,
#physical_address_attributes: shared_address_params
])
end
def shared_address_params
params.fetch(:customer).fetch("address").fetch("postal_address").permit(
:street, etc...
)
end
客户型号:
has_one :address, dependent: :destroy
accepts_nested_attributes_for :address
客户已成功创建,但地址未创建。这是表格,例如:
<form>
<input name="customer[address][postal_address][street]" value="Foo Street" />
</form>
记录“params”,我看到了所有值,但没有创建地址。我认为错误在于 shared_address_params
。有什么想法吗?
我认为您只是在该参数白名单的间接层和复杂性中迷失了自己。
你基本上想要的是:
def customer_params
params.require(:customer)
.permit(
address_attributes: {
physical_address_attributes: [:street, :foo, :bar, :baz],
postal_address: [:street, :foo, :bar, :baz]
}
)
end
正如您在此处看到的,您需要参数键 customer[address_attributes]
而不仅仅是 customer[address]
。
现在让我们重构以减少重复:
def customer_params
params.require(:customer)
.permit(
address_attributes: {
physical_address_attributes: address_attributes,
postal_address: address_attributes
}
)
end
def address_attributes
[:street, :foo, :bar, :baz]
end
如您所见,这里应该不会增加任何复杂性,如果您需要使其更灵活,请向 address_attributes
方法添加参数 - 毕竟构建白名单只是简单的数组和哈希操作.
如果你想处理将某种共享属性映射到两种地址类型,你真的应该在模型中进行,而不是用业务逻辑使控制器膨胀。例如,通过为“虚拟属性”创建 setter 和 getter:
class Address < ApplicationController
def shared_address_attributes
post_address_attributes.slice("street", "foo", "bar", "baz")
end
def shared_address_attributes=(**attrs)
# @todo map the attributes to the postal and
# visiting address
end
end
这样您就可以像设置任何其他属性一样设置表单并将其列入白名单,而控制器不需要关心细节。
def customer_params
params.require(:customer)
.permit(
address_attributes: {
shared_address_attributes: address_attributes,
physical_address_attributes: address_attributes,
postal_address: address_attributes
}
)
end
我有一个客户的嵌套关联。设置是这样的:
- 一个客户有一个地址
- 一个地址有 physical_address
- 地址有 postal_addrsss
地址模型
belongs_to :customer, optional: true # Yes, optional
has_one :physical_address, dependent: :destroy
has_one :postal_address, dependent: :destroy
accepts_nested_attributes_for :physical_address
accepts_nested_attributes_for :postal_address
邮政地址模型
# same for physical_address.rb
belongs_to :address
客户控制员:
def create
@customer = current_user.customers.build(customer_params)
if @customer.save
return puts "customer saves"
end
puts @customer.errors.messages
#redirect_to new_customer_path
render :new
end
private
def customer_params
params.require(:customer).permit(
address_attributes: address_params
)
end
def address_params
return ([
postal_address_attributes: shared_address_params,
#physical_address_attributes: shared_address_params
])
end
def shared_address_params
params.fetch(:customer).fetch("address").fetch("postal_address").permit(
:street, etc...
)
end
客户型号:
has_one :address, dependent: :destroy
accepts_nested_attributes_for :address
客户已成功创建,但地址未创建。这是表格,例如:
<form>
<input name="customer[address][postal_address][street]" value="Foo Street" />
</form>
记录“params”,我看到了所有值,但没有创建地址。我认为错误在于 shared_address_params
。有什么想法吗?
我认为您只是在该参数白名单的间接层和复杂性中迷失了自己。
你基本上想要的是:
def customer_params
params.require(:customer)
.permit(
address_attributes: {
physical_address_attributes: [:street, :foo, :bar, :baz],
postal_address: [:street, :foo, :bar, :baz]
}
)
end
正如您在此处看到的,您需要参数键 customer[address_attributes]
而不仅仅是 customer[address]
。
现在让我们重构以减少重复:
def customer_params
params.require(:customer)
.permit(
address_attributes: {
physical_address_attributes: address_attributes,
postal_address: address_attributes
}
)
end
def address_attributes
[:street, :foo, :bar, :baz]
end
如您所见,这里应该不会增加任何复杂性,如果您需要使其更灵活,请向 address_attributes
方法添加参数 - 毕竟构建白名单只是简单的数组和哈希操作.
如果你想处理将某种共享属性映射到两种地址类型,你真的应该在模型中进行,而不是用业务逻辑使控制器膨胀。例如,通过为“虚拟属性”创建 setter 和 getter:
class Address < ApplicationController
def shared_address_attributes
post_address_attributes.slice("street", "foo", "bar", "baz")
end
def shared_address_attributes=(**attrs)
# @todo map the attributes to the postal and
# visiting address
end
end
这样您就可以像设置任何其他属性一样设置表单并将其列入白名单,而控制器不需要关心细节。
def customer_params
params.require(:customer)
.permit(
address_attributes: {
shared_address_attributes: address_attributes,
physical_address_attributes: address_attributes,
postal_address: address_attributes
}
)
end