form_for non-AR model - fields_for Array attribute doesn't iterate
Asked Answered
B

3

11

I'm having trouble getting fields_for to work on an Array attribute of a non-ActiveRecord model.

Distilled down, I have to following:

models/parent.rb

class Parent
  extend ActiveModel::Naming
  include ActiveModel::Conversion
  include ActiveModel::Validations
  extend ActiveModel::Translation

  attr_accessor :bars
end

controllers/parent_controller.rb

def new_parent
  @parent = Parent.new

  @parent.bars = ["hello", "world"]
  render 'new_parent'
end

views/new_parent.html.haml

= form_for @parent, :url => new_parent_path do |f|
  = f.fields_for :bars, @parent.bars do |r|
    = r.object.inspect

With the code as above, my page contains ["hello", "world"] - that is, the result of inspect called on the Array assigned to bars. (With @parent.bars omitted from the fields_for line, I just get nil displayed).

How can I make fields_for behave as for an AR association - that is, perform the code in the block once for each member of my bars array?

Batavia answered 25/11, 2011 at 16:37 Comment(1)
Thanks for this. I didn't think anyone else had tried to do this! Thanks... a lot!Lp
B
13

I think the correct technique is:

= form_for @parent, :url => new_parent_path do |f|
  - @parent.bars.each do |bar|
    = f.fields_for "bars[]", bar do |r|
      = r.object.inspect

Quite why it can't be made to Just Work I'm not sure, but this seems to do the trick.

Batavia answered 3/1, 2012 at 9:49 Comment(0)
S
1

I think that it can be done without the need of each:

= form_for @parent, :url => new_parent_path do |f|
  = f.fields_for :bars do |r|
    = r.object.inspect

You need to set some methods that are expected in the parent class to identify the collection.

class Parent
  def bars_attributes= attributes
  end
end

And you also will need to make sure that the objects in the array respond to persisted (so you cannot use strings) :(

Sikh answered 1/10, 2015 at 20:15 Comment(0)
B
0

I ditched the fields_for and added multiple: true

= form_for @parent, :url => new_parent_path do |f|
  - @parent.bars.each_with_index do |bar, i|
    = f.text_field :bars, value: bar, multiple: true, id: "bar#{i}"
Barrows answered 4/11, 2017 at 13:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.