嵌套关联未保存



我有一个客户的嵌套关联。设置如下:

  • 客户只有一个地址
  • 地址具有物理地址
  • 地址有postal_addrss

地址模型

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方法添加参数——毕竟,构建白名单只是简单的数组和哈希操作。

如果你想处理将某种共享属性映射到这两种地址类型,你真的应该在模型中完成,而不是用业务逻辑夸大控制器。例如,通过为";虚拟属性":

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

相关内容

  • 没有找到相关文章

最新更新