Ruby on Rails unpermitted parameters with has many through - ruby-on-rails

I have order and products, and a join table called orders_products, the order has many products through order_products and accepts nested attributed for it.
When I try to save it keeps saying unpermitted paramters: order_product
Params
def order_params
params.require(:order).permit(:id, :order_number, :customer_id, {order_products_attributes: [:id, :order, :product, :quantity ]}, {:product_ids => []})
end
Order model
class Order < ActiveRecord::Base
belongs_to :customer
has_many :order_products, class_name: "OrderProduct"
has_many :products, through: :order_products
accepts_nested_attributes_for :order_products, :allow_destroy => true
end
Order Product model
class OrderProduct < ActiveRecord::Base
belongs_to :product
belongs_to :order
end
Order controller new action
def new
#order = Order.new
#order.order_products.build
end
Order Form
<%= simple_form_for #order do |f| %>
<%= f.input :order_number %>
<%= f.fields_for :order_product do |fa| %>
<%= fa.input :product, collection: Product.all %>
<%= fa.input :quantity %>
<% end %>
<%= f.association :customer, as: :select %>
<%= f.submit %>
<% end %>
Params hash - {"utf8"=>"√","authenticity_token"=>"yBrH91u0OHTSPnCFO/484Ff6CRtyRLSg5AKD1Lc33k4=", "order"=>{"order_number"=>"0121", "order_product"=>{"product"=>"4", "quantity"=>"5"}, "customer_id"=>"3"}, "commit"=>"Create Order"}
Unpermitted parameters: order_product

you are missing s here:
<%= f.fields_for :order_products do |fa| %>

Related

Rails nested attributes "no implicit conversion of Symbol into Integer" for has_many association

I've following are the Model codes.
user.rb
has_many :teams, dependent: :destroy
has_many :companies, dependent: :destroy
after_create :create_tables!
def create_tables!
companies.create!
Team.create!(user_id: self.id, company_id: Company.where(user_id: self.id).first.id)
end
company.rb
belongs_to :user
has_many :teams, inverse_of: :company, dependent: :destroy
has_many :users, through: :teams
accepts_nested_attributes_for :teams
team.rb
belongs_to :user
belongs_to :company, inverse_of: :teams
Following are my Controller codes
companies_controller.rb
def new
#company = current_user.companies.new
#company.build_teams
end
def update
current_user.companies.first.update_attributes(company_params)
respond_to {|format| format.js}
end
private
def company_params
params.require(:company).permit(:name, :about, :problem, :solution, :logo, :url, :email, :phone, :category, :started_in,
teams_attributes: [:position, :admin])
end
In views
<%= form_with model: #company, method: :put do |f| %>
<%= f.fields_for :teams_attributes, #company.teams.first do |team| %>
<%= team.hidden_field :admin, value: true %>
<%= team.text_field :position, placeholder: 'Eg: CEO', class: 'input' %>
<% end %>
<%= f.submit 'Next' %>
<% end %>
When i try this in rails console it works and saved in db, in views params are also passing good. Its below
But in views it says
TypeError in CompaniesController#update no implicit conversion of Symbol into Integer
It should be f.fields_for :teams instead of f.fields_for :teams_attributes
<%= form_with model: #company, method: :put do |f| %>
<%= f.fields_for :teams, #company.teams.first do |team| %>
<%= team.hidden_field :admin, value: true %>
<%= team.text_field :position, placeholder: 'Eg: CEO', class: 'input' %>
<% end %>
<%= f.submit 'Next' %>
<% end %>

Rails 5 Has Many Through with Nested Form and Cocoon

Solverd: see bottom
I am building a ordering system of many products, with a HBTM from Join Table to anotherModel, but I have some problems when creating and editing a new record of a nested form.
I have tried many solutions from other questions and followed some tutorial like this or this, but nothing solved my issues.
Product Model:
class Product < ApplicationRecord
belongs_to :subcategory
has_many :order_products, inverse_of: :product
has_many :order, :through => :order_products
end
Order Model:
class Order < ApplicationRecord
has_many :order_products, inverse_of: :order
has_many :products, :through => :order_products
accepts_nested_attributes_for :products, reject_if: :all_blank, allow_destroy: true
end
Join Table:
class OrderProduct < ApplicationRecord
belongs_to :order
belongs_to :product
has_and_belongs_to_many :ingredients
accepts_nested_attributes_for :ingredients, reject_if: :all_blank, allow_destroy: true
end
Ingredients Model associated with join table: (many-to-many to save added ingredients to every products on the order)
class Ingredient < ApplicationRecord
has_and_belongs_to_many :order_products
end
Order Controller:
# GET /orders/new
def new
#order = Order.new
end
# GET /orders/1/edit
def edit
end
# POST /orders
# POST /orders.json
def create
#order = Order.new(order_params)
respond_to do |format|
if #order.save
format.html { redirect_to #order, notice: 'Order was successfully created.' }
format.json { render :show, status: :created, location: #order }
else
format.html { render :new }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
def order_params
params.require(:order).permit(:subtotal, :discount, :total,
order_products_attributes: [[:id, :order_id, :product_id , :_destroy]])
end
Views:
<%= simple_form_for(#order) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :subtotal %>
<%= f.input :discount %>
<%= f.input :total %>
</div>
<%= f.simple_fields_for :order_products do |o| %>
<%= render 'order_product_fields', f: o %>
<% end %>
<%= link_to_add_association "aggiungi prodotto", f, :order_products %>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
Partial: (unable to add cocoon's destroy link: undefined method `reflect_on_association' for NilClass:Class due to auto add of blank fields)
<div class="nested-fields order-product-fields">
<%= f.input :product %>
<%= f.input :order %>
<%= f.check_box :_destroy %>
</div>
I get this on console:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"PRNzrnxk/jrsAyPK5OzFxix2hIUmjCeWpD8Fkuhuhx8Wp3/xYTbTTvsfQkhnMDEBNnC/iNL46kl68XR7skb03g==", "order"=>{"subtotal"=>"", "discount"=>"", "total"=>"", "order_products"=>{"product"=>"", "order"=>"", "_destroy"=>"0"}}, "commit"=>"Create Order"}
Unpermitted parameter: order_products
My throubles are: EDIT: Solution on each point
When I load order pages, blanks fields for nested attributes are automatically created ()
Was wrong nested_attributes on Order Model:
accepts_nested_attributes_for **:order_products**, reject_if: :all_blank, allow_destroy: true
When submitting form no entry are created. (but I can add product to order via console .ex: order.products << product1)
When I add more product via cocoon's add link, only first is sent to controller
Don't know how to implements Strong Parameters and views for Ingredient's attributes inside the form of Order
Got this working:
Ingredient model:
has_many :ingredient_order_products, inverse_of: :ingredient
has_many :order_products, :through => :ingredient_order_products
IngredientOrderProduct model:
belongs_to :ingredient
belongs_to :order_product
Order Product model:
has_many :ingredient_order_products, inverse_of: :order_product
has_many :ingredients, :through => :ingredient_order_products
accepts_nested_attributes_for :ingredient_order_products, reject_if: :all_blank, allow_destroy: true
Order Controller:
def order_params
params.require(:order).permit(:customer_id, :subtotal, :discount, :total,
order_products_attributes: [[:id, :order_id, :product_id, :qty, :gift, :_destroy,
ingredient_order_products_attributes: [:id, :order_id, :ingredient_id, :_destroy]]])
end
_order_product_fields Partial:
<div id="ingredient">
<%= f.simple_fields_for :ingredient_order_products do |ingredient| %>
<%= render 'ingredient_order_product_fields', f: ingredient %>
<% end %>
<%= link_to_add_association "Aggiungi Ingrediente", f, :ingredient_order_products %>
</div>

rails4 collection select with has_many through association and nested model forms

I have a rails4 app. At the moment my collection select only works if I select only one option. Below is my working code. I only have product form. Industry model is populated with seeds.rb. IndustryProduct is only use to connect the other 2 models.
I'd like to know what I have to change in the code to be able to choose more.
I saw some working examples with multiple: true option like (https://www.youtube.com/watch?v=ZNrNGTe2Zqk at 10:20) but in this case the UI is kinda ugly + couldn't pull it off with any of the sample codes. Is there an other solution like having more boxes with one option chosen instead of one box with multiple options?
models:
class Product < ActiveRecord::Base
belongs_to :user
has_many :industry_products
has_many :industries, through: :industry_products
has_many :product_features
accepts_nested_attributes_for :industry_products, allow_destroy: true
accepts_nested_attributes_for :product_features
validates_associated :industry_products
validates_associated :product_features
end
class Industry < ActiveRecord::Base
has_many :industry_products
has_many :products, through: :industry_products
accepts_nested_attributes_for :industry_products
end
class IndustryProduct < ActiveRecord::Base
belongs_to :product
belongs_to :industry
end
_form.html.erb
<%= form_for #product do |f| %>
<%= render 'layouts/error_messages', object: f.object %>
......
<%= f.fields_for :industry_products do |p| %>
<%= p.collection_select :industry_id, Industry.all, :id, :name %>
<% end %>
<%= f.fields_for :product_features do |p| %>
<%= p.text_field :feature, placeholder: "add a feature", class: "form-control" %>
<% end %>
<%= f.submit class: "btn btn-primary" %>
<% end %>
products controller
def new
#product = Product.new
#product.industry_products.build
#product.product_features.build
end
def create
#product = current_user.products.new(product_params)
if #product.save
redirect_to #product
else
render action: :new
end
end
......
def product_params
params.require(:product).permit(....., industry_products_attributes: [:id, :industry_id, :_destroy], industries_attributes: [:id, :name], product_features_attributes: [:feature])
end
Firstly, you could fix your first collection select by using it to set the industry_ids for the #product:
<%= form_for #product do |f| %>
<%= f.collection_select :industry_ids, Industry.all, :id, :name %>
<% end %>
This will allow you to set the collection_singular_ids method, which exists for all has_many associations.
You'd have to back it up in the params method:
#app/controllers/products_controller.rb
....
def product_params
params.require(:product).permit(.... industry_ids: [])
end
A lot more succinct than using nested attributes.
To get that "multiple" selection, you'll want to use the following:
<%= f.collection_select :industry_ids, Industry.all, :id, :name, {}, { multiple: true } %>
Tested & working
--
You may also want to look at collection_check_boxes:
<%= f.collection_check_boxes :industry_ids, Industry.all, :id, :name %>

Rails 4.2 Create ActiveRecord object with nested params

Does anybody know how to handle these attributes in the controllers new and create action?
(byebug) params
{"utf8"=>"V", "authenticity_token"=>"Wex9nnFigOviySzjfPN6zw==",
"recipe"=>{"name"=>"Cupcake"},
"name"=>{"ingredient_id"=>"2"},
"quantity"=>{"amount"=>"zwei"},
"commit"=>"Create", "controller"=>"recipes", "action"=>"create"}
I don't know how to create the quantities record with the value from Ingredient in recipe#new
("name"=>{"ingredient_id"=>"2")
Two records should be created (Recipe and Quantity).
Recipe
name
Quantity
ingredient_id
recipe_id
amount
Ingredient
name
class Recipe < ActiveRecord::Base
belongs_to :user
has_many :quantities
has_many :ingredients, through: :quantities
accepts_nested_attributes_for :quantities, :reject_if => :all_blank, :allow_destroy => true
accepts_nested_attributes_for :ingredients
end
class Ingredient < ActiveRecord::Base
has_many :quantities
has_many :recipes, :through => :quantities
end
class Quantity < ActiveRecord::Base
belongs_to :recipe
belongs_to :ingredient
accepts_nested_attributes_for :ingredient, :reject_if => :all_blank
end
<%= form_for(#recipe) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= form_for(#recipe.quantities.build) do |g| %>
<%= select("name", "ingredient_id", Ingredient.all.collect {|p| [ p.name, p.id ] }, {include_blank: 'Auswählen'}) %>
<%= g.label :amount %>
<%= g.text_field :amount %>
<%= g.submit "Create" %>
<% end %>
<% end %>
I replaced:
<%= form_for(#recipe.quantities.build) do |g| %>
with:
<%= f.fields_for :quantities, #recipe.quantities.build do |g| %>
And put submit action to form level after fields_for:
<%= f.submit "Create" %>

form_for with ckeckbox_tag from other model

I'm new to rails and just cant get that problem solved.
i have 3 models. Orders, Products and LineItems.
I want to have a order form with checkboxes for each product. User selects appropriate products and submits the order.
I cannot get the form to create the correct hash.
class Order < ActiveRecord::Base
attr_accessible :account_id, :user_id
has_many :line_items, :dependent => :destroy
end
class LineItem < ActiveRecord::Base
attr_accessible :account_id, :product_id, :order_id
belongs_to :orders
belongs_to :product
end
Here the view:
<%= form_for 'line_items[]' do |f| %>
<%= f.select :account_id, options_from_collection_for_select( Account.all,
:id, :name ), :prompt => 'Select Account' %>
<% Product.all.each do |product| %>
<div>
<%= check_box_tag 'line_items[product_ids][]', product.id %>
</div>
<% end -%>
<div>
<%= f.submit 'save' %>
</div>
thanks!
You would need to use accepts_nested_attributes_for in your model to enable nested atributes from associated models. You may also want to check out this railscast and adapt to your needs.
For example in the orders model:
class Order < ActiveRecord::Base
attr_accessible :account_id, :user_id
has_many :products #This makes the association to products
has_many :line_items, :dependent => :destroy
accepts_nested_attributes_for :products #This allows the attributes from products accessible
end
Then the form could be:
<%= form_for #order do |f| %>
<%= f.select :account_id, options_from_collection_for_select( Account.all,
:id, :name ), :prompt => 'Select Account' %>
<%= f.fields_for :product do |product_form| %>
<%= product_form.check_box :id %>
<% end %>
<%= f.submit %>
<% end %>

Resources