Rails nested form with three models - ruby-on-rails

I have three models
class Property < ActiveRecord::Base
has_many :contact
accepts_nested_attributes_for :contact
has_many :business
accepts_nested_attributes_for :business
end
class Business < ActiveRecord::Base
belongs_to :property
has_many :contact
end
class Contact < ActiveRecord::Base
belongs_to :property
belongs_to :business
end
I created a form that creates the Property with a nested contact and a nested business, how can I get that business to have a nested contact?
Here is my form
<%= form_for(#property) do |f| %>
<div class="field">
<%= f.label :address %><br>
<%= f.text_field :address %>
</div>
<% end %>
<%= f.fields_for :contact do |contact_form| %>
<div class="field">
<%= f.label :contact_title, "Title" %><br>
<%= contact_form.text_field :title %><br>
<%= f.label :contact_name, "Name" %><br>
<%= contact_form.text_field :name %><br>
</div>
<% end %>
<%= f.fields_for :business do | business_form| %>
<div class="indv-biz field">
<%= f.label :business_name, "Name" %><br>
<%= business_form.text_field :name %><br>
</div>
<div class="business-contact">
<p>Business Contact</p>
<%= f.fields_for :business_contact do | business_contact | %>
<div class="field">
<%= business_contact.label :contact_title, "Title" %><br>
<%= business_contact.text_field :title %><br>
<% end %>
<% end %>
I can get it to save so the business is connected to the property and the contact is connected to the property but I can't figure out how to get a contact connected to the business
Thanks

You should try deep nesting like this. your requirement is a property have many business which in-turn have many contacts. In this case, you actually should do is setting nested form for property with business and that business should have nested form of contacts. The below one will work for you.
Form
nested_form_for #property do |f|
...
f.fields_for :bussiness do |bussiness_form|
...
bussiness_form.fields_for :contact_form do |contact_form|
....
end
end
end
end
Models
class Property < ActiveRecord::Base
has_many :contact
has_many :business
accepts_nested_attributes_for :business
end
class Business < ActiveRecord::Base
belongs_to :property
has_many :contacts
accepts_nested_attributes_for :contacts
end
class Contact < ActiveRecord::Base
belongs_to :property
belongs_to :business
end
controller
def property_params
params.require(:property).permit(:id,.., :bussiness_attributes => [:id,.., , :contacts_attributes => [:id, ..]])
end

Related

Rails 4.0 nested object forms not rendered

I have two models in my app: "WorkPost" and "Contacts".
WorkPost
class WorkPost < ActiveRecord::Base
has_one :contacts
end
Contacts
class Contacts < ActiveRecord::Base
belongs_to :work_post
end
In my controller's new method I do:
def new
#work_post = WorkPost.new
#work_post.contacts
end
And in view I create form:
<%= form_for(#work_post) do |f| %>
<div class="field">
<%= f.label 'Vacation' %><br>
<%= f.text_field :post_title, :placeholder => 'Vacation here' %>
</div>
<div class="field">
<%= f.label 'Vacation description' %><br>
<%= f.text_area :post_body, :placeholder => 'Vacation description here' %>
</div>
<% f.fields_for :contacts do |cf| %>
<div class="field">
<%= cf.label 'Email' %><br>
<%= cf.text_field :emails, :placeholder => 'Email here' %>
</div>
<% end %>
<div class="actions">
<%= f.submit "Post vacation", :class => 'btn_act' %>
</div>
<% end %>
But it seems like line <% f.fields_for :contacts do |cf| %> doesn't work.
Everything is rendered fine but email field.What I am doing wrong?
The problem is with this line
<% f.fields_for :contacts do |cf| %>
which should be
<%= f.fields_for :contact do |cf| %>
Also, the class name for the model and the association name for has_one/belongs_to should be singular.
#work_post.rb
class WorkPost < ActiveRecord::Base
has_one :contact #should be singular
end
#contact.rb
class Contact < ActiveRecord::Base #should be singular
belongs_to :work_post
end
Also, notice the change :contacts to :contact, as it is a has_one association.
Update:
Also, try the below changes
Include accepts_nested_attributes_for :contact in work_post.rb model
#work_post.rb
class WorkPost < ActiveRecord::Base
has_one :contact
accepts_nested_attributes_for :contact
end
Change the new method to below
def new
#work_post = WorkPost.new
#work_post.build_contact
end

Rails Multiple Associations

I'm having trouble setting up my associations. I'm trying to set up Courses to have different Prices depending on the Season and amount of alumns. It gets even more complicated when Seasons have different date ranges for the same Season, like for instance the first Season is from 12/24/2014 to 12/31/2014 but also from 01/07/2015 to 01/14/2015. For this I created another model Season_dates.
I can't figure out how to set up my associations, here's what I have got so far:
class Season < ActiveRecord::Base
has_many :season_dates
has_many :prices, through: :season_dates
end
class SeasonDate < ActiveRecord::Base
belongs_to :price
belongs_to :seasons
end
class Price < ActiveRecord::Base
belongs_to :course
has_many :season_dates
has_many :seasons, through: :season_dates
accepts_nested_attributes_for :season_dates
end
class Course < ActiveRecord::Base
has_many :prices
end
Form:
<%= form_for #price do |f| %>
<div class="field">
<%= f.fields_for :couse do |course_f| %>
<%= course_f.label :course %><br>
<%= course_f.collection_select :course_id, Course.all, :id, :name, {}, {class: 'form-control'} %>
<% end %>
</div>
<div class="field">
<%= f.label :alumn %><br>
<%= f.number_field :alumn, in: 1...11, step: 1, class: 'form-control' %>
</div>
<div class="field">
<%= f.fields_for :season_date do |season_f| %>
<%= season_f.label :season %><br>
<%= season_f.select :season_id, options_from_collection_for_select(Season.all, :id, :name), {}, {class: 'form-control'} %>
<% end %>
</div>
<div class="field form-group">
<%= f.label :price %><br>
<%= f.number_field :price, in: 0.01..999.99, step: 0.01, placeholder: "0.00€", class: 'form-control' %>
</div>
<div class="actions">
<%= f.submit class: 'btn btn-default' %>
</div>
<% end %>
I want to be able to call price.season.name or price.course.name. I'm not sure how to proceed, any help is appreciated.
I think you might be complicating the scenario a bit. Is there a reason that SeasonDate is its own class? Is there a way you can model like this?
class Season < ActiveRecord::Base
has_many :courses
# I would have on this model the attributes of from_date and
# to_date removing the need for a SeasonDate class
end
class Course < ActiveRecord::Base
belongs_to :season
# You might need to model this as a has_and_belongs_to_many relationship
# with a Season if a Course can belong to many seasons
end
class Price < ActiveRecord::Base
belongs_to :course
belongs_to :season
end
These models would give you methods such as:
#season.courses # would return all courses in a particular season
#price.season.name
#price.course.name
#course.prices # would return all prices associated with a particular course
If you do go for the habtm association, meaning a course can belong to many seasons, you could do something like this (guessing at your price attribute names) in your views.
<%= #course.name %>
<% #course.prices.each do |price| %>
<%= price.season.name %> : <%= price.price_in_dollars %>
<% end
This would allow you to iterate over all prices for a course and display which season they are applicable for so each person can find the best price for them.

'Can't mass-assign protected attributes' when implementing Multiple Table Inheritance with nested forms

HI I am trying to implement the MTI in my application. I have a Person Model and 2 models inheriting from it: Client and TeamMember. When creating a Team Member I want to save to to database vallues for both person (first and last name, email etc) and team member(experience level, type of team, if lead or not). I am using the nested attributes form so in my team member form I am nesting the person fields. Unfortunatellly I am getting "Can't mass-assign protected attributes: person" error when trying to save. Can anyone tell me how this can be solved? Thanks!
Models:
UPDATED TeamMember class but still the same error
also tried people_attributes and persons_attributes and none of these worked
class TeamMember < ActiveRecord::Base
has_many :project_team_members
has_many :projects, through: :project_team_members
has_one :person, as: :profile, dependent: :destroy
accepts_nested_attributes_for :person
attr_accessible :person_attributes, :experience_level, :lead, :qualification, :team
end
class Person < ActiveRecord::Base
belongs_to :company
belongs_to :profile, polymorphic: true
attr_accessible :email, :first_name, :last_name, :phone_number, :profile_id, :profile_type
end
Controller as follows:
class TeamMembersController < ApplicationController
def create
person = Person.create! { |p| p.profile = TeamMember.create!(params[:team_member]) }
redirect_to root_url
end
and the view:
<%= form_for(#team_member) do |f| %>
<%= f.fields_for :person do |ff| %>
<div>
<%= ff.label :first_name %>
<%= ff.text_field :first_name %>
</div>
<div>
<%= ff.label :last_name %>
<%= ff.text_field :last_name %>
</div>
<div>
<%= ff.label :phone_number %>
<%= ff.text_field :phone_number %>
</div>
<div>
<%= ff.label :email %>
<%= ff.text_field :email %>
</div>
<div>
<%= ff.label :company_id %>
<%= ff.text_field :company_id %>
</div>
<% end %>
<div class="field">
<%= f.label :team %><br />
<%= f.text_field :team %>
</div>
<div class="field">
<%= f.label :experience_level %><br />
<%= f.text_field :experience_level %>
</div>
<div class="field">
<%= f.label :qualification %><br />
<%= f.text_field :qualification %>
</div>
<div class="field">
<%= f.label :lead %><br />
<%= f.check_box :lead %>
</div>
<div class="actions">
<%= f.submit %>
</div>
UPDATED TeamMembersController (Solution thanks to the courtesy of Tiago)
def new
#team_member = TeamMember.new
#team_member.build_person
respond_to do |format|
format.html # new.html.erb
format.json { render json: #team_member }
end
end
def create
#team_member = TeamMember.create!(params[:team_member])
redirect_to root_url
end
To mass assign attributes in a nested form, you'll need to specify:
class TeamMember < ActiveRecord::Base
has_many :project_team_members
has_many :projects, through: :project_team_members
has_one :person, as: :profile, dependent: :destroy
:experience_level, :lead, :qualification, :team #what is this line doing??
accepts_nested_attributes_for :person
attr_accessible :person_attributes
end
EDIT:
In the action called before the form you need to build person. Like:
#team_member = TeamMember.new
#team_member.build_person
Then you'll have one person (non-persisted) associated with #team_member.

Model form within another model's form in Ruby on Rails

I have a Content model, a Playlist model and a join association in a model called PlaylistItem.
This is how they're connected:
class Content < ActiveRecord::Base
has_many :playlist_items
has_many :playlists, through: :playlist_items
end
class Playlist < ActiveRecord::Base
has_many :playlist_items, -> { order 'position ASC' }
has_many :contents, through: :playlist_items
end
class PlaylistItem < ActiveRecord::Base
belongs_to :content
belongs_to :playlist
end
When I edit a Playlist, the form only shows its field Name, that's the only attribute that it has. But I want to be able to add a Content to that Playlist (in a certain position, that's the PlaylistItems only attribute) within that form.
How can I do that?
This is the code I have by now:
<%= form_for(#playlist) do |f| %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<%= f.fields_for :playlist_items do |builder| %>
<fieldset>
<%= builder.label :content, "Content ID" %><br>
<%= builder.text_area :content_id %>
</fieldset>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
First, you can let you Playlist model accept nested attributes for playlist_items.
class Playlist < ActiveRecord::Base
has_many :playlist_items, -> { order 'position ASC' }
has_many :contents, through: :playlist_items
accepts_nested_attributes_for :playlist_items
end
Then, you can add content_id as a collection select, which will create a drop down selection of contents for each playlist item.
<%= f.fields_for :playlist_items do |builder| %>
<%= builder.label :position %><br>
<%= builder.integer :position %><br>
<%= builder.label :content %><br>
<%= builder.collection_select :content_id, #contents, :id, :title, include_blank: 'Please Select' %>
<% end %>
Finally, in your controller, you'll need to allow playlist items attributes to be passed as params, and also set your #contents instance variable.
class PlaylistController < ApplicationController
before_action :load_contents, only: [:new, :edit]
def edit
#playlist = Playlist.find(params[:id])
# Build 10 playlist_items to be added to your playlist
10.times do; #playlist.playlist_items.build; end
end
private
def load_contents
#contents = Content.all # or another query to get the specific contents you'd like
end
def playlist_params
params.require(:playlist).permit(:name, playlist_items_attributes: [:id, :position, :content_id])
end
end
Remember that you'll need to build each playlist item that you'd like to use. You can do that in your new and edit methods as you desire.

Rails uninitialized constant for an association

So there is a plethora of questions about the "uninitialized constant" error, and it's almost always due to an incorrectly specified association (e.g. plural model names instead of singular, incorrectly writing your association inside the model, etc). My models and form look spotless, so maybe this is something new (or I'm blind)?
A "user" has one "move". A "move" has many "neighborhood_preferences", and through this, many "neighborhoods".
Models:
class User < ActiveRecord::Base
has_one :move
accepts_nested_attributes_for :move, allow_destroy: true
end
class Move < ActiveRecord::Base
belongs_to :user
has_many :neighborhood_preferences
has_many :neighborhoods, through: :neighborhood_preferences
accepts_nested_attributes_for :neighborhood_preferences, allow_destroy: true
end
class NeighbhoodPreference < ActiveRecord::Base
belongs_to :neighborhood
belongs_to :move
end
class Neighborhood < ActiveRecord::Base
belongs_to :city
has_many :neighborhood_preferences
has_many :moves, through: :neighborhood_preferences
end
View:
<%= simple_form_for(#user, :html => { class: :form } ) do |u| %>
<%= u.fields_for :move do |m| %>
<div>
<%= m.label :start_date %>
<%= m.date_field :start_date %>
</div>
<div>
<%= m.label :end_date %>
<%= m.date_field :end_date %>
</div>
<div>
<%= m.label :min_price %>
<%= m.text_field :min_price %>
</div>
<div>
<%= m.label :max_price %>
<%= m.text_field :max_price %>
</div>
<%= m.association :neighborhood_preferences %>
<% end %>
<%= u.submit "Save Changes" %>
<% end %>
There is a typo in class name NeighbhoodPreference.

Resources