Rails nested form inserts null attributes in database - ruby-on-rails

I've searched a lot and the common cause of this problem is attr_ascessible :model_attributes not being declared but I can't seem to get it working.
Looking at the Log below :referee, and :ticket_order values are in the params hash but then are inserted as null in the table. Foreign keys for user_id and event_id are saved in a new record without any errors. The warning about mass assignment led me to the attr_ascessible declaration, tried different variations of it without luck. I'm using devise.
Development log
Started POST "/events/1" for 127.0.0.1 at 2011-07-14 17:38:16 +0100
Processing by EventsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"ddddddjTdnaLKQgZncSDGYt63JA=", "event"=>{"relationship"=>{"event_id"=>"1", "referee"=>"9", "ticket_order"=>"1"}}, "commit"=>"Confirm Purchase", "id"=>"1"}
User Load (20.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 8 LIMIT 1
Event Load (13.1ms) SELECT "events".* FROM "events" WHERE "events"."id" = 1 LIMIT 1
AREL (18.7ms) INSERT INTO "relationships" ("user_id", "event_id", "created_at", "updated_at", "referee", "ticket_order") VALUES (8, 1, '2011-07-14 16:38:16.963351', '2011-07-14 16:38:16.963351', NULL, NULL)
WARNING: Can't mass-assign protected attributes: relationship
[paperclip] Saving attachments.
Redirected to http://localhost:3000/events/1
Completed 302 Found in 588ms
Events
class Event < ActiveRecord::Base
attr_accessible :artist, :venue, :show_info, :date, :doors, :ticket_issue, :ticket_price,
:travel_cost, :accomodation_cost, :hire_cost, :image, :avatar_url, :relationships_attributes, :referee, :ticket_order
has_many :relationships
has_many :users, :through => :relationships
accepts_nested_attributes_for :relationships
Events Controller
def new
#event = Event.new
#users = Relationships.find(:all)
relationship = #event.relationships.build()
end
def create
#event = Event.new(params[:event])
current_user.attend!(#event)
if #event.save
redirect_to #event, :notice => "Successfully created event."
else
render :action => 'new'
end
end
User.rb
def attending?(event)
relationships.find_by_event_id(event)
end
Relationship.rb
class Relationship < ActiveRecord::Base
belongs_to :user
belongs_to :event
attr_accessible :event_id
form view
<%= semantic_form_for #event do |form| %>
<%= form.semantic_fields_for :relationship do |builder| %>
<%= builder.hidden_field :event_id, :value => #event.id %>
<%= builder.inputs do %>
<%= builder.input :referee, :as => :select, :collection => #event.users.all %>
<%= builder.input :ticket_order, :as => :number %>
<% end %>
<% end %>

Yes it must be this, replace:
form.semantic_fields_for :relationship
with:
form.semantic_fields_for :relationships

Related

Unpermitted parameters for has_many :through nested form in Rails 5

Hi I am trying to implement a has_many :through nested form in my Rails 5 app to create a project with users assigned to it. However, when I try to create the project, I face the following validation errors:
- Project users user company must exist
- Project users user email can't be blank
- Project users user email is invalid
- Project users user password can't be blank
- Project users user firstname can't be blank
- Project users user lastname can't be blank
These are validations I did for the user model but I do not understand why they appear when I create a project with nested users. In addition, the console indicated :fullname as an unpermitted parameters, as shown below.
Parameters: {"utf8"=>"✓", "authenticity_token"=>"3RtrzKKVrSOiGLYnHwubF3GaRAbcQE/61doRM5clT8GpFYeJoEVnU2lEmQsNwVO8qecdqig8xjwbTqqaqL1gYQ==", "project"=>{"name"=>"dsada", "description"=>"dadasd", "project_users_attributes"=>{"0"=>{"user_attributes"=>{"fullname"=>["", "5", "4", "3"]}}},"choice"=>"1", "button"=>"", "company_id"=>"1"}
User Load (0.9ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
Company Load (0.3ms) SELECT "companies".* FROM "companies" WHERE "companies"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
Unpermitted parameter: fullname
Could anyone enlighten me on why I am facing these validation errors and why fullname is considered unpermitted although i included them in project strong params? My codes are as shown below. Thank you!
#Model - project.rb
class Project < ApplicationRecord
has_many :project_users, inverse_of: :project
has_many :users, through: :project_users
accepts_nested_attributes_for :project_users
end
#Model - project_user.rb
class ProjectUser < ApplicationRecord
belongs_to :project, inverse_of: :project_users
belongs_to :user, inverse_of: :project_users
accepts_nested_attributes_for :user
end
#Model - user.rb
class User < ApplicationRecord
has_many :project_users, inverse_of: :user
has_many :projects, through: :project_users
end
#Controller - projects_controller.rb
class ProjectsController < ApplicationController
def new
#company = Company.find(params[:company_id])
#project = #company.projects.build
#project.project_users.build.build_user
end
def create
#company = Company.find(params[:company_id])
#project = #company.projects.build(proj_params)
if #project.valid?
#project.save
render 'show'
else
render 'new'
end
end
private
def proj_params
params.require(:project).permit(:name, :description, project_users_attributes: [:id, user_attributes:[:fullname]])
end
end
end
#Views - new.html.erb
<%= form_for [#company, #project] do |f| %>
<%= f.label :title %>
<%= f.text_field :name %>
<%= f.label :description %>
<%= f.text_area :description %>
<%= f.fields_for :project_users do |project_user_form| %>
<%= project_user_form.fields_for :user do |user| %>
<%= user.label :team_members %>
<%= user.select :fullname, company.users.collect { |p| [ p.fullname, p.id ] }, {:prompt => 'Select Team Members'}, { :multiple => true} %>
<% end %>
<% end %>
<%= f.button :submit => "" %>
<% end %>
Here is why your strong parameters does not work well.
You're saying in proj_params that :fullname is a field. But it's not just a field - it's an array of values. So if you change that to :fullname => [] that'll permit the parameter.
But.. that doesn't make any sense.
Your code is trying to create new users, not assign them. That's why you get validations errors. The simplest way to prevent that is to pass IDs of user, which will try to update / build association, not create.
Then, you'd be better off to pass users' IDs from the view. Try passing user_ids instead of fullnames and don't forget user_ids => [] in strong parameters.

Rails 4 Nested Forms, Error: Unpermitted parameter: order_item

My goal is to create a new Order and an associated OrderItem using the same form.
Models
class Order < ActiveRecord::Base
belongs_to :user
has_many :order_items, dependent: :destroy
accepts_nested_attributes_for :order_items
validates_associated :order_items
end
class OrderItem < ActiveRecord::Base
belongs_to :order
default_scope -> { order(created_at: :desc) }
end
View
<% #items.each do |item| %>
<%= form_for(#order) do |f| %>
<%= f.hidden_field :user_id, :value => session[:user_id] %>
<%= f.fields_for :order_items do |oi| %>
<%= oi.hidden_field :product_id, :value => item.id %>
<%= oi.hidden_field :price, :value => item.price %>
<%= oi.number_field :quantity, value: 1, class: 'form-control', min: 1 %>
<% end %>
<%= f.submit "Buy Now", class: "btn btn-primary" %>
<% end %>
Controller
def new
#order = Order.new
#order.order_items.build
end
def create
#order = Order.new(order_params)
if #order.save
redirect_to cart_path
else
redirect_to root_url
end
end
private
def order_params
params.require(:order).permit(:user_id, :custom_item_id, order_items_attributes: [:product_id, :price, :quantity])
end
When submitting the nested form data to the database, the error message Unpermitted parameter: order_item gets returned and only the order data is saved.
Update <-- This is resolved
When I remove the "f." from <%= f.fields_for the form renders correctly and order_params includes the order_items data. This is interesting because the RailsGuide for Form Helpers includes the "f." http://guides.rubyonrails.org/form_helpers.html#nested-forms
Parameter
{"utf8"=>"✓", "authenticity_token"=>"<TOKEN>", "order"=>{"user_id"=>"1", "order_item"=>{"product_id"=>"5", "price"=>"120.0", "quantity"=>"1"}}, "commit"=>"Buy Now"}
The data still does not save to the corresponding models.
Update 2 <-- This is resolved
Updated the createaction in the controller to if #order.save!, below is the error message:
Validation failed: Order items order can't be blank, Order items product can't be blank, Order items quantity can't be blank, Order items price can't be blank, Order items is invalid
I believe that the mistake is in this line of code #order.order_items.build(order_params[:order_items_attributes]) but I am not sure what I need to change.
Update 3 Unpermitted parameter: order_item Error message
From the terminal:
Processing by OrdersController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=><TOKEN>, "order"=> "user_id"=>"1", "order_item"=>{"product_id"=>"5", "price"=>"120.0", quantity"=>"1"}}, "commit"=>"Buy Now"}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
Unpermitted parameter: order_item
(0.2ms) begin transaction
SQL (1.4ms) INSERT INTO "orders" ("user_id", "created_at", "updated_at") VALUES (?, ?, ?) [["user_id", 1], ["created_at", "2016-03-18 14:58:21.724246"], ["updated_at", "2016-03-18 14:58:21.724246"]]
(14.4ms) commit transaction
The order_itemsdata does not get saved.
First, it seems like your association is incorrect in OrderItem. It should be belongs_to :order instead of belongs_to :order_item_params.
Second, I believe your form should say <%= f.fields_for :order_items do |oi| %> (:order_items not :order_item)
Finally, you should not need to do this in your controller: #order.order_items.build(order_params[:order_items_attributes])
Controller
def create
#order = Order.new(order_params)
if #order.save
redirect_to cart_path
else
redirect_to root#url
end
end
def order_params
params.require(:order).permit(:user_id, :custom_item_id, order_items_attributes: [:product_id, :price, :quantity])
end
The view that rendered the form was not in another controller and not in the orders controller. The show action of tht view did not include an instance variable for order_items. This caused the error messages. Thank you for all of your help. For anyone looking for resources for nested forms below are some helpful resources.
YouTube Video Instructions API dock for fields_for
Go Rails video for Form Nested Attributes and Fields For in Rails
Active Record Nested Attributes
Rails Guide: Active Record Associations

Rails 4, double-nested models and strong parameters

I am fairly new to Ruby on Rails and began with rails 4 right away.
I have sucessfully nested a Recipe and a Ingredient model so that they can be added in the same form. Next I want to nest quantity within ingredient so that that aswell can be added within the same form. Everything seems to be working fine up until when the quantity of the ingredient is about to be inserted in the database and from this i believe there is something wrong with the strong params in the recipes_controller. But i will post the full code below.
I am using simple_form for the forms.
Thankful for any help!
Here are my models:
class Recipe < ActiveRecord::Base
has_many :comments, dependent: :destroy
has_many :ingredients, dependent: :destroy
accepts_nested_attributes_for :ingredients, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
validates :title, presence: true
validates :desc, presence: true
end
class Ingredient < ActiveRecord::Base
belongs_to :recipe
has_many :quantities, dependent: :destroy
accepts_nested_attributes_for :quantities, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
end
class Quantity < ActiveRecord::Base
belongs_to :ingredient
end
Here is the recipes_controller
class RecipesController < ApplicationController
def new
#recipe = Recipe.new
3.times do
ingredient = #recipe.ingredients.build
1.times {ingredient.quantities.build }
end
end
def create
#recipe = Recipe.new(params[:recipe].permit(:title, :desc, ingredients_attributes: [:id, :recipe_id, :name, :_destroy, quantities_attributes: [:id, :ingredient_id, :amount, :unit, :_destroy]]))
if #recipe.save
redirect_to #recipe
else
render "new"
end
end
def show
#recipe = Recipe.find(params[:id])
end
def edit
#recipe = Recipe.find(params[:id])
end
def update
#recipe = Recipe.find(params[:id])
if #recipe.update(params[:recipe].permit(:title, :desc))
redirect_to #recipe
else
render 'edit'
end
end
def destroy
#recipe = Recipe.find(params[:id])
#recipe.destroy
redirect_to recipes_path
end
def index
#recipes = Recipe.all
end
private
def post_params
params.require(:recipe).permit(:title, :desc, ingredients_attributes: [:id, :recipe_id, :name, :_destroy, quantities_attributes: [:id, :ingredient_id, :amount, :unit, :_destroy]])
end
end
Then i use simple form to create a form for recipe, ingredient and quantity through partials.
_form:
<%= simple_form_for #recipe do |f| %>
<%= f.error_notification %>
<%= f.input :title %>
<%= f.input :desc %>
<%= f.simple_fields_for :ingredients do |builder| %>
<%= render "ingredient_fields", :f => builder %>
<% end %>
<p class="links">
<%= link_to_add_association 'add ingredient', f, :ingredients %>
<p class="links">
<%= f.error :base%>
<%= f.submit %>
<% end %>
Which renders from _ingredients_fields:
<div class="nested-fields">
<%= f.input :name, label: "Ingredient" %>
<%= f.simple_fields_for :quantities do |builder| %>
<%= render "quantities_fields", :f => builder %>
<% end %>
<%= link_to_remove_association "remove", f %>
</div>
which renders from _quantities_fields: [EDITED]
<div class="nested-fields">
<%= f.input :amount %>
<%= f.input :unit %>
</div>
Trying to add new recipes result in the following log statement:
Started POST "/recipes" for 127.0.0.1 at 2013-10-29 14:15:40 +0100
Processing by RecipesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"t6LKgDLwAxaU9xo2ipyCM+j1yfVF9WrI8AoGTX+gRkw=", "recipe"=>{"title"=>"Pancakes", "desc"=>"Tasty", "ingredients_attributes"=>{"0"=>{"name"=>"Milk", "quantities_attributes"=>{"0"=>{"amount"=>"1", "unit"=>"Cup"}}, "_destroy"=>"false"}}}, "commit"=>"Create Recipe"}
[1m[35m (0.1ms)[0m begin transaction
[1m[36mSQL (3.5ms)[0m [1mINSERT INTO "recipes" ("created_at", "desc", "title", "updated_at") VALUES (?, ?, ?, ?)[0m [["created_at", Tue, 29 Oct 2013 13:15:40 UTC +00:00], ["desc", "Tasty"], ["title", "Pancakes"], ["updated_at", Tue, 29 Oct 2013 13:15:40 UTC +00:00]]
[1m[35mSQL (0.4ms)[0m INSERT INTO "ingredients" ("created_at", "name", "recipe_id", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Tue, 29 Oct 2013 13:15:40 UTC +00:00], ["name", "Milk"], ["recipe_id", 27], ["updated_at", Tue, 29 Oct 2013 13:15:40 UTC +00:00]]
[1m[36m (7.8ms)[0m [1mcommit transaction[0m
Redirected to http://www.projectcookbook.dev/recipes/27
Completed 302 Found in 22ms (ActiveRecord: 11.7ms)
You're using similar render for _quantities and _ingredients partials, which is wrong. In _quantities_field you don't need
<%= f.simple_fields_for :quantities do |builder| %>
<%= render "quantities_fields", :f => builder %>
<% end %>
AND should adjust
<%= f.input :name, label: "Quantity" %>
in _quantities_fields.
UPD
I think the problem is in :reject_if-clause at Ingredient model. It should be
:reject_if => lambda { |a| a[:amount].blank? }
bc here you specify conditions for Quantity, not for Ingredient
On code styling:
1) In controller it's better to use relevant name of private method for strong parameters: recipe_params instead of post_params and then use it for creation of new Recipe #recipe = Recipe.new(recipe_params)
2) Current associations between Recipe, Ingredient and Quantity will lead to Ingredient duplication in case two Recipes use similar one. The reason is belongs_to, which define single association. Try another approach (bellow).
BTW. recently I've answered on the similar question. Check it out: How do I reference an existing instance of a model in a nested Rails form?
I thing you are missing in this part
<%= simple_form_for #recipe do |f| %>
it should be
<%= simple_nested_form_for #recipe do |f| %>

rails formtastic nested form WARNING: Can't mass-assign protected attributes

I've following models:
class CapstoneMilestone < ActiveRecord::Base
attr_accessible :capstone_id, :milestone_id, :rank, :id, :status, :statusweight, :rating, :ratingweight
belongs_to :milestone
belongs_to :capstone
accepts_nested_attributes_for :capstone, :allow_destroy => false
accepts_nested_attributes_for :milestone, :allow_destroy => false
end
class Milestone < ActiveRecord::Base
has_many :capstone_milestones
has_many :capstones, :through => :capstone_milestones
attr_accessible :id, :name, :description, :department_id, :project
accepts_nested_attributes_for :capstone_milestones, :allow_destroy => true
end
I also have a formtastic form:
<% semantic_form_for(#capstone_milestone) do |form| %>
<%= form.semantic_errors :state %>
<% form.inputs do %>
<%= form.input :capstone_id , :as => :select, :collection => Capstone.all %>
<%= form.input :milestone_id, :as => :select, :collection => Milestone.all %>
<%= form.input :status, :as => :numeric%>
<%= form.input :statusweight, :as => :numeric%>
<%= form.input :rating, :as => :numeric%>
<%= form.input :ratingweight, :as => :numeric%>
<% end %>
<%= form.inputs :name, :for => :milestone%>
<%= form.buttons %>
<% end %>
And my capstone_milestone controller (should) take care of the update:
def update
#milestone=#capstone_milestone.milestone # I also removed these 2 lines without success
#milestone.update_attributes(params[:milestone_id])
respond_to do |format|
if #capstone_milestone.update_attributes(params[:capstone_milestone])
format.html { redirect_to(session[:return_to], :notice => 'Milestone was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #capstone_milestone.errors, :status => :unprocessable_entity }
end
end
end
When I submit the form, the capstone_milestone is update but the linked milestone is not.
This is the server log:
Started POST "/capstone_milestones/12" for 127.0.0.1 at 2011-03-18 11:40:30 +0100
Processing by CapstoneMilestonesController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"ZkErrLTpdp56BASPdZiiT6ZcvUx5KsI+Gm3JLnzM6D0=", "capstone_milestone"=>{"capstone_id"=>"100001", "milestone_id"=>"100002", "status"=>"80.0", "statusweight"=>"1.0", "rating"=>"", "ratingweight"=>"1.0", "milestone_attributes"=>{"name"=>"Land Control Analysis 2", "id"=>"100002"}}, "commit"=>"Update Capstone milestone", "id"=>"12"}
User Load (0.4ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 3 LIMIT 1
CapstoneMilestone Load (0.4ms) SELECT `capstone_milestones`.* FROM `capstone_milestones` WHERE `capstone_milestones`.`id` = 12 ORDER BY capstone_milestones.rank LIMIT 1
Milestone Load (0.3ms) SELECT `milestones`.* FROM `milestones` WHERE `milestones`.`id` = 100002 LIMIT 1
SQL (0.1ms) BEGIN
SQL (0.1ms) COMMIT
SQL (0.1ms) BEGIN
WARNING: Can't mass-assign protected attributes: milestone_attributes
Any idea, suggestion to unblock me would be greatly appreciated!
You need to add :milestone_attributes to attr_accessible of CapstoneMilestone.
attr_accessible :capstone_id, :milestone_id, :rank, :id, :status, :statusweight,
:rating, :ratingweight, :milestone_attributes

Rails 3.0.5 Nested Form - Unable to Create New - WARNING: Can't mass-assign protected attributes

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.

Resources