我有一个父母,accepts_nested_attributes_for
是一个孩子。所以,当我有父母的表格时,我需要build
孩子,所以我也可以为它显示表格字段。我想知道的是:我应该在哪里build
孩子?在模型,视图或控制器中?
你可能会摇头,以为我是一个疯狂的人,因为他提出了这样的问题,但这里的思路让我在这里。
我有一个Customer
模型,accepts_nested_attributes_for
一个billing_address
,如下所示:
class Customer
belongs_to :billing_address, class_name: 'Address'
accepts_nested_attributes_for :billing_address
end
当我向用户提供新Customer
的表单时,我想确保空白billing_address
,以便用户实际看到billing_address
的字段。所以我的控制器中有这样的东西:
def new
@customer = Customer.new
@customer.build_billing_address
end
但是,如果用户未填写任何billing_address
字段,但尝试提交无效表单,系统会向其显示一个不再包含billing_address
字段的表单,除非我在我的控制器的create
动作中添加了这样的内容:
def create
@customer = Customer.new(params[:customer])
@customer.build_billing_address if @customer.billing_address.nil?
end
还有另一个问题,即如果用户尝试编辑Customer
,但Customer
已经没有关联的billing_address
,则他们将看不到字段对于billing_address
。所以我必须向控制器添加这样的东西:
def edit
@customer = Customer.find(params[:id])
@customer.build_billing_address if @customer.billing_address.nil?
end
类似的东西需要在控制器的update
方法中发生。
无论如何,这是高度重复的,所以我想在模型中做一些事情。我最初的想法是为模型的after_initialize
事件添加一个回调,如下所示:
class CustomerModel
after_initialize :build_billing_address, if: 'billing_address.nil?'
end
但我的蜘蛛般的感觉开始刺痛。谁会说我将来不会在我的代码的其他部分实例化Customer
,并以某种意想不到的方式造成严重破坏。
所以我目前的想法是,最好的地方是在表单视图本身,因为我要完成的是为表单创建一个空白billing_address
,表单本身是唯一的在我知道的代码中放置我将要显示billing_address
的表单。
但是,你知道,我只是互联网上的一些人。我应该在哪里build_billing_address
?
答案 0 :(得分:3)
尽管Xavier Shay的this advice是2011年,但他建议将其放入 视图 ,"因为这是一个视图问题(我们是否显示字段?)" :
应用/助手/ form_helper.rb:强>
module FormHelper
def setup_user(user)
user.address ||= Address.new
user
end
end
应用/视图/用户/ _form.html.erb:强>
<%= form_for setup_user(@user) do |f| %>
请注意,我必须将帮助方法更改为以下内容:
def setup_user(user)
user.addresses.build if user.addresses.empty?
user
end
控制器保持完全不变。
答案 1 :(得分:1)
如果你想建立一些东西并稍后保存,你会使用build。我会说,在嵌套路线中使用它。
def create
@address = @customer.billing_addresses.build(params[:billing_address])
if @address.save
redirect_to @customer.billing_addresses
else
render "create"
end
end
这样的事情。我在控制台时也使用构建。
答案 2 :(得分:1)
你必须记住MVC的原则,即创建DRY(不要重复自己)代码,这些代码在应用程序的各个移动部分之间有效分配
accepts_nested_attributes_for
非常适合保持干净
accepts_nested_attributes_for
是一个模型函数,它允许您通过关联将数据传递给另一个模型。它存在的原因是为了让您能够基于单个表单填充另一个模型的数据,并且非常适合在没有太多额外代码的情况下扩展功能
您引用的问题是,如果您想在应用的其他区域使用该代码,您最终会遇到各种各样的问题
我的反驳是为了创建尽可能高效的应用程序,你想尽可能少地编写代码 - 让Rails处理所有事情。 accepts_nested_attributes_for
函数允许您执行此操作,但显然需要付出代价,因为每次要使用它时都必须适应它
我的建议是使用您认为最有效的代码,但也要遵守惯例;因为这将确保速度和效率
答案 3 :(得分:1)
如果您知道您的模型总是有帐单邮寄地址,您可以按照the docs中所述覆盖模型类中此属性的getter:
def billing_address
super || build_billing_address
end
根据您的特定需求,可以选择将任何属性传递给build_billing_address
。
答案 4 :(得分:1)
您应该在控制器中处理所有这些场景,因为它不是模型的责任。
就保持干燥而言,你可以写一个方法,
def build_customer(customer)
customer.build_billing_address if customer.billing_address.nil?
#add more code if needed
end
在控制器内部,您可以在需要的地方调用此方法。例如
def create
@customer = Customer.new(params[:customer])
if @customer.save
redirect_to @customer.billing_addresses
else
build_customer(@customer)
render "new"
end
end