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).
Related
My Rails 5 application includes two models, Activity and Timeslot.
activity.rb
class Activity < ApplicationRecord
belongs_to :club
has_many :timeslots, :dependent => :destroy
accepts_nested_attributes_for :timeslots
validates :club_id, presence: true
validates :name, presence: true, length: { maximum: 50 }
end
timeslot.rb
class Timeslot < ApplicationRecord
belongs_to :activity
validates :time_start, presence: true
validates :time_end, presence: true
validates :day, presence: true
#validates :activity_id, presence: true (I realised this was causing one of the errors I had)
default_scope -> { order(day: :asc) }
end
When I create my activity, I'd also like to create it's first timeslot on the same page, same form.
new.html.erb
<%= form_for(#activity) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.label :name, "Class name" %>*
<%= f.text_field :name, class: 'form-control' %>
<%= f.fields_for :timeslots do |timeslots_form| %>
<%= timeslots_form.label :time_start, "Start time" %>
<%= timeslots_form.time_select :time_start %>
<%= timeslots_form.label :time_end, "End time" %>
<%= timeslots_form.time_select :time_end %>
<%= timeslots_form.label :day %>
<%= timeslots_form.select :day, (0..6).map {|d| [Date::DAYNAMES[d], d]} %>
<% end %>
</div>
<%= f.submit "Create class", class: "btn btn-primary" %>
<% end %>
My edit/update version of this seems to be working fine.
activities_controller.rb
class ActivitiesController < ApplicationController
...
def new
#activity = Activity.new
#activity.timeslots.build
end
def create
#activity = current_club.activities.build(activity_params)
##activity.timeslots.first.activity_id = #activity.id (I thought this might solve the problem, but didn't)
if #activity.save
flash[:success] = "New class created!"
redirect_to activities_path
else
render 'new'
end
end
def edit
#activity = current_club.activities.find_by(id: params[:id])
#activity.timeslots.build
end
def update
#activity = current_club.activities.find_by(id: params[:id])
if #activity.update_attributes(activity_params)
flash[:sucess] = "Class updated!"
redirect_to edit_activity_path(#activity)
else
render 'edit'
end
end
...
private
def activity_params
params.require(:activity).permit(:name, :active, #active is set to default: true
:timeslots_attributes => [:id,
:time_start,
:time_end,
:day,
:active])
end
end
But whenever I try to create a new activity I get the error message "Timeslots activities must exist".
I feel it's trying to assign the activity_id for timeslot before the activity is created, but I'm not sure. I've tried many things (some of which I've included in my example in comment form) but am unable to work out why I'm getting this error.
Update: Add error log
Started POST "/activities" for 127.0.0.1 at 2016-09-25 18:04:51 +0700
Processing by ActivitiesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"xp+dBcWC4cjI6FLpIqhU0RzM4ldZ4JpkFLSyAXcmifL73QqWz6R65EHm/Tj7QxlXnWiBA0axjVXvMZHQ+XKA9A==", "activity"=>{"name"=>"Newest class", "timeslots_attributes"=>{"0"=>{"time_start(1i)"=>"2016", "time_start(2i)"=>"9", "time_start(3i)"=>"25", "time_start(4i)"=>"12", "time_start(5i)"=>"00", "time_end(1i)"=>"2016", "time_end(2i)"=>"9", "time_end(3i)"=>"25", "time_end(4i)"=>"13", "time_end(5i)"=>"30", "day"=>"4"}}}, "commit"=>"Create class"}
Club Load (0.2ms) SELECT "clubs".* FROM "clubs" WHERE "clubs"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
(0.1ms) begin transaction
(0.1ms) rollback transaction
Rendering activities/new.html.erb within layouts/application
Rendered shared/_error_messages.html.erb (1.5ms)
Rendered activities/new.html.erb within layouts/application (16.9ms)
Rendered layouts/_rails_default.html.erb (58.5ms)
Rendered layouts/_shim.html.erb (0.5ms)
Rendered layouts/_header.html.erb (1.7ms)
Rendered layouts/_footer.html.erb (0.8ms)
Completed 200 OK in 111ms (Views: 93.9ms | ActiveRecord: 0.3ms)
You're getting this error because Rails 5 makes belongs_to attribute required by default. Also, the saving mechanism kind of follows:
validate your parent model
validate your child model # validation fails here because parent doesn't have an id yet, because it hasn't been saved
save parent model
save child model
A way to resolve this is to:
class Activity < AR
has_many :timeslots, dependent: :destroy, inverse_of: :activity
accepts_nested_attributes_for :timeslots
end
class Timeslot < AR
belongs_to :activity, inverse_of: :timeslot
end
You could learn more of this here and here
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
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
My accepts_nested_attributes_for only saves the parent and not the child (nested) attributes. This is many_to_many relationship between parent and child.
Problem: nothing happens and nothing is saved. But on the page, I get this message:
utf8: "\xE2\x9C\x93"
authenticity_token: 9Pjxt7e5RRgWVGafRyMoDqBSqmtj/R2zBSiVxGGxFOI=
parent: !map:ActiveSupport::HashWithIndifferentAccess
name: "Test"
gender: Male
children_attributes: !map:ActiveSupport::HashWithIndifferentAccess
"0": !map:ActiveSupport::HashWithIndifferentAccess
email: 1234#testing.com
commit: Submit
From the msg on my terminal log, I think it's because the children_attributes never got saved as it was assigned a "0"?. This is the terminal msg:
Started POST "/parents" for 127.0.0.1 at 2011-09-14 11:14:14 -0400
Processing by ParentsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"9Pjxt7e5RRgWVGafRyMoDqBSqmtj/R2zBSiVxGGxFOI=", "parent"=>{"name"=>"123", "gender"=>"Male", "children_attributes"=>{"0"=>{"email"=>"1234#testing.com"}}}, "commit"=>"Submit"}
SQL (0.1ms) BEGIN
SQL (0.6ms) SELECT 1 FROM `children` WHERE (LOWER(`children`.`email`) = LOWER('1234#testing.com')) LIMIT 1
SQL (0.2ms) ROLLBACK
Controller-
def new
#parent = Parent.new
#parent.children.build
end
def create
#parent = Parent.new(params[:parent])
if #parent.save
redirect_to root_path
else
render 'new'
end
end
Parent model -
attr_accessible :children_attributes
has_many :children, :through => :parent_child_relationships
accepts_nested_attributes_for :children
Child model -
has_many :parents, :through => :parent_child_relationships
validates :email, :name, :presence => true
Parent form view -
<%= form_for(#parent, new_parent_path) do |f| %>
<div>
<%= f.label(:name) %></br>
<%= f.text_field(:name) %>
</div>
<div>
<%= f.label(:gender) %> <br/>
<%= f.select(:gender, ['Male', 'Female']) %>
</div>
<%= f.fields_for :children do |ff| %>
<div>
<%= ff.label(:email)%></br>
<%= ff.text_field(:email)%>
</div>
<% end %>
<%= submit_tag "Submit" %>
<% end %>
Any help would be greatly appreciated! Thank you!
Can you change your validations on child model to :
validates :name, :presence => true
validates :email, :presence => true, :email => true
And see if that fixes it for you?
Check if there are any unsuccessful validations for the children model
You can validate on create, using something like below
validates_uniqueness_of :xxxx, :on => :create
I'm having difficulty saving two fields in a nested form. The parent field saves fine, but the nested field is throwing the "WARNING: Can't mass-assign protected attributes" error.
I've placed things in the Item model with attr_accessible, but it's not solving the issue.
List_controller
def create
#list = List.new(params[:list])
#list[:user_id] = current_user.id
if #list.save
flash[:notice] = "Successfully created list."
redirect_to #list
else
render :action => 'new'
end
end
List model
class List < ActiveRecord::Base
has_many :items, :dependent => :destroy
accepts_nested_attributes_for :items, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
end
Item model
class Item < ActiveRecord::Base
belongs_to :list
end
Form
<%= form_for(#list) do |list_form| %>
<p>
<%= list_form.label :title %><br />
<%= list_form.text_field :title %>
</p>
<p>
<%= render :partial => 'item_fields',
:locals => {:form => list_form} %>
</p>
<%= list_form.submit %>
<% end %>
Form partial
<%= form.fields_for :item do |item_form| %>
<%= item_form.label :name, 'item' %>
<%= item_form.text_field :name %>
<% end %>
Server error log
Started POST "/lists" for 127.0.0.1 at Sun Mar 27 02:54:18 -0400 2011
Processing by ListsController#create as HTML
Parameters: {"commit"=>"Create List", "list"=>{"title"=>"figaro", "item"=>{"na
me"=>"foobar"}}, "authenticity_token"=>"afu5xPgvJenu6XKXcsyilR8RconLP/OZ3NxsICE3RVk=
", "utf8"=>"Γ£ô"}
←[1m←[35mUser Load (1.0ms)←[0m SELECT "users".* FROM "users" WHERE "users"."i
d" = 2 LIMIT 1
WARNING: Can't mass-assign protected attributes: item
←[1m←[36mAREL (2.0ms)←[0m ←[1mINSERT INTO "lists" ("user_id", "updated_at", "
title", "created_at") VALUES (2, '2011-03-27 06:54:18.893302', 'figaro', '2011-0
3-27 06:54:18.893302')←[0m
Redirected to http://localhost:3000/lists/77
Completed 302 Found in 117ms
You're using fields_for :item but your List model has_many :items.
Try this:
<%= form.fields_for :items do |item_form| %>
If this doesn't help try to add attr_accessible :items_attributes to you List model. From the docs:
[..] If you are using attr_protected or attr_accessible, then you will need to add the attribute writer to the allowed list.
Add attr_accessible :items to your List class.