在Rails应用程序中使用accepts_nested_attributes_for时,如何维护嵌套属性的排序

Bha*_*rat 19 ruby-on-rails nested-attributes

这是父模型:

class TypeWell < ActiveRecord::Base
   ...

  has_many :type_well_phases, :dependent => :destroy
  accepts_nested_attributes_for :type_well_phases, :reject_if => lambda { |a| a[:phase_id].blank? }, :allow_destroy => true

  ...
end
Run Code Online (Sandbox Code Playgroud)

这是嵌套模型:

class TypeWellPhase < ActiveRecord::Base

  belongs_to :type_well
  belongs_to :phase

end
Run Code Online (Sandbox Code Playgroud)

这是阶段模型:

class Phase < ActiveRecord::Base
  ... 
  has_many :type_well_phases
  ...
end
Run Code Online (Sandbox Code Playgroud)

我通过在父模型的控制器中复制我的阶段(阶段模型)表中的所有记录来在子表(TypeWellPhases)中添加嵌套记录,如下所示:

class TypeWellsController < ResourceController
   ...
  def new
    @new_heading = "New Type Well - Computed"
    @type_well   = TypeWell.new
    initialize_phase_fields
  end

  private

  def initialize_phase_fields
    Phase.order("id").all.each do |p|
      type_well_phase               = @type_well.type_well_phases.build
      type_well_phase.phase_id      = p.id
      type_well_phase.gw_heat_value = p.gw_heat_value
    end
  end
  ...
end
Run Code Online (Sandbox Code Playgroud)

我这样做是因为我想通过添加的子字段维护特定的顺序.代码Phase.order("id")的部分用于此,因为阶段表按特定顺序具有这些记录.

在此之后我使用simple_form_for和simple_fields_for帮助器,如下面的表单部分所示:

= simple_form_for @type_well do |f|
    ...
    #type_well_phases
      = f.simple_fields_for :type_well_phases do |type_well_phase|
        = render "type_well_phase_fields", :f => type_well_phase
Run Code Online (Sandbox Code Playgroud)

一切都按预期工作; 大部分的时间.但是,有时表单中Child行的顺序在保存后会搞乱.顺序在此应用程序中很重要,这就是我在控制器中的私有方法中明确执行此排序的原因.

我使用"cocoon"gem来添加删除子记录.我不确定为什么这个订单有时搞砸了.

很抱歉这么长的帖子,但我想提前提供所有相关细节.

感谢任何指针.

巴拉特

jdo*_*doe 44

我会以更通用的方式解释你.比如说,您有产品和订单型号:

= form_for @product do |f|
    ...
    = f.fields_for :orders do |order_fields|
        = order_fields.text_field :name
Run Code Online (Sandbox Code Playgroud)

如果您希望按名称对订单进行排序,那么只需对它们进行排序:)

代替:

    = f.fields_for :orders do |order_fields|
Run Code Online (Sandbox Code Playgroud)

放:

    = f.fields_for :orders, f.object.orders.order(:name) do |order_fields|
Run Code Online (Sandbox Code Playgroud)

如您所见,f变量是form_for具有方法的块的参数object.这是你的@product,所以你可以通过获取订单.orders,然后通过应用所需的排序.order(:name)(抱歉这个小混乱:订单/订单).

解决方案的关键,您可以将排序的订单作为第二个参数传递给fields_for.

PS您使用simple_form gem不会影响我的解决方案.如果你向帮助者添加'simple_',它会起作用.只是希望我的回答对其他人更有帮助,而不是与任务有关.

  • @DevR根本不使用`.order(:name)`,而是`.sort_by {| o | o.name.to_s}`,以便在ruby数组上操作排序,而不是在SQL查询的意义上操作. (7认同)
  • 警告:这个解决方案不保留预先构建的对象,即如果你在控制器中执行`@ product.orders.build`,你就不会得到一个新对象,只有持久对象. (4认同)