I have a rails 4 application that has a params block that looks like:
def store_params
params.require(:store).permit(:name, :description, :user_id, products_attributes: [:id, :type, { productFields: [:type, :content ] } ])
end
but I'm getting the error:
ActiveRecord::AssociationTypeMismatch in StoresController#create
ProductField expected, got Array
The parameters I'm trying to insert look like:
Parameters: {"utf8"=>"✓", "store"=>{"name"=>"fdsaf", "description"=>"sdfd","products_attributes"=>{"0"=>{"productFields"=>{"type"=>"", "content"=>""}}}}, "type"=>"Magazine", "commit"=>"Create store"}
My models are
Store (has a has_many :products)
Product (has a has_many :productFields and belongs_to :store)
ProductField (has a belongs_to :product)
My view looks like:
<%= f.fields_for :products do |builder| %>
<%= render 'product_fields', f: builder %>
<% end %>
and then the product_fields partial:
<%= f.fields_for :productFields do |builder| %>
<%= builder.text_field :type%>
<%= builder.text_area :content %>
<% end %>
Make sure your Product and Store models have:
accepts_nested_attributes_for
inside them.
Then, if your calling nested fields_for like that, make sure you build them (in the controller), something like:
product = #store.products.build
product.productFields.build
Firstly you should have set accepts_nested_attributes_for in your models like this
class Store < ActiveRecord::Base
has_many :products
accepts_nested_attributes_for :products
end
class Product < ActiveRecord::Base
has_many :product_fields
belongs_to :store
accepts_nested_attributes_for :product_fields
end
class ProductField < ActiveRecord::Base
belongs_to :products
end
Secondly, your store_params should look like this
def store_params
params.require(:store).permit(:name, :description, :user_id, products_attributes: [:id, :type, { product_fields_attributes: [:type, :content ] } ])
end
Related
I'm trying to create a form in Rails 5.2 for a model with a has_many :through relationship to another model. The form needs to include nested attributes for the other model. However, the params are not nesting properly. I've created the following minimal example.
Here are my models:
class Order < ApplicationRecord
has_many :component_orders, dependent: :restrict_with_exception
has_many :components, through: :component_orders
accepts_nested_attributes_for :components
end
class Component < ApplicationRecord
has_many :component_orders, dependent: :restrict_with_exception
has_many :orders, through: :component_orders
end
class ComponentOrder < ApplicationRecord
belongs_to :component
belongs_to :order
end
The Component and Order models each have one attribute: :name.
Here is my form code:
<%= form_with model: #order do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= fields_for :components do |builder| %>
<%= builder.label :name %>
<%= builder.text_field :name %>
<% end %>
<%= f.submit %>
<% end %>
When I fill out the form, I get the following params:
{"utf8"=>"✓", "authenticity_token"=>"ztA1D9MBp1IRPsiZnnSAIl2sEYjFeincKxivoq0/pUO+ptlcfi6VG+ibBnSREqGq3VzckyRfkQtkCTDqvnTDjg==", "order"=>{"name"=>"Hello"}, "components"=>{"name"=>"World"}, "commit"=>"Create Order", "controller"=>"orders", "action"=>"create"}
Specifically, note that instead of a param like this:
{
"order" => {
"name" => "Hello",
"components_attributes" => {
"0" => {"name" => "World"}
}
}
}
There are separate keys for "order" and "components" at the same level. How can I cause these attributes to nest properly? Thank you!
EDIT: Here is my controller code:
class OrdersController < ApplicationController
def new
#order = Order.new
end
def create
#order = Order.new(order_params)
if #order.save
render json: #order, status: :created
else
render :head, status: :unprocessable_entity
end
end
private
def order_params
params.require(:order).permit(:name, components_attributes: [:name])
end
end
You should include accepts_nested_attributes_for :components in the Order model.
class Order < ApplicationRecord
has_many :component_orders, dependent: :restrict_with_exception
has_many :components, through: :component_orders
accepts_nested_attributes_for :components
end
And change
<%= fields_for :components do |builder| %>
to
<%= f.fields_for :components do |builder| %>
to get the desired params. accepts_nested_attributes_for :components creates a method namely components_attributes
More Info here
I'm trying to create an event app where each event has multiple tables and each table has multiple people sitting at a table the event has multiple tickets which map the people to the tables that they are sitting at -> in order to achieve this I have created a checkbox nested in the fields_for :tables (which is in turn in the event form) I presume something is wrong with either the strong parameters or the form itself but I have not been able to find any information that provides a solution to the problem.After checking the checkboxes in the form indicating which people are going to be sitting at this table and submitting the form and returning to the form I find that the checkboxes are no longer checked???
here are the contents of my model files
# models
class Event < ActiveRecord::Base
has_many :tables, dependent: :destroy
has_many :people , through: :tickets
has_many :tickets
accepts_nested_attributes_for :tickets, allow_destroy: true
accepts_nested_attributes_for :tables, allow_destroy: true
end
class Table < ActiveRecord::Base
belongs_to :event
has_many :tickets
has_many :people, through: :tickets
end
class Ticket < ActiveRecord::Base
belongs_to :table
belongs_to :person
end
class Person < ActiveRecord::Base
has_many :tickets
has_many :tables, through: :tickets
end
Here is the form with parts omitted for brevity.
<%= form_for(#event) do |f| %>
...
<%= f.fields_for :tables do |builder| %>
<%= render 'table_field', f: builder %>
<% end %>
<%= link_to_add_fields "Add Table", f, :tables %>
...
<% end %>
And here is the checkbox list I have implemented within the table_field.
<% Person.all.each do |person| %>
<div class="field">
<%= check_box_tag "table[people_ids][]", person.id, f.object.people.include?(person) %> <%= f.label [person.first_name, person.last_name].join(" ") %>
</div>
<% end %>
this is the event_params
def event_params
params.require(:event).permit(:name, :description, :start, :end, :latitude, :longitude, :address, :data, :people_ids => [], tables_attributes: [:id, :number, :size, :people_ids => []]).tap do |whitelisted|
whitelisted[:data] = params[:event][:data]
end
How do I get the checkboxes to be persistently checked in this form?
You can use http://apidock.com/rails/v4.0.2/ActionView/Helpers/FormOptionsHelper/collection_check_boxes
<%= f.collection_check_boxes(:people_ids, Person.all, :id, :name) do |person| %>
<%= person.label { person.check_box } %>
<% end %>
It will persist data as well.
I'm creating an application where a "submission" can be made using a form which creates client details and allows "referrals" to be created depending on the branch(es) that can provide the required service
class Submission < ActiveRecord::Base
has_many :referrals, :inverse_of => :submission, dependent: :delete_all
accepts_nested_attributes_for :referrals, :allow_destroy => true
end
class Referral < ActiveRecord::Base
belongs_to :submission
end
class Branch < ActiveRecord::Base
has_many :referrals
end
Submissions controller:
def new
#submission = Submission.new
#submission.build_client
#submission.client.build_address
#submission.referrals.build
end
def submission_params
params.require(:submission).permit(:consent, :user_id, client_attributes:
[:client_id, :first_name,
address_attributes:
[:first_line, :second_line,]
],
referrals_attributes:
[:branch_id]
)
end
The Submission form:
<%= form_for(#submission) do |f| %>
<%= f.fields_for :referrals do |referral| %>
<%= render 'referral_fields', f: referral %>
<% end %>
<% end %>
_referral_fields.html.erb:
<% Branch.all.where(referrable: true).each do |branch| %>
<label>
<%= check_box_tag 'branch_ids[]', branch.id %>
<%= branch.name %>
</label>
<% end %>
What I want is to have checkboxes for each referrable branch. When a branch is ticked and the submission is created, a referral will be created for that branch. However, when I submit the form, I get a validation error of "Referrals can't be blank". Any idea why this is not working?
Any help is most appreciated
Use collection_check_boxes.
<% # _referral_fields.html.erb %>
<%= f.collection_check_boxes(:branch_ids, Branch.where(referrable: true), :id, :name) do |b|
b.label { b.check_box } # wraps check box in label
end %>
You would need to whitelist submission[referrals_attributes][branch_ids] - not branch_id.
def submission_params
params.require(:submission)
.permit(
:consent,
:user_id,
client_attributes: [
:client_id,
:first_name,
address_attributes: [
:first_line, :second_line,
]
],
referrals_attributes: [:branch_ids]
)
end
Edited.
However for this to work you need to setup a relation between Referral and Branch. In this case you could use either a has_and_belongs_to_many (HABTM) or has_many though: (HMT) relationship.
See Choosing Between has_many :through and has_and_belongs_to_many.
class Referral < ActiveRecord::Base
belongs_to :submission
has_and_belongs_to_many :branches
end
class Branch < ActiveRecord::Base
has_and_belongs_to_many :referrals
end
You need to create a join table as well:
rails g migration CreateBranchReferralJoinTable branch referral
Been trying this all night and I can't get the photo upload to work. The 2 tables work just fine but no dice on a polymorphic table that holds photos. Any fresh new eyes would be such great help.
def restaurant_params
params.require(:restaurant).permit(:res_name, :res_description, restaurant_branches_attributes: [ :id, :address_line1, :address_line2, :address_line3, :address_line4, :address_line5, :address_line6, :number_phone, :number_fax, :email, :_destroy ], pictures_attributes: [ :id, :name, :image] )
end
class Picture < ActiveRecord::Base
belongs_to :imageable, polymorphic: true
mount_uploader :image, ImageUploader
end
class Restaurant < ActiveRecord::Base
has_many :restaurant_branches
accepts_nested_attributes_for :restaurant_branches, allow_destroy: true
end
class RestaurantBranch < ActiveRecord::Base
belongs_to :restaurants
has_many :pictures, as: :imageable
accepts_nested_attributes_for :pictures, allow_destroy: true
before_save :set_address
def set_contact_info
contact_info = "Phone: #{self[:number_phone]} Fax: #{self[:number_fax]} Email: #{self[:email]}"
end
def set_address
address = self.address_line2.nil? ? partial_address.titleize : complete_address.titleize
end
private
def complete_address
address = "#{self[:address_line1]} #{self[:address_line2]} #{self[:address_line3]} #{self[:address_line4]} #{self[:address_line5]} #{self[:address_line6]}"
end
def partial_address
address = "#{self[:address_line1]} #{self[:address_line3]} #{self[:address_line4]} #{self[:address_line5]} #{self[:address_line6]}"
end
end
Multi-Level Association
The polymorphic nature of the associations shouldn't be a problem, as Rails will typically send the data to the association - in this case pictures
I think your problem is more to do with the multi-level association you have, specifically that you need to pass the attributes as follows [form submit] > RestaurantBranch > Pictures
--
We've done this before, and here's how you do it:
#app/controllers/restaurants_controller.rb
Class RestaurantsController < ApplicationController
def new
#restaurant = Resaurant.new
#restaurant.restaurant_branches.build.pictures.build #-> notice multi-level nesting
end
def create
#restaurant = Restaurant.new(restaurant_params)
#restaurant.save
end
private
def restaurant_params
params.require(:restaurant).permit(:res_name, :res_description, restaurant_branches_attributes: [ :id, :address_line1, :address_line2, :address_line3, :address_line4, :address_line5, :address_line6, :number_phone, :number_fax, :email, :_destroy, pictures_attributes: [ :id, :name, :image]])
end
end
#app/views/restaurants/new.html.erb
<%= form_for #restaurant do |f| %>
<%= f.fields_for :restaurant_branches do |rb| %>
<%= rb.fields_for :pictures do |p| %>
<%= p.file_field :image %>
<% end %>
<% end %>
<% end %>
I am attempting to make the relationship in the Products controller through the Categorizations model to the ClothingSize model. I am getting a "Unpermitted parameters: clothing_size" error and the relationship is not ever made as a result. I think there is something wrong with the nested forms in the view as I cannot get the "Size" field to appear unless the symbol is singular shown below. I think that may be pointing to another problem.
<%= form_for(#product) do |f| %>
<%= f.fields_for :clothing_size do |cs| %>
Models
Products
class Product < ActiveRecord::Base
has_many :categorizations
has_many :clothing_sizes, through: :categorizations
accepts_nested_attributes_for :categorizations
end
Categorizations
class Categorization < ActiveRecord::Base
belongs_to :product
belongs_to :clothing_size
accepts_nested_attributes_for :clothing_size
end
ClothingSizes
class ClothingSize < ActiveRecord::Base
has_many :categorizations
has_many :products, through: :categorizations
accepts_nested_attributes_for :categorizations
end
Controller for Products
def new
#product = Product.new
test = #product.categorizations.build
def product_params
params.require(:product).permit(:title, :description, :image_url, :image_url2, :price, :quantity, :color, :clothing_sizes => [:sizes, :clothing_size_id])
end
end
View
<%= form_for(#product) do |f| %>
<%= f.fields_for :clothing_size do |cs| %>
<div class="field">
<%= cs.label :sizes, "Sizes" %><br>
<%= cs.text_field :sizes %>
</div>
<% end %>
<% end %>
In your view you have :clothing_size (singular) but in your product_params method you have :clothing_sizes (plural). Because your Product model has_many :clothing_sizes, you want it to be plural in your view.
<%= form_for(#product) do |f| %>
<%= f.fields_for :clothing_sizes do |cs| %>
In addition, you'll want to build a clothing_size for your product in your controller, and permit :clothing_sizes_attributes rather than clothing sizes in your product_params method. (I'd separate your new and product_params methods, making product_params private, but that's just me.)
def new
#product = Product.new
#clothing_size = #product.clothing_sizes.build
end
private
def product_params
params.require(:product).permit(:title, :description, :image_url, :image_url2, :price, :quantity, :color, :clothing_sizes_attributes => [:sizes, :clothing_size_id])
end