Automatically create a has_one and belongs_to associations object
If you ever had a wonderful situation when you registered associations for models (has_one and belongs_to), accepted_nested_attributes, but the fields_for helper does not show the form, then this post will help you get rid of this “glitch” once and for all. I warn you in advance that the post is purely for rails developers, and no one will be interested in developers except rails for anyone!
So, let's say we have the following models:
We need a company form with user and location resources nested. At first glance, it might seem that the code:
will be enough to show the desired shape. However, it is not. By launching the application and opening the browser, you will see that instead of the expected 3 fields on the page, there is only one thing - this is the name field for company (it is assumed that we have an initialized object like this:
The problem is that we did not initialize the associated user and location objects for @company:
If these conditions are met before the field_for helpers are executed, the form will look as we expected. However, writing such code every time in the controllers is somehow not serious, because the controllers must be clean!
This problem can be avoided with the help of this gem , which has a slightly awkward name - get_or_build .
Add the line to the Gemfile:
Install gems: bundle install, restart the application and refactor the fields_for helpers as follows:
After that, the initialization code for user and location association objects can be removed from controllers, templates, and helpers (somewhere else where it is;) and is no longer needed).
I would be very grateful for the criticism and comments, volunteers for the development of the gem are also welcome. Thanks for attention!
Preconditions
So, let's say we have the following models:
class Company < ActiveRecord::Base
belongs_to :location
has_one :user
accepts_nested_attributes_for :user
accepts_nested_attrbiutes_for :location
end
class User < ActiveRecord::Base
belongs_to :company
end
class Location < ActiveRecord::Base
has_one :company
end
We need a company form with user and location resources nested. At first glance, it might seem that the code:
form_for :company do |f|
f.text_field :name
f.fields_for :user, f.object.user_or_build do |fu|
fu.text_field :name
end
f.fields_for :location, f.object.location_or_build do |fl|
fl.text_field :address
end
end
will be enough to show the desired shape. However, it is not. By launching the application and opening the browser, you will see that instead of the expected 3 fields on the page, there is only one thing - this is the name field for company (it is assumed that we have an initialized object like this:
@company = Company.new
)What is wrong with this code?
The problem is that we did not initialize the associated user and location objects for @company:
@company.build_location # то же что и @company.location = Location.new
@company.build_user # то же что и @company.user = User.new
If these conditions are met before the field_for helpers are executed, the form will look as we expected. However, writing such code every time in the controllers is somehow not serious, because the controllers must be clean!
Decision
This problem can be avoided with the help of this gem , which has a slightly awkward name - get_or_build .
Add the line to the Gemfile:
gem 'get_ot_build'
Install gems: bundle install, restart the application and refactor the fields_for helpers as follows:
form_for :company do |f|
f.fields_for :user, :build_association => true do |fu|
fu.text_field :name
end
f.fields_for :user, :build_association => true do |fl|
fl.text_field :address
end
end
After that, the initialization code for user and location association objects can be removed from controllers, templates, and helpers (somewhere else where it is;) and is no longer needed).
I would be very grateful for the criticism and comments, volunteers for the development of the gem are also welcome. Thanks for attention!