Search code examples
ruby-on-railsrubyfields-for

Ruby on Rails 4 fields_for number of repetitions


I would like to display a form with four nested fieldsets for associated objects. The only way I've found is to override the initialize method and define four associations:

RUBY

def initialize(attributes = {})
  super
  4.times { items << Item.new }
end

and then display nested fields normally:

HAML

= f.fields_for :items do |item|
  = render 'item_fields', f: item

This is not working when I try to edit objects that already exist and have fewer number of associated items.

Any help will be appreciated.

MORE INFO:

Order has_many items
OrderSet has_many orders

Orders are added through the cocoon gem (there is at least one order in each set)

There should always be four items for each order. But when there are less items I don't want to save empty records, instead I would like to just display remaining items as empty.


Solution

  • The initialize is not the place as it is executed every time a new Order instance is created, this means: also when retrieving an existing order from the database.

    Imho the view is also not the optimal place.

    I would solve this in the controller:

    def new
      @order = Order.new
      4.times { @order.items.build }
    end
    

    and then you can just leave your model/view as they were originally.

    If you always want to show 4 nested items, you can do something similar in the edit action (to fill up to 4)

    def edit
      @order = Order.find(params[:id])
      (@order.items.length...4).each { @order.items.build }
    end
    

    In my personal opinion this is cleaner then doing it in the view.

    [EDIT: apparently it is a double nested form]

    So, in your comment you clarified that it is a double-nested form, in that case, I would use the :wrap_object option as follows (it gets a bit hard to write a decent example here, without you giving more details, so I keep it short and hope it is clear). I am guessing you have a form for "something", with a link_to_add_association for :orders, and that order needs to have several (4) items, so you could do something like:

    = link_to_add_association('add order', f, :orders,
    :wrap_object => Proc.new { |order| 4.times { order.items.build}; order })