Saving Multiple ActiveRecord objects at once that _aren't_ nested

It struck me today that there's no way to emulate accepts_nested_attributes_for for saving multiple objects that aren't nested.

accepts_nested_attributes_for gives a good pattern for managing multiple objects in a single form, elegantly handling current records and new records, and validations for the lot of them.

Should there be an equivalent way to manage multiple objects in a single form that aren't nested under any parent? Something like:

@posts = Post.all

<% form_for @posts do |f| %>   <% fields_for :post %>     ...   <% end %> <% end %>

What do you think?

Paul

@posts = Post.all

<% form_for @posts do |f| %> <% fields_for :post %> ... <% end %> <% end %>

What do you think?

I think most of the time the better solution here is to have an 'owning record' of some sort. For example:

<% form_for @blog ... %>

Otherwise what would go in the controller action? What would we be calling .attributes= on?

I guess one of the use cases is a list of checkboxes, eg:

... but I think it holds for any list that would present multiple non-nested objects for editing in a single form.

Ryan's implementation makes use of form_tag and a loop inside the controller action ... which to me indicates a bit of code smell, but also that Rails doesn't yet have an elegant solution.

Otherwise what would go in the controller action? What would we be calling .attributes= on?

I'm not exactly sure how the best solution would work.

I'm not certain about the owning record in this case ... <%= form_for @post ... %> doesn't express any intent that there's going to be multiple objects in the form ( where for example, <% fields_for :comments %> does...

It might also require a class method on active record that would accept multiple records to create or update. Perhaps an equivalent of find_or_create ... that would mirror the behaviour of accepts_nested_attributes_for ... maybe something like:

Post.create_or_update_many( { '0' => { # create record... }, { '1' => { # update record } } )

... another option would be to use some kind of presenter pattern ( <% form_for @posts_collection ... %> ) to mock the owning record ... but I've never been fully sold on presenters.

If there's interest in this I'd be happy to spin up a plugin or a patch.

Paul

I think this would be the best option, as you can simply use the existing code. Although you probably need to make some adjustments here and there, for which you could write a plugin/patch.

Eloy

There is a lot of magic in Rails that I'm trying to get my head around. Specifically, I get this error with Ruby -r24788 (today's snapshot) and Rails (fails both in 2.3.4 and edge).

I would like to work out if this is a 1.9.2 incompatibility with Rails or a bug in Ruby (most likely the latter):

  foo@studio:~/work/bar$ rake db:migrate --trace

  (snip)

  ** Execute db:migrate   rake aborted!   undefined method `singleton_method_added' for ActiveRecord::Migration:Class   /home/foo/backup/work/bar/vendor/rails/activerecord/lib/active_record/migration.rb:297:in `singletonclass'   /home/foo/backup/work/bar/vendor/rails/activerecord/lib/active_record/migration.rb:265:in `<class:Migration>'   /home/foo/backup/work/bar/vendor/rails/activerecord/lib/active_record/migration.rb:261:in `<module:ActiveRecord>'   /home/foo/backup/work/bar/vendor/rails/activerecord/lib/active_record/migration.rb:3:in `<top (required)>'   /home/foo/backup/work/bar/vendor/rails/railties/lib/tasks/databases.rake:135:in `block (2 levels) in <top (required)>'

  (snip)

It seems like its trying to call singleton_method_added before it actually is defined. I wanted to isolate a test case for the ruby parser - where is this called from, or how is the singleton instance callback set up?

This is caused by the call (cattr_accessor):

  ActiveRecord::Migration.verbose = ...

Any tips or documentation pointers would help.

Thanks in advance.