Nested form with has_many - ruby-on-rails

I'm trying to make a nested form,
my form is for model A which have many Bs, and have to save them all on the save form.
The problem is: I'm building 3 bs on A controller, but only one field is showing up,
here's the code:
class A:
class A < ActiveRecord::Base
has_many :bs
accepts_nested_attributes_for :bs
end
class B:
class B < ActiveRecord::Base
belongs_to :a
end
A controller:
class AController < ApplicationController
def new
#a = A.new
3.times { #a.bs.build }
end
end
A and B form:
<%= form_for :a do |f| %>
<%= f.fields_for :bs do |b| %>
<%= b.text_field :name, :class => 'default' %>
<% end %>
<% end %>

<%= form_for #a do |f| %>
<%= f.fields_for :bs do |b| %>
<%= b.text_field :name, :class => 'default' %>
<% end %>
<% end %>
#a, not :a

Related

Rails not saving nested attributes

I have the tables Task and Item. I have a form for Item where I record all the possible items that my Tasks may have, which is working fine. Then I have the form for Task where all the Items are displayed alongside a field to put a cost value for each item. This will result in a join between Task and Item: TaskItem (this table contains task_id, item_id and cost).
When I submit the form, it's saving the Task but not the TaskItems associated. I don't see what I'm missing as I searched a lot for this problem and nothing seems to work. Please, see the code below.
Model:
class Task < ApplicationRecord
has_many :task_items
has_many :items, :through => :task_items
accepts_nested_attributes_for :task_items, :allow_destroy => true
end
class Item < ApplicationRecord
has_many :task_items
has_many :tasks, :through => :task_items
end
class TaskItem < ApplicationRecord
belongs_to :task
belongs_to :item
accepts_nested_attributes_for :item, :allow_destroy => true
end
Controller:
def new
#items = Item.all
#task = Task.new
#task.task_items.build
end
def create
#task = Task.new(task_params)
#task.save
redirect_to action: "index"
end
private def task_params
params.require(:task).permit(:id, :title, task_items_attributes: [:id, :item_id, :cost])
end
My view:
<%= form_for :task, url:tasks_path do |f| %>
<p>
<%= f.label :title %><br>
<%= f.text_field(:title, {:class => 'form-control'}) %><br>
</p>
<% #items.each do |item| %>
<% #task_items = TaskItem.new %>
<%= f.fields_for :task_items do |ti| %>
<%= ti.label item.description %>
<%= ti.text_field :cost %>
<%= ti.hidden_field :item_id, value: item.id %>
<% end %>
<% end %>
<p>
<%= f.submit({:class => 'btn btn-primary'}) %>
</p>
You need to add inverse_of option to the has_many method in class Task:
class Task < ApplicationRecord
has_many :task_items, inverse_of: :task
has_many :items, through: :task_items
accepts_nested_attributes_for :task_items, :allow_destroy => true
end
This is due to the when creating a new TaskItem instance, it requires that the Task instance already exists in database to be able to grab the id fo the Task instance. Using this option, it skips the validation.
You can read this post about inverse_of option and its use cases.
fields_for has an option to specify the object which is going to store the information. This combined with building each of the TaskItem from the has_many collection should ensure that all the relationship are set correctly.
View Code:
<%= form_for #task do |f| %>
<p>
<%= f.label :title %><br>
<%= f.text_field(:title, {:class => 'form-control'}) %><br>
</p>
<% #items.each do |item| %>
<% task_item = #task.task_items.build %>
<%= f.fields_for :task_items, task_item do |ti| %>
<%= ti.label item.description %>
<%= ti.text_field :cost %>
<%= ti.hidden_field :item_id, value: item.id %>
<% end %>
<% end %>
<p>
<%= f.submit({:class => 'btn btn-primary'}) %>
</p>
<% end %>
Controller Code:
def index
end
def new
#items = Item.all
#task = Task.new
end
def create
#task = Task.new(task_params)
#task.save
redirect_to action: "index"
end
private
def task_params
params.require(:task).permit(:id, :title, task_items_attributes: [:id, :item_id, :cost])
end

add property to many lists rails4

I want to create property . Then add it on many lists. One Property can be on many list.
here is my models:
class List < ActiveRecord::Base
has_many :propertyships
has_many :properties, :through => :propertyships
end
class Propertyship < ActiveRecord::Base
belongs_to :list
belongs_to :property
end
class Property < ActiveRecord::Base
has_many :propertyships
has_many :lists, :through => :propertyships
end
properties/show.html.erb
<%= form_for #property do |f| %>
<% List.all.each do |list| %>
<%= check_box_tag "property[list_ids][]", list.id,#property.list_ids.include?(list.id) %>
<%= list.name %>
<% end %>
<%= f.submit %>
<% end %>
property is not adding to lists.
what am i doing wrong??
Use collection_check_boxes instead of manually creating the inputs:
<%= form_for #property do |f| %>
<%= f.collection_check_boxes(:list_ids, List.all, :id, :name) %>
<%= f.submit %>
<% end %>
Whitelisting the params is a bit special since params[:property][:list_ids] will contain an array:
class PropertiesController < ApplicationController
# ...
def create
#property = Property.new(property_params)
# ...
end
# ...
private
def property_params
params.require(:property)
.permit(:foo, :bar, list_ids: [])
end
end

how to add details in two database table in one submit

I have 3 tables: coaches, categories and also a join table categories_coaches, on submit I want to store category_id and coach_id in join table categories_coaches and name, email, university, batch, phone in coach table. how to do so?
now details are storing in coach table but not storing in join table
please help me to solve this problem.
coach.rb
class Coach < ActiveRecord::Base
has_and_belongs_to_many :categories
end
category.rb
class Category < ActiveRecord::Base
belongs_to :coach
end
registrationcontroller.erb
class Coaches::RegistrationsController < Devise::RegistrationsController
def new
#individual=#individual ||= Coach.new
super
end
def create
build_resource sign_up_params
#individual=#individual ||= Coach.new
super
end
private
def sign_up_params
params.require(:coach).permit(:name, :email, :university, :batch, :linkedin_url, :code, :phone,category_ids: []
)
end
end
view page
<%= simple_form_for(#individual, as: :coach, url: registration_path(:coach)) do |f| %>
<%= f.input :name, required: true, %>
<%= f.input :university %>
<%= f.input :batch %>
<%= f.input :email%>
<%= f.input :phone%>
<div class="category-scroll">
<% Category.all.each do |c| %>
<% if c.parent_id != nil %>
<div class="category-left">
<%= check_box_tag "category_ids[]", c.id, false, :id => "category_ids_#{c.id}" %>
<%= c.name %>
</div>
<% else %>
<b><%= c.name %></b>
<% end %>
<% end %>
</div>
<div class="form-group">
<%= f.button :submit, "SUBMIT", class: "apply-continue_form" %
<% end %>
What you've mentioned sounds like a has_and_belongs_to_many relationship to me.
I'll detail what you should do, and the underlying mechanics of the association:
#app/models/coach.rb
class Coach < ActiveRecord::Base
has_and_belongs_to_many :categories
end
#app/models/category.rb
class Category < ActiveRecord::Base
has_and_belongs_to_many :coaches
end
This, as opposed to the has_many :through relationship, does most of the legwork for you. You were correct in setting up your join_table as you did:
The importance of getting this right is that each time you CRUD either your Coach or Category objects, you'll have access to their associated data through the :categories and :coaches methods respectively.
Thus, you'll be able to populate the data like this:
#config/routes.rb
resources :coaches #-> url.com/coaches/new
#app/controllers/coaches_controller.rb
class CoachesController < ApplicationController
def index
#coaches = Coach.all
end
def new
#coach = Coach.new
end
def create
#coach = Coach.new coach_params
end
private
def coach_params
params.require(:coach).permit(:name, :email, :university, :batch, :phone, :categories)
end
end
This will then allow you to make the following view:
#app/views/coaches/new.html.erb
<%= form_for #coach do |f| %>
<%= f.text_field :name %>
<%= f.email_field :email %>
<%= f.text_field :university %>
<%= f.text_field :batch %>
<%= f.text_field :phone %>
<%= f.collection_select :categories, Category.all, :id, :name %>
<%= f.submit %>
<% end %>

New action with form in one_of_many-to-one association

Can't figure out how to render new action. When I'm trying to load new action, I get next error - undefined method 'hotel' for nil:NilClass
My trip, hotelseller and hotel models
class Trip < ActiveRecord::Base
has_many :hotelsellers, :dependent => :destroy
attr_accessible :hotelsellers_attributes, :description
accepts_nested_attributes_for :hotelsellers, :reject_if => lambda { |a| a.blank? }
end
class Hotelseller < ActiveRecord::Base
belongs_to :trip
has_one :hotel
attr_accessible :hotel_attributes,
accepts_nested_attributes_for :hotel, :reject_if => lambda { |a| a.blank? }
end
class Hotel < ActiveRecord::Base
belongs_to :hotelseller
attr_accessible :description
end
My controller trips_controller.rb
def new
hotelseller_first = #trip.hotelsellers.build(five_stars: false)
hotelseller_second = #trip.hotelsellers.build(five_stars: true)
#hotel = #trip.hotelsellers.build.build_hotel
end
My form new.html.erb
<%= simple_form_for(#trip) do |f| %>
<%- f.description %>
<%= f.fields_for :hotelsellers do |builder| %>
<% if builder.object.five_stars %>
First hotel
<%= builder.hidden_field :five_stars, value: true %>
<% else %>
Second hotel
<%= builder.hidden_field :five_stars, value: false %>
<% end %>
<%= builder.descritpion %>
<%= builder.simple_fields_for :hotel do |builder| %>
<%= builder.description %>
<% end %>
<% end %>
<% end %>
I should change builder.simple_fields_for :hotel to builder.simple_fields_for :hotel_attributes

Nested attributes form for model which belongs_to few models

I have few models - User, Teacher and TeacherLeader.
class User < ActiveRecord::Base
attr_accessible ...,
:teacher_attributes
has_one :teacher
has_one :teacher_leader
accepts_nested_attributes_for :teacher_leader
end
class Teacher < ActiveRecord::Base
belongs_to :user
has_one :teacher_leader
end
class TeacherLeader < ActiveRecord::Base
belongs_to :user
belongs_to :teacher
end
I would like to fill TeacherLeader via nested attributes. So, i do such things in controller:
class TeacherLeadersController < ApplicationController
...
def new
#user = User.new
#teacher_leader = #user.build_teacher_leader
#teachers_collection = Teacher.all.collect do |t|
[ "#{t.teacher_last_name} #{t.teacher_first_name} #{t.teacher_middle_name}", t.id ]
end
#choosen_teacher = #teachers_collection.first.last unless #teachers_collection.empty?
end
end
And also have such view (new.html.erb):
<%= form_for #user, :url => teacher_leaders_url, :html => {:class => "form-horizontal"} do |f| %>
<%= field_set_tag do %>
<% f.fields_for :teacher_leader do |tl| %>
<div class="control-group">
<%= tl.label :teacher_id, "Teacher names", :class => "control-label" %>
<div class="controls">
<%= select_tag( :teacher_id,
options_for_select( #teachers_collection, #choosen_teacher )) %>
</div>
</div>
<% end %>
<% end %>
...
<%= f.submit "Create", :class => "btn btn-large btn-success" %>
<% end %>
Problem is that select form here does NOT appear. Why? Do i do something wrong?
<%= f.fields_for :teacher_leader do |tl| %>

Resources