【问题标题】:Rails 5 - find_or_create_by with nested attributesRails 5 - 带有嵌套属性的 find_or_create_by
【发布时间】:2017-11-24 21:40:34
【问题描述】:

我正在尝试创建一个新对象,其关联记录采用相同的形式,但希望关联记录使用find_or_create_by 而不仅仅是创建(因为关联的模型记录可能并且大部分时间已经存在)。在过去的两天里,我一直在挖掘与这个主题相关的每一篇文章和文章,试图让它发挥作用,但我的表单仍然试图只创建新对象,而不是搜索现有对象。

模型

#order.rb
has_many :order_owners, dependent: :destroy, inverse_of: :order
has_many :owners, through: :order_owners

accepts_nested_attributes_for :order_owners

#owner.rb
has_many :order_owners, dependent: :destroy
has_many :orders, through: :order_owners
validates :name, presence: true, uniqueness: { case_sensitive: false } 

#order_owner.rb
belongs_to :owner
belongs_to :order

accepts_nested_attributes_for :owner

表格

orders/new.html.erb

<%= bootstrap_form_for(@orders, layout: :horizontal, label_col: "col-sm-2", control_col: "col-sm-6") do |f| %>
  <%= render 'shared/error_messages', object: f.object %>

  ...

  <%= f.fields_for :order_owners do |orderowner| %>

    <%= render 'orders/new_order_owners', f: orderowner, render_partial: 'orders/new_order_owners' %>

  <% end %>

  ...

  <%= f.form_group do %>
    <%= f.submit "Create Order", class: "btn btn-primary" %>
    <%= link_to_add_association fa_icon("plus", text: "Add Owner"), f, :order_owners,
                                  class: "btn btn-outline pull-right #{orderBtnDisable(@properties)}", partial: "orders/new_order_owners", id: "newOrderOwnerAdd" %>
  <% end %>
<% end %>

orders/new_order_owners部分

<div class="m-t-md m-b-md border-bottom form-horizontal nested-fields">

  <%= link_to_remove_association(fa_icon("remove", text: ""), f, { class: "btn btn-danger btn-outline pull-right" }) %>

  <% f.object.build_owner unless f.object.owner %>

  <%= f.fields_for :owner do |owner| %>
    <%= owner.select :name, options_from_collection_for_select(@owners, "name", "name"),
               { label: "Name:", include_blank: true }, { id: "orderPropOwnerSelect", data: { placeholder: "Select an existing Owner or type a new one.."} } %>
  <% end %>

</div>

控制器

orders/new

def new
  @order = Order.new
  @order.build_property
  @order.order_owners.build.build_owner
  @properties = Property.find_by_id(params[:property_id])
  if @properties
    @owners = @properties.owners
  else
    @owners = []
  end
  respond_to do |format|
    format.html
    format.js
  end
end

orders/create

def create
  @properties = Property.find(params[:order][:property_id])
  @order = @properties.orders.create(order_params)
  respond_to do |format|
    format.html { if @order.save
                    if params[:order][:owners_attributes]
                      order_prop_owner_check(@order, @properties)
                    end
                    flash[:success] = "Order created successfully!"
                    redirect_to property_order_path(@properties, @order)
                  else
                    @properties
                    @owner = @properties.owner
                    render 'new'
                  end
    }
    format.js {
                  if @order.save
                    flash.now[:success] = "Order Updated Successfully!"
                  else
                    flash.now[:danger] = @order.errors.full_messages.join(", ")
                  end
    }
  end
end

正如您在new 操作中看到的那样,我实例化了新订单,构建了它的关联属性(它属于订单的所属对象),构建了新的 order_owner 关系,并为该关系构建了所有者。然后在提交时通过@properties.orders.create(order_params) 创建订单。

我得到的错误是“订单所有者所有者名称已存在”。很明显,它没有按名称查找所有者。 我试过了:

  • 在 order.rb 和 order_owner.rb 中重新定义 autosave_associated_records_for_owner,同时使用 belongs_to 和 has_many 变体,但似乎它们从未被调用,所以我一定做错了什么。 (我已经尝试了几乎所有可以在 SO 上找到的答案的变体)
  • before_add: 在 order.rb 中对 has_many :owners, through: :order_ownershas_many :order_owners 进行回调。
  • 在 order.rb 中扩展 has_many :ownershas_many :owners, through: :order_owners 以及在 order_order.rb 中扩展 belongs_to :owner

我还尝试了调用关联的不同变体等形式,所以我一定只是误解了一些东西。我也在使用 Cocoon 来管理嵌套表单,但我已经与作者讨论了不相关的问题,并且 Cocoon 本质上只是嵌套表单的视图助手,因此解决方案必须在模型/控制器中。

欢迎提出任何想法。提前致谢。

附:我在控制器动作中留下了可能/可能不属于这个确切帖子的代码,但我想展示整个动作的完整性。如果重要,当在另一个字段中选择属性时,我通过 AJAX 手动设置所有者选择。基本上它只是查找属性并将现有所有者添加到所有者选择中。

【问题讨论】:

  • 确认一下,OrderOwner 表是连接表吗?也就是说,它真的只有订单的id和所有者的id吗?另外,你能添加你的路线吗?
  • 另外,对不起,如果我在这里很密集,但是你到底什么时候打电话给.find_or_create_by
  • 嘿,为延迟回复道歉,花了一整天的时间旅行。是的OrderOwner 是一个只有order_idowner_id 的连接表/模型。目前,我在任何时候都不会打电话给find_or_create_by,因为我无法让它工作。理想情况下,我希望在通过 Order 的嵌套属性创建所有者时调用它。从我发现的所有内容来看,OrderOwner 表中的autosave_associated_records_for_owner 似乎(所以我认为)应该是我的票,但我无法让它发挥作用。我应该发布哪组路线?订单?

标签: ruby-on-rails ruby-on-rails-5 nested-forms nested-attributes


【解决方案1】:

所有者嵌套在订单中。因此,当您调用 order.save 时,它​​会运行所有验证(包括所有者的)。如果您想使用find_or_create_by,您需要在before_save 中进行,这样您就可以在验证命中之前对所有者进行修改。

#order.rb

before_save :find_or_create_owner

def find_or_create_owner
  self.order_owners.each do |order_owner|
    order_owner.owner = Owner.find_or_create_by(name: final_owner.name)
  end
end

根据您的表单和业务逻辑,可能需要进一步定制,但这是主要概念。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多