Looks like this feature has been pulled from Edge Rails though it’s tentatively scheduled to come back post the 2.2 release. Vote here if you want to see this feature implemented in Rails!
Nested models (nested forms by another name) describe the scenario when you want to create and modify values of nested attributes through a containing model. For instance, if you have an user model with many phone numbers:
1
2
3
4
5
6
7
8
9
|
class User < ActiveRecord::Base
validates_presence_of :login
has_many :phone_numbers
end
class PhoneNumber < ActiveRecord::Base
validates_presence_of :area_code, :number
belongs_to :user
end |
you may want to be able to create the user and a group of phone numbers at the same time. This is what this looks like with the new mass assignment functionality of Rails keyed off of the :accessible option of the association declaration (:phone_numbers, in this case).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class User < ActiveRecord::Base
validates_presence_of :login
has_many :phone_numbers, :accessible => true
end
ryan = User.create( {
:login => 'ryan',
:phone_numbers => [
{ :area_code => '919', :number => '123-4567' },
{ :area_code => '920', :number => '123-8901' }
]
})
ryan.phone_numbers.count #=> 2 |
A single hash of values being sent to User.create results in both a new user object and new associated phone numbers. Previously, you would have had to manually create your own phone_numbers= setter method on user to get this same functionality:
1
2
3
4
5
6
7
8
9
10
11
|
class User < ActiveRecord::Base
...
def phone_numbers=(attrs_array)
attrs_array.each do |attrs|
phone_numbers.create(attrs)
end
end
end |
Mass assignment now gives you this functionality for free.
This may not look like much, but it is a step in the direction of letting you use nested forms. Consider a user registration form where a user can enter their login name and their phone numbers in the same form (through the use of fields_for which will bundle nested model attributes into a single form):
1
2
3
4
5
6
7
8
|
<% form_for @user do |f| %>
<%= f.text_field :login %>
<% fields_for :phone_numbers do |pn_f| %>
<%= pn_f.text_field :area_code %>
<%= pn_f.text_field :number %>
<% end %>
<%= submit_tag %>
<% end %> |
This form, when submitted to the following standard RESTful UserController, will correctly create the user and its associated phone numbers through the beauty of mass assignment.
1
2
3
4
5
6
7
8
9
10
|
class UserController < ApplicationController
# Create a new user and their phone numbers with mass assignment
def new
@user = User.create(params[:user])
respond_to do |wants|
...
end
end
end |
Mass assignment can be used on all association types – :belongs_to, :has_one, :has_many and :has_and_belongs_to_many as long as the :accessible => true option is specified.
This is a very convenient addition to ActiveRecord, but the real zinger will come with full nested form support when you can create, update and delete these nested models directly from what is pushed down in the parameter hash of a form submission. This would allow for the functionality in this complex forms screencast with minimal hassle. What a fine day that would be.
tags: ruby,
rubyonrails