Rails 4 nested forms and strong parameters - ruby-on-rails

I cannot get accepts_nested_attributes_for to work with strong parameters in Rails 4. This is the error
Processing by CityaddressesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Cx9nunLAsHkvo/Z8vKnWFnrub1LpmUgVNdePcQ9VDSQ=", "cityaddress"=>{"st_unit"=>"1", "st_num"=>"1", "st_prefix"=>"E", "name"=>"1", "st_type"=>"ST", "st_postalcode"=>"", "description"=>"", "cityaccount"=>{"name"=>"1", "description"=>"1"}}, "commit"=>"Create Cityaddress"}
[1m[36mUser Load (0.0ms)[0m [1mSELECT `users`.* FROM `users` WHERE `users`.`id` = 3 LIMIT 1[0m
Unpermitted parameters: cityaccount
This is the model:
class Cityaddress < ActiveRecord::Base
has_many :cityaccounts
has_many :license_plates
accepts_nested_attributes_for :cityaccounts, allow_destroy: true
def street_address
return "#{st_unit} #{st_num} #{name} #{st_type} #{st_prefix}"
end
def address
return "#{st_unit}#{st_prefix} #{name} #{st_type} #{st_num} "
end
end
This is the controller:
# GET /cityaddresses/new
def new
#cityaddress = Cityaddress.new
#streets = Street.where("active=1").order("display_order")
#cityaddress_accounts = #cityaddress.cityaccounts.build
end
def cityaddress_params
params.require(:cityaddress).permit(:st_unit, :st_num, :st_prefix, :name, :st_type, :st_postalcode, :description, cityaccounts_attributes: [:name, :description, :id])
end
This is the view:
<%= f.fields_for #cityaddress_accounts do |ff| %>
<div class="field">
<%= ff.label :name %>
<%= ff.text_field :name %><br>
</div>
<div class="field">
<%= ff.label :description %>
<%= ff.text_field :description %><br>
</div>
<% end %>
I'm thinking it's something to do with the strong parameter syntax?
Cheers.

I think you have to change the view a bit.
Try changing this
<%= f.fields_for #cityaddress_accounts do |ff| %>
to
<%= f.fields_for :cityaccounts do |ff| %>

Seems all correct, but try in Controller do this:
def new
#cityaddress = Cityaddress.new
#streets = Street.where("active=1").order("display_order")
#cityaddress.cityaccounts.build
end

Related

Complex Rails form with Nested Attributes (Rails 5)

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

processing by create instead of update

when I attempt to run my code, I got the error above.
I try to add specific attributes to my products, but every time I try to add them to my product, a new one is created instead of just edit the old.
Here is the result :
Started POST "/my_products" for 127.0.0.1 at 2016-01-03 16:33:46 +0100
[localhost] [127.0.0.1] [a6533ae8-475f-4e] Processing by MyProductsController#create as JS
[localhost] [127.0.0.1] [a6533ae8-475f-4e] Parameters: {"utf8"=>"✓", "my_product"=>{"size_name"=>"Gros oeuf", "size_img"=>"big-egg.png", "size_price"=>"40"}, "commit"=>"Choisir"}
[localhost] [127.0.0.1] [a6533ae8-475f-4e] (0.2ms) BEGIN
[localhost] [127.0.0.1] [a6533ae8-475f-4e] SQL (0.3ms) INSERT INTO `my_products` (`size_name`, `size_price`, `size_img`, `created_at`, `updated_at`) VALUES ('Gros oeuf', '40', 'big-egg.png', '2016-01-03 15:33:46', '2016-01-03 15:33:46')
[localhost] [127.0.0.1] [a6533ae8-475f-4e] (2.0ms) COMMIT
My application_controller.rb :
def current_product
if !session[:my_product_id].nil?
MyProduct.find(session[:my_product_id])
else
MyProduct.new
end
end
My Products_controller :
def base
#myproduct = current_product
#size = Size.all
#chocolate = MyProductItem.where(item_category_id: 1)
end
def create
#myproduct = current_product
if #myproduct.update(my_product_params)
redirect_to(:back)
else
render 'new'
end
end
My base.html.erb :
<% #size.each do |size| %>
<div class="Box" >
<p><%= size.name %></p>
<p><%= image_tag size.image, style: 'width:7em;height:auto;' %></p>
<p><%= number_to_currency size.price %></p>
<p><%= size.description.try(:html_safe) %></p>
<%= form_for #myproduct, remote: true do |f| %>
<%= f.hidden_field :size_name, value: size.name %>
<%= f.hidden_field :size_img, value: size.image %>
<%= f.hidden_field :size_price, value: size.price %>
<%= f.submit "Choisir", class: "addtocart", :id => "#orders" %>
<% end %>
</div>
<% end %>
My models :
class MyProduct < ActiveRecord::Base
attr_accessible :name, :slug, :price, :image, :my_product_item_id, :user_id, :size_name, :size_img, :size_price
has_many :elements, dependent: :destroy
has_one :size, dependent: :destroy
belongs_to :user
belongs_to :order
class Size < ActiveRecord::Base
attr_accessible :name, :price, :weight, :image, :description, :object_size
belongs_to :my_product
end
Any idea ?
Add field with proper :my_product_id value into the form:
<%= hidden_field_tag(:my_product_id, #my_product.id) if #my_product %>
If you invoke base action with GET request without parameters new object will be created, for update you must pass to this action parameter my_product_id=value (value is an id of updated product).

Wicked Gem, associated models param is missing

I have a Boat model and Location Model. Boat has_one :location, Location belongs_to :boat. I used wicked gem to update the models. But I am having an issue in boat_steps_controller's #update action.
Here is my boat_steps_controller,
class BoatStepsController < ApplicationController
include Wicked::Wizard
before_action :logged_in_user
steps :model, :pricing, :description, :picture, :overview, :features, :location
def show
#boat = current_user.boats.find(params[:boat_id])
case step
when :location
#location = #boat.build_location
when :picture
#picture = #boat.pictures.new
#pictures = #boat.pictures.all
end
render_wizard
end
def update
#boat = current_user.boats.find(params[:boat_id])
#boat.update(boat_params)
case step
when :picture
#picture.update(picture_params)
when :location
#location.update(location_params)
end
render_wizard #boat
end
private
def boat_params
params.require(:boat).permit(:brand, :year, :model, .....)
end
def picture_params
params.require(:picture).permit(:name, :boat_id, :image)
end
def location_params
params.require(:location).permit(:address, :longitude, :latitude, :formatted_address, :location_type)
end
end
The problem here is that, in #update action, I update boat_params in every step. But in Location, there is no boat_params to update as it is a associated model. So I have to find a way either get the boat id from the form or put if statement.
Here is the location.html.erb (form for wicked gem)
<%= form_for [#boat, #location], url: wizard_path, method: :put do |f| %>
<div class="field">
<%= f.label :address %><br>
<%= f.text_field :address,:id => "geocomplete", :value => "Ataköy Marina, 34140 Bakırköy/İstanbul, Türkiye" %>
</div>
<div class="field">
<%= f.label :longitude %><br>
<%= f.text_field :longitude, :name => "lng", :readonly => "readonly" %>
</div>
<div class="field">
<%= f.label :latitude %><br>
<%= f.text_field :latitude, :name => "lat", :readonly => "readonly" %>
</div>
<div class="field">
<%= f.label :formatted_address %><br>
<%= f.text_field :formatted_address, :name => "formatted_address", :readonly => "readonly" %>
</div>
<div class="actions">
<%= f.submit "Finish" ,class: "btn btn-primary" %>
</div>
<% end %>
It should normally send boat id as I use [#boat, #location], the url becomes, http://localhost:3000/boats/241/boat_steps/location. But when I post this, I get an error of;
Started PUT "/boats/241/boat_steps/location" for ::1 at 2015-05-12 10:00:21 +0300
Processing by BoatStepsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"jJOEBSCe9WdcuMKiHeVnh9zFEYuu15L5tzIkNFo9cED7ToG0MHq8jqeGstq5krdRGnrNXayNTQI0fajjHsNGgQ==", "location"=>{"address"=>"Ataköy Marina, 34140, Bakırköy, İstanbul, Türkiye"}, "lng"=>"28.87443200000007", "lat"=>"40.971388", "formatted_address"=>"Ataköy Marina, 34140 Bakırköy/İstanbul, Türkiye", "commit"=>"Finish", "boat_id"=>"241", "id"=>"location"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
Boat Load (0.2ms) SELECT "boats".* FROM "boats" WHERE "boats"."user_id" = ? AND "boats"."id" = ? LIMIT 1 [["user_id", 1], ["id", 241]]
Completed 400 Bad Request in 51ms
ActionController::ParameterMissing (param is missing or the value is empty: boat):
app/controllers/boat_steps_controller.rb:50:in `boat_params'
app/controllers/boat_steps_controller.rb:25:in `update'
And when I erase #boat.update(boat_params) from #update action (which is wrong) but then I receive an error,
NoMethodError (undefined method `update' for nil:NilClass):
app/controllers/boat_steps_controller.rb:32:in `update'
I just put an easy else condition as;
def update
#boat = current_user.boats.find(params[:boat_id])
case step
when :picture
#picture.update(picture_params)
when :location
#location = #boat.build_location
#location.update_attributes(address: params[:location][:address], longitude: params[:lng], latitude: params[:lat])
else
#boat.update(boat_params)
end
render_wizard #boat
end

Update two records from different tables with nested form

My form is updating the tester record (which is an end user). I am also trying to update many applied_program records which belong to the tester.
I am sending the parameters to the controller but cannot get it to update the the applied_program records. It is trying to use all the parameters instead of just the applied program params to update it.
Form:
<%= form_for #tester, url: { controller: :admins, action: :update_tester } do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name, class: "input-lg" %>
...
<%= f.fields_for :applied_programs do |fml| %>
<%= fml.label :approved, "Approved: " %><%= fml.check_box :approved %>
<%= fml.hidden_field :id %>
<% end %>
<%= f.submit "Save Changes", class: "btn btn-lg btn-primary" %>
<% end %>
Tester Model:
has_many :applied_programs, :dependent => :destroy
accepts_nested_attributes_for :applied_programs
AppliedProgram Model:
belongs_to :tester
Controller:
def update_tester
#applied_programs = AppliedProgram.where(tester_id: #tester.id)
#tester.update_attributes(tester_params)
#applied_programs.each do |p|
p.update_attributes(tester_params)
end
end
def tester_params
params.require(:tester).permit(:name, :email, :phone_number, :address1,
:city, :zip_code, :country, :password, :password_confirmation,
:active, :approved, applied_programs_attributes: [ :approved, :id ])
end
The log:
Processing by AdminsController#update_tester as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"x", "tester"=>{"name"=>"Dave", "email"=>"nope#gmail.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "applied_programs_attributes"=>{"0"=>{"approved"=>"0", "id"=>"9"}, "1"=>{"approved"=>"1", "id"=>"745"}}}, "commit"=>"Save Changes", "id"=>"16"}
Tester Load (0.1ms) SELECT `testers`.* FROM `testers` WHERE `testers`.`id` = 16 LIMIT 1
Tester Load (1.1ms) SELECT `testers`.* FROM `testers` WHERE `testers`.`remember_token` = 'x' LIMIT 1
(6.8ms) BEGIN
AppliedProgram Load (2.6ms) SELECT `applied_programs`.* FROM `applied_programs` WHERE `applied_programs`.`tester_id` = 16 AND `applied_programs`.`id` IN (9, 745)
Tester Exists (0.8ms) SELECT 1 AS one FROM `testers` WHERE (`testers`.`email` = 'nope#gmail.com' AND `testers`.`id` != 16) LIMIT 1
(0.1ms) COMMIT
AppliedProgram Load (0.1ms) SELECT `applied_programs`.* FROM `applied_programs` WHERE `applied_programs`.`tester_id` = 16
(0.1ms) BEGIN
(12.4ms) ROLLBACK
Completed 500 Internal Server Error in 95ms
ActiveRecord::UnknownAttributeError (unknown attribute: name)
You problem is the loop over the applied_programs you need to do something like:
def update_tester
#applied_programs = AppliedProgram.where(tester_id: #tester.id)
#tester.update_attributes(tester_params)
end
def tester_params
params.require(:tester).permit(:name, :email, :phone_number, :address1,
:city, :zip_code, :country, :password, :password_confirmation,
:active, :approved, applied_programs_attributes: [ :approved, :id ])
end

Rails not updating attribute

Pretty standard update in my opinion, but upon submitting the put request, the attribute is not updated. Here is my relevant model:
class Vendor < ActiveRecord::Base
geocoded_by :address
after_validation :geocode,
:if => lambda{ |obj| obj.address_changed? }
end
My controller methods:
def edit
#vendor = Vendor.find(params[:id])
end
def update
#vendor = Vendor.find(params[:id])
if #vendor.update_attributes(vendor_params)
redirect_to vendors_mgmt_path
else
render 'edit'
end
end
def vendor_params
params.permit(:id, :name, :address, :image, :latitude, :longituded )
end
I see this in the server log after trying to update:
Started PUT "/vendors/1" for 127.0.0.1 at 2013-10-20 20:44:54 -0700
Processing by VendorsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"fTbZVEfckQz4xQzY5xSMQCArrGZqymNsVeyic/PXKcE=", "vendor"=>{"name"=>"Store", "address"=>"1221 E. Main St."}, "commit"=>"Save changes", "id"=>"1"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
Vendor Load (0.2ms) SELECT "vendors".* FROM "vendors" WHERE "vendors"."id" = ? LIMIT 1 [["id", "1"]]
Unpermitted parameters: utf8, _method, authenticity_token, vendor, commit
(0.1ms) begin transaction
(0.1ms) commit transaction
Redirected to http://localhost:3000/vendors/mgmt
Completed 302 Found in 10ms (ActiveRecord: 0.6ms)
This confuses me, because the Vendor form looks like so, and has no authenticity token etc.
<h1>Update <%= "#{#vendor.name}" %></h1>
<%= form_for(#vendor) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :address %>
<%= f.text_field :address %>
<%= f.label :Logo %>
<%= f.file_field :image %>
<%= f.submit "Save changes", class: "btn btn-success" %>
<% end %>
Anyone see any glaring errors? Any help is much appreciated. Thanks in advance!
Rails by default includes certain hidden fields in all forms, such as the authenticity_token, which is present to stop CSRF. (More info here) I would recommend changing the line:
params.permit(:id, :name, :address, :image, :latitude, :longituded )
to:
params.require(:vendor).permit(:id, :name, :address, :image, :latitude, :longituded)
Changing this line in your controller should permit the other parameters that are submitted by the form, not just the ones in the vendor param.
Also, you misspelled "longitude", I'm not sure if that's causing any additional trouble or if it's just a typo in your question instead.

Resources