I am trying to build a simple_nested_form in my Ruby on Rails app. When I submit my form I am getting some unknown error because it is just redirecting back to the form to input again. Here is the output in the rails server console for when I submit the form. It looks like there is some random "0" => thrown in there.
Parameters: {"machine"=>{"name"=>"2134", "ip_adress"=>"2", "machine_employees_attributes"=>{"0"=>{"machine_id"=>"1", "employee_id"=>"2"}}}, "commit"=>"Create Machine"}
I have a machine model which has_many :machine_employees
and a machineemployee model which belongs_to :machine
Do you have any idea why this 0 => could be appearing because I think it is what is giving me the issues.
Here is the code for my models.
Machine
class Machine < ActiveRecord::Base
# Relationships
has_many :machine_employees
has_many :employees, :through => :machine_employees
accepts_nested_attributes_for :machine_employees, :reject_if => lambda{ |me| me[:employee_id].blank? }
attr_accessible :ip_adress, :name, :machine_employees_attributes
# Validations
validates_presence_of :name, :ip_adress
end
MachineEmployee
class MachineEmployee < ActiveRecord::Base
before_validation :set_default
# Relationships
belongs_to :machine
belongs_to :employee
attr_accessible :employee_id, :machine_id, :end_date, :start_date
# Validations
validates_presence_of :employee_id, :machine_id, :start_date
private
# Callback Methods
def set_default
self.start_date = Date.today
self.end_date = nil
end
end
New Machine Form
<div class="row-fluid">
<div class="span3">
<h1>Add a Machine</h1>
<br />
<%= simple_nested_form_for #machine do |f| %>
<%= render "machine_fields", :f => f %>
<%= f.button :submit %>
<%= link_to 'Back', machines_path %>
</div>
<div class="span4">
<h4>Assign an Employee to This Machine</h4>
<%= f.simple_fields_for :machine_employees do |me_form| %>
<!-- render nested machine_employee fields-->
<%= render "machine_employee_fields", :f => me_form %>
<% end %>
</div>
<% end %>
</div>
Machine Employee Fields Partial
<%= f.input :machine_id, :as => :hidden, :input_html => { :value => #machine.id } %>
<%= f.input :employee_id, collection: #employees, :id => :name, :prompt => "Select ..." %>
The 0 is thrown in there because the machine model has_many machine_employees. When you use nested forms, it passes a pseudo-array for has_many relations. So, if you tried to submit 2 machine employees, your hash would look like this:
Parameters: {"machine"=>{"name"=>"2134", "ip_adress"=>"2", "machine_employees_attributes"=>{
"0"=>{"machine_id"=>"1", "employee_id"=>"2"},
"1"=>{"machine_id"=>"1", "employee_id"=>"3"}
}
}, "commit"=>"Create Machine"}
This way you can access the machine_employees passed from the form by doing params[:machine][:machine_employees_attributes][0] or params[:machine][:machine_employees_attributes][1]. Note that if this was a has_one relationship, then the machine_employees_attributes key would be changed to machine_employee_attributes and there would be no numerical index.
I suspect the problem is that your machine model must accept_nested_attributes_for :machine_employees and must also have attr_accessible :machine_employees_attributes.
Related
This is a new error to me, and struggling to resolve it. It also states: Roaster(#70130698993440) expected, got "1" which is an instance of String(#70130675908140)
It's highlighting my create method in my Roasts Controller:
def create
#roast = Roast.new(roast_params)
The scenario is that I'm trying to create a triple nested form. for three models Roasts Countries and Regions where roasts has many countries and countries has many regions.
I'm assuming there is something wrong with the roast params, but I can see what it is. I have added the associations there for the nested models
def roast_params
params.require(:roast).permit(:roaster, :name, :bestfor, :beans, :roast, :tastingnotes, :notes, :slug, :avatar, :countries_attributes => [:country_name, :regions_attributes => [:region_name]])
end
my form
<div class="form-group">
<%= form.fields_for :countries do |countries_form| %>
<%= countries_form.label :country %>
<%= countries_form.text_field :name, class: "form-control" %>
</div>
<div class="form-group">
<%= form.fields_for :regions do |regions_form| %>
<%= regions_form.label :region %>
<%= regions_form.text_field :region_name, class: "form-control" %>
<% end %>
<% end %>
</div>
Roast Controller
...
def new
#roast = Roast.new
#roast.countries.build.regions.build
end
...
roast model
class Roast < ApplicationRecord
has_many :tastings
has_many :countries
has_many :notes, through: :tastings
has_many :comments, as: :commentable
belongs_to :roaster
accepts_nested_attributes_for :countries
country model
class Country < ApplicationRecord
has_many :regions, inverse_of: :country
accepts_nested_attributes_for :regions
belongs_to :roasts
region model
class Region < ApplicationRecord
belongs_to :country
I've nested the regions params in the country params, is that correct? I also saw on SO other issues with suggestions for setting config.cache_classes to true in development.rb but that didn't help here.
Update
So looking at this further, I believe it's not related to the nested forms, but rather a collection_select I'm using.
<%= form.label :roaster, class: 'control-label' %>
<%= form.collection_select(:roaster, Roaster.order(:roaster_name).all, :id, :roaster_name, prompt: true, class: "form-control") %>
So this select is pulling the roaster_name from a model called Roaster.
My params now look like the below:
params.require(:roast).permit(:roaster_name, :roaster, :name, :bestfor, :beans, :roast, :tastingnotes, :notes, :slug, :avatar, :countries_attributes => [:country_id, :country_name, :regions_attributes => [:region_id, :region_name]])
And looking at the console when submitting the form, it seems that just the :id of Roaster is getting passed, rather than the value of :roaster_name.
{"utf8"=>"✓",
"authenticity_token"=>"EG+zty85IiVsgipm1pjSAEZ7M66ELWefLq8Znux+cf89sSnVXxielRr1IaSS9+cJvdQD8g1D4+v2KqtKEwh6gw==",
"roast"=>{"roaster"=>"1", "name"=>"Espress", "countries_attributes"=>{"0"=>{"country_name"=>"UK"}}, "regions"=>{"region_name"=>"Highlands"}, "bestfor"=>"", "roast"=>"", "tastingnotes"=>""},
"commit"=>"Create Roast"}
Can't work this out
ActiveRecord::AssociationTypeMismatch is raised when an association-setter (Roast#roaster= in this case) is called with a value that is not an instance of the expected class. Roaster was expected, got String.
The issue seems to be with passing roaster in as a param, which is "1" (String) in your example. I'm guessing this is actually an ID of a Roaster, the form code in the question does not show it.
Perhaps you meant to permit and pass a roaster_id param?
def roast_params
params.require(:roast).permit(:roaster_id, # ...
end
I have a few models in my project : Request, Work, Car and Employee. Work is an intermediate model between Request and Car/Employee.
Here are the associations:
Request
has_many :works, dependent: :destroy
def performers
works.map {|x| x.performer}
end
Work
belongs_to :request
belongs_to :performer, polymorphic: true
Car
has_many :works, as: :performer
has_many :requests, through: :works, as: :performer
Employee
has_many :works, as: :performer
has_many :requests, through: :works, as: :performer
View used to create works:
<%= form_for([#request, #work]) do |f| %>
<%= (f.collection_select :performer_id, Employee.all, :id, :name) if #request.type == "StaffRequest" %>
<%= (f.collection_select :performer_id, Car.all, :id, :select_info) if #request.type == "CarRequest" %>
<%= f.submit 'OK' %>
<% end %>
Work controller
def new
#work = #request.works.new
end
def create
#work = #request.works.new(work_params)
end
def work_params
params.require(:work).permit(:performer_id, :request_id)
end
The problem is that my performer_type column is always empty, it does not save the class name. What can be the problem? Any ideas?
It's empty because you did't pass it, you should add a hidden field for you form:
<%= form_for([#request, #work]) do |f| %>
<% if #request.type == "StaffRequest" %>
<%= (f.hidden_field :performer_type, value: "Employee") %>
<%= (f.collection_select :performer_id, Employee.all, :id, :name) %>
<% elsif #request.type == "CarRequest" %>
<%= (f.hidden_field :performer_type, value: "Car") %>
<%= (f.collection_select :performer_id, Car.all, :id, :select_info) %>
<% end %>
<%= f.submit 'OK' %>
<% end %>
Beside :performer_id, you have to pass the :performer_type also, one way to do this is via the form select_tag :
def create
#work = #request.works.new(work_params)
end
def work_params
# use :performer if you use :performer as in the select form field
params.require(:work).permit(:performer, :request_id)
# OR
# use :performer_id & :performer_type if you also use the hidden field
params.require(:work).permit(:performer_id, :performer_type, :request_id)
end
There is a good example (for Rails 4.2) of using a single select form field for polymorphic so you can write like:
<%= f.grouped_collection_select :global_performer, [ Car, Employee ], :all, :model_name, :to_global_id, :name %>
How to create grouped select box in Rails for polymorphic association using Global ID?
I have a form, that is saving the main attribute, but not its nested attributes. I have dug into a lot of documents, and seem to be doing things correctly, but still get an error that my nested attributes "must exist".
My interview attributes are saving correctly to the database, but my logs show "Unpermitted parameters: student, parents"
My code is modified for brevity, but I will still try to be thorough enough to get some direction as to what might be going wrong ...
Models (which I include accepts_nested_attributes for :student, :parents)
:student is singular since it has a has_one relationship
:parents is plural since it has a has_many relationship
class Interview < ApplicationRecord
has_one :student
has_many :parents
accepts_nested_attributes_for :student, :parents
end
class Student < ApplicationRecord
belongs_to :interview
end
class Parent < ApplicationRecord
belongs_to :interview
end
Controller
class InterviewsController < ApplicationController
def index
#interviews = Interview.all
end
def show
#interview = Interview.find(params[:id])
end
def new
#interview = Interview.new
#interview.build_student
2.times { #interview.parents.build }
end
def create
#interview = Interview.new(interview_params)
if #interview.save
redirect_to #interview
else
render :action => 'new'
end
end
private
def interview_params
params.require(:interview).permit(:date_today, :date_contact, :purpose_of_call, :problems_start_date, :cause, :violence, :running_away, :police_contact, :suicide, :self_harm, :other_info, :testing, :hospitalization, :medications, :school_problems, :teacher_relationships, :parent_goals, :notes,
student_attributes: [:id, :name, :age, :height, :weight, :dob, :interview_id],
parents_attributes: [:id, :name, :relationship, :parentage, :address, :phone_home, :phone_work, :phone_mobile, :phone_mobile, :email, :employer, :notes, :interview_id] )
end
end
Form (important bits)
<%= form_for(#interview) do |f| %>
<p class="inline">
<%= f.label :date_today, 'Today\'s Date' %>
<%= f.date_select(:date_today, :order => [:month, :day, :year], :start_year => 2000, :end_year => Date.today.year) %>
</p>
<p class="inline float_right">
<%= f.label :date_contact, 'Initial Contact' %>
<%= f.date_select(:date_contact, :order => [:month, :day, :year], :start_year => 2000, :end_year => Date.today.year) %>
</p>
<%= f.fields_for :student do |student_form| %>
<p><%= student_form.text_field :name, placeholder: 'Name' %></p>
<p class="inline">
<%= student_form.label :age %>
<%= student_form.text_field :age %>
</p>
<p class="inline">
<%= student_form.label :height %>
<%= student_form.text_field :height %>
</p>
<p class="inline">
<%= student_form.label :weight %>
<%= student_form.text_field :weight %>
</p>
///// removed for brevity /////
<% end %>
<%= f.fields_for :parents do |parent_form| %>
<%= render 'parents', :f => parent_form %>
<% end %>
Parent Partial
<p>
<%= f.label :name, 'Name' %>
<%= f.text_field :name %>
</p>
//// and more of the same /////
Routes
resources :interviews do
resources :student
resources :parents
end
The website form (at it's current state) can be found here: www.compassconsultingwi.com/interviews/new
and the link to the github can be found here: https://github.com/plantoteachme/compassconsultingwi
Params returns this ..
Parameters: {"utf8"=>"✓", "authenticity_token"=>"nU4WM2RO5GJd36eaSLHMxhRQCOnY8EPjDhUdFBHlYGkcw6H7/Oc5y7kFx0HMU9nm5cc47ZZZBDW6oQ2QNF5yhA==", "interview"=>{"date_today(2i)"=>"11", "date_today(3i)"=>"16", "date_today(1i)"=>"2016", "date_contact(2i)"=>"10", "date_contact(3i)"=>"23", "date_contact(1i)"=>"2016", "student"=>{"name"=>"John", "age"=>"12", "height"=>"5 feet", "weight"=>"123 lbs", "dob(2i)"=>"3", "dob(3i)"=>"13", "dob(1i)"=>"2004", "strengths"=>"Great with his siblings", "weaknesses"=>"Lazy", "likes"=>"Food", "dislikes"=>"Chores", "medical_prolems"=>"ADD", "religous_training"=>"Catholic", "ethnic_issues"=>"none", "grade_level"=>"6"}, "parents"=>{"name"=>"Jamie", "relationship"=>"Mom", "parentage"=>"Strict", "address"=>"Miwaukee Wi", "phone_home"=>"555-1000", "phone_work"=>"555-1001", "phone_mobile"=>"555-1002", "email"=>"jj#jj.com", "employer"=>"Googleer", "notes"=>"PhD in Computer Science"}, "purpose_of_call"=>"Depression causing suicidal tendencies", "problems_start_date"=>"When we moved from Nigeria last year", "cause"=>"Relocating", "violence"=>"none", "running_away"=>"no", "police_contact"=>"no", "suicide"=>"Hasn't acted on it, but talks about it", "self_harm"=>"Minor bruising from \"sports\"", "other_info"=>"", "testing"=>"Yes, for ADD", "hospitalization"=>"no", "medications"=>"Regeline", "school_problems"=>"Getting bullied", "teacher_relationships"=>"Strained", "parent_goals"=>"Improve self awareness", "notes"=>"Our family was in Nigeria for mission work"}, "button"=>""}
Unpermitted parameters: student, parents
Try to use cocoon gem.
You can build a model object using link_to_add_association method of cocoon gem.
Also, you can remove object using link_to_remove_association
A fully working example here: https://github.com/nathanvda/cocoon/wiki/ERB-examples
I am trying to create a web application to practise my Ruby on Rails skill. I have a few entities in my database manufacturers, models, tints, prices
manufacturers {id, name} - stores the make of the car
models {id, manufacturer_id, name} - stores the models of the car
tints {id, manufacturer_id, model_id, front, sides, rear} - stores the length of tint required
prices {id, description, price } - stores the price of the item
I created a page to generate a quotation for window tinting. The page includes drop-down menus to let user to select manufacturer, model, type of film(front), type of film(side+rear)
Below is the code for the form
<%= form_tag('/quotation/tints/generate') do %>
<%= label :manufacturer_id, 'Manufacturer' %>
<div class="field">
<%= collection_select(:tint, :manufacturer_id, Manufacturer.order(:name), :id, :name, {:prompt => "Select Manufacturer"}) %>
</div>
Model:
<div class="field">
<%= grouped_collection_select(:tint, :model_id, Manufacturer.order(:name), :models, :name, :id, :name, {:prompt => "Select Model"}) %>
</div>
<%= label :price_front, 'Front Tint' %>
<div class="field">
<%= collection_select(:price, :price_front, Price.order(:name), :id, :name, {:prompt => "Select Front Tint"}) %>
</div>
<%= label :price_rear, 'Size and Back Tint' %>
<div class="field">
<%= collection_select(:price, :price_rear, Price.order(:name), :id, :name, {:prompt => "Select Side & Rear Tint"}) %>
</div>
<div class="form-group">
<%= submit_tag 'Submit' %>
</div>
<% end %>
When the form is submitted, it should be redirected to /quotation/tints/generate and display the value from the dropdown menu. However, I received an error, saying that Couldn't find Manufacturer with 'id'=. The code that caused the error is shown below
def generate
#manufacturers = Manufacturer.find(params[:manufacturer_id])
end
Here is the parameter from the debug log
{"utf8"=>"✓",
"authenticity_token"=>"Pl2bXiRT0AoF4i0h1RCHDbuvaKJNZOkV5ULQHKxDQgZzBWWLJ2mH7ddb9akwgxbloxBIHoVaT3pcwoIGcRufpg==",
"tint"=>{"manufacturer_id"=>"7", "model_id"=>"6"},
"price"=>{"price_front"=>"1", "price_rear"=>"2"},
"commit"=>"Submit"}
I can see that the id of each drop down value are shown up correctly in the parameter list. However, I coundn't able to print the value at /quotation/tints/generate nor get the name of the manufacturer or model.
Here is routes.rb:
get '/quotation/tints' => 'tints#quotation', :as => 'tints_quotation'
post '/quotation/tints/generate' => 'tints#generate', :as => 'generate_tints_quotation'
Tint.rb:
class Tint < ApplicationRecord
has_many :manufacturers
has_many :models
belongs_to :manufacturer
belongs_to :model
validates_uniqueness_of :model_id, :scope => [:manufacturer_id]
end
Model.rb:
class Model < ApplicationRecord
belongs_to :manufacturer, :dependent => :destroy
validates :name, :presence => true
validates_uniqueness_of :name, :scope => [:manufacturer_id]
before_save :capitalize_content
end
Manufacruter.rb:
class Manufacturer < ApplicationRecord
has_many :models, :dependent => :destroy
validates :name, :presence => true, uniqueness: { case_sensitive: false }
before_save :capitalize_content
end
tints.controller.rb:
def quotation
render 'quotation'
end
def generate
#manufacturers = Manufacturer.find(params[:manufacturer_id])
end
generate.html.erb:
<%= #manufacturers.name %>
I'm trying to print the manufacturer selected
I have tried multiple ways to define it, but I am still facing the same error. Any help is greatly appreciated.
In your params, manufacturer_id is a nested value of tint, as opposed to being a direct key of the params hash. Try the following:
def generate
#manufacturers = Manufacturer.find(params[:tint][:manufacturer_id])
end
I looked for two days on the web but I am still blocked to update a child object of a parent object.
My parent:
class Pass < ActiveRecord::Base
has_many :fields
attr_accessor :fields_attributes
accepts_nested_attributes_for :fields, :allow_destroy => true, :update_only => true
My child:
class Field < ActiveRecord::Base
belongs_to :pass
My form view:
<%= f.fields_for :fields do |field|%>
<div class="control-group">
<%= field.label :id, :class => 'control-label' %>
<%= field.label :value, :class => 'control-label' %>
<div class="controls">
<%= field.text_field :value, :class => 'text_field' %>
</div>
</div>
<% end %>
I also define permitted parameters thanks to:
def pass_params params.require(:pass).permit(:pass,
:description,
:organization_name,
:logo_upload,
:icon_upload,
:strip_upload,
fields_attributes: [:id,:value])
#params.require(:pass).permit!
end
I have no problem to create a pass with 5 fields in my passes_controller
def new
#pass = Pass.new
5.times {#pass.fields.build}
##fields = #pass.fields
end
My problem happens is that child fields of my pass are not updated after an edit of the pass. I always get initial values (at the creation of the pass) of fields.
I tried to update using different ways without success
if #pass.update_attributes(pass_params)
if #pass.update_attributes[params[:pass][:fields_attributes]]
if #pass.update_attributes(params[:fields_attributes])
When I update my pass, the pass_params looks like this:
{"description"=>"Test22gg", "organization_name"=>"Toto", "fields_attributes"=>{"0"=>{"id"=>"30", "value"=>"testf"}, "1"=>{"id"=>"29", "value"=>"test"}, "2"=>{"id"=>"28", "value"=>"test"}, "3"=>{"id"=>"27", "value"=>"test"}, "4"=>{"id"=>"26", "value"=>"test"}}}
I don't see which requirement or thing I forget to update these fields!