Nested form with values from model - ruby-on-rails

I have a workout model:
class Workout < ActiveRecord::Base
attr_accessible :time
belongs_to :user
has_and_belongs_to_many :trainers
accepts_nested_attributes_for :trainers
end
And a trainer model:
class Trainer < ActiveRecord::Base
attr_accessible :name
validates_uniqueness_of :name
has_and_belongs_to_many :workouts
end
I need to have a nester trainer form, which allows to pull values from database.
Now I have this inside a new workout form:
<%= f.fields_for :trainers do |builder| %>
<%= builder.select :trainer, options_for_select(Trainer.all.collect{ |u| [u.name, u.id] }) %>
<br>
<% end %>
I get "undefined method `trainer' for #"
What am I doing wrong?

I forgot to add attr_accessible :trainers_attributes to Workout controller

Related

Rails Form: field_for polymorphic association with belongs_to another

I have a form on a model called "Patient", which has_one "Role" via polymorphic association. And the "Role" has_one "User". And I need to modify the "User" field "first_name" via a form...
class Patient < ApplicationRecord
has_one :role, :as => :roleable, dependent: :destroy
accepts_nested_attributes_for :role
end
class Role < ApplicationRecord
belongs_to :user
accepts_nested_attributes_for :user
belongs_to :roleable, polymorphic: true, optional: true
end
class User < ApplicationRecord
has_many :roles
end
class PatientsController < ApplicationController
def show
#patient = Patient.find(params[:id])
# This works just fine, so I know the data is there
puts(#patient.role.user.first_name)
end
end
How do I make a form that includes this field? This is what I have so far that isn't working:
<%= form_for(:patient, url: edit_patient_path(params[:id])) do |f| %>
<%= f.fields_for :role do |r| %>
<%= r.fields_for :user do |u| %>
<%= u.text_field :first_name, value: u.first_name, class: "value", disabled: false %>
<% end %>
<% end %>
<% end %>
But unfortunately this is not working:
undefined method `first_name' for #<ActionView::Helpers::FormBuilder:0x007f82d30c4ad8>
First change your form to <%= form_for(#patient) %> so that it wraps the #patient object.
Use .object to get the object wrapped by the form builder.
<%= u.text_field :first_name, value: u.object.first_name, class: "value", disabled: false %>
But you don't need to explicitly assign the value in the first place and the disabled attribute defaults to false:
<%= u.text_field :first_name, class: "value" %>

Creating an object with a nested form - how to pass params to controller

I'm really struggling with how to make a form create an object, and two sub-objects. My Guide has_one City_obj and has_one Country_obj.
guide.rb
class Guide < ActiveRecord::Base
has_one :city_obj, dependent: :destroy
has_one :country_obj, dependent: :destroy
belongs_to :user
has_many :guide_pics, dependent: :destroy
accepts_nested_attributes_for :city_obj, :country_obj
end
city_obj.rb
class CityObj < ActiveRecord::Base
belongs_to :guide
belongs_to :country_obj
end
country_obj.rb
class CountryObj < ActiveRecord::Base
belongs_to :guides
has_many :city_obj, dependent: :destroy
end
new.html
<%= form_for(#guide) do |f| %>
<%= render 'new_form_part', f: f, field: 'name', label: 'name', type: 'text_field',
<%= f.fields_for :country_obj, #guide.country_obj do |p| %>
<%= f.text_field :name, class: 'form-control' %>
<% end %>
<%= f.fields_for :city_obj, #guide.city_obj do |p| %>
<%= f.text_field :name, class: 'form-control' %>
<% end %>
<% end %>
In my controller create method, I get
params[:guide] = {"name"="whatever is submitted for city"}
That's because the partial that sets :name is being overwritten by the text_fields below. How can I get them to pass params[:guide][:city_obj][:name] and params[:guide][:country_obj][:name]?
UPDATE: There is a typo. I should be using p.text_field, not f.text_field

Has Many Through. How to get the access?

Here is my models:
class Item < ActiveRecord::Base
has_many :price_group_lines
has_many :price_groups, through: :price_group_lines
attr_accessible :item_name, :item_id
validates :item_name, presence: true
def to_label
"#{item_name}"
end
end
class PriceGroup < ActiveRecord::Base
has_many :customers
has_many :price_group_lines
has_many :items, through: :price_group_lines
attr_accessible :price_group_name
validates :price_group_name, presence: true
def to_label
"#{price_group_name}"
end
end
class PriceGroupLine < ActiveRecord::Base
belongs_to :item
belongs_to :price_group
attr_accessible :item_id, :price_group_id, :price, :item, :price_group
validates :price, :item_id, :price_group_id, presence: true
end
View (show.html.erb) for Price Group controller
<h1> PRICE GROUP </h1>
<p> <%= #pg.price_group_name %> </p> <br>
<% #pg.items.each do |i|%>
<%= i.item_name %>
<% end %>
<br>
<%= link_to "PRICE GROUP List", price_groups_path %>
So, I have the access to item_name in show.html.erb, but i don't know how to get the access to "price" attribute in PriceGroupLine model. Something, like
i.items.price not working. Please, help!
Problem is because you have association of price, better said prices.
Your variable i is already item just call price_group_lines on it and you will get association on which you can call each and get each price.
<% #pg.items.each do |i|%>
<%= i.item_name %> # will display item name
<% i.price_group_lines.each do |pgl| %>
<%= pgl.price %> # will display price
<% end %>
<% end %>

Rails Nested Forms Not Updating Nested Model

I am having trouble trying to update nested models in my form. I don't get any errors and but the attributes don't get updated.
I have the following model:
class Trip < ActiveRecord::Base
has_many :segments
accepts_nested_attributes_for :segments, allow_destroy: true
end
class Segment < ActiveRecord::Base
belongs_to :start_location, class_name: 'Location'
belongs_to :end_location, class_name: 'Location'
belongs_to :trip
validates_presence_of :date, :start_location, :end_location
end
class Location < ActiveRecord::Base
has_many :segments
end
And have this code in the _form.html.erb:
<%= form_for #trip do |f| %>
...
<%= f.fields_for :segments do |builder| %>
<%= render 'segment_fields', f: builder %>
<% end %>
...
<% end %>
And this in the partial _segment_fields.html.erb:
<%= f.collection_select :start_location_id, Location.order(:name), :id, :name %> -
<%= f.collection_select :end_location_id, Location.order(:name), :id, :name %> <br>
<%= f.date_field :date %>
In my controller I also permited the assigment of :segments_attributes
def trip_params
params.require(:trip).permit(:name, :start_date, :end_date, :segments_attributes)
end
Does anybody know what I am lacking or doing wrong?
When you are creating a new record you don't need its id to be permitted as it's not been created but when you want to update your record you need to pass id to the permitted attributes, else it will work with create but not when you want to update your record, so you need to do:
def trip_params
params.require(:trip).permit(:id, :name, :start_date, :end_date, segments_attributes: [:id,:start_location_id,:end_location_id, :date])
end

rails: Updating a record nested two join tables deep

I have a problem that's really confusing me.
I have four models, a Workout model, an Exercise model, a workout_exercise join model, and a workout_exercise_set model.
I can add exercises to workouts through the workout_exercises join table. Now I'm trying to add sets to exercises in workouts, which is what the workout_exercises_sets table is for.
Here's an example.
Workout
Exercise 1
Set 1
Set 2
Set 3
Exercise 2
Set 1
Set 2
Set 3
Exercise 3
etc.
In workouts/edit.html.erb I have a form where I can see all the exercises in the workout, and edit the number of sets by using form_for and fields_for, but when I try to update an exercise or the entire workout I get a MassAssignmentSecurity::Error in WorkoutsController#update that says Can't mass-assign protected attributes: workout_exercise_sets. I can't figure out how to get past this. I know I'm editing a workout, but I'm not trying to write to a field called workout_exercise_sets, so I'm really confused here. I really appreciate any guidance. All relevant code is below.
workout/edit.html.erb:
<%= form_for(#workout) do |f| %>
<%= f.label :name %><br />
<%= f.text_field :name %><br />
<%= f.label :description %><br>
<%= f.text_area :description %></br>
<%= f.fields_for :workout_exercises do |s| %>
<%= s.object.exercise.name %></b>
<%= s.fields_for :workout_exercise_sets do |set| %>
<%= set.label :set_number %>:
<%= set.number_field :set_number %>
<%= set.label :reps %>:
<%= set.number_field :repetitions %>
<%= set.label :rest_time %>(seconds):
<%= set.number_field :rest_time %>
<%= set.submit %>
<% end %>
<%= s.hidden_field :_destroy %>
<%= link_to "Remove exercise?", '#', class: "remove_fields" %>
<% end %>
<%= f.submit %>
<% end %>
Here is the workout model:
class Workout < ActiveRecord::Base
attr_accessible :name, :exercises_attributes, :workout_exercises_attributes, :exercise_order, :description
has_many :workout_exercises, dependent: :destroy, :order => "exercise_order DESC"
has_many :exercises, through: :workout_exercises
accepts_nested_attributes_for :exercises
accepts_nested_attributes_for :workout_exercises, allow_destroy: :true
end
Here is the exercise model:
class Exercise < ActiveRecord::Base
attr_accessible :name, :description
has_many :workout_exercises
has_many :workouts, through: :workout_exercises
validates :name, uniqueness: :true, presence: :true
validates :description, uniqueness: :true, presence: :true
end
Here is the workout_exercise model:
class WorkoutExercise < ActiveRecord::Base
attr_accessible :exercise_id, :workout_id
belongs_to :exercise
belongs_to :workout
has_many :workout_exercise_sets, dependent: :destroy
accepts_nested_attributes_for :workout_exercise_sets, allow_destroy: :true
end
and finally, here is the workout_exercise_sets model:
class WorkoutExerciseSet < ActiveRecord::Base
attr_accessible :repetitions, :rest_time, :set_number, :workout_exercise_id
belongs_to :workout_exercise
end
And for good measure, here is a diagram of the DB:
I think in your workout_excercise.rb file, you should add :workout_exercise_sets_attributes to your attr_accessible list.
class WorkoutExercise < ActiveRecord::Base
attr_accessible :exercise_id, :workout_id, :workout_exercise_sets_attributes
belongs_to :exercise
belongs_to :workout
has_many :workout_exercise_sets, dependent: :destroy
accepts_nested_attributes_for :workout_exercise_sets, allow_destroy: :true
end

Resources