I'm having a little trouble setting up my simple for for create/update. Here's the form:
<%= simple_form_for( setup_menu(#menu) ) do |f| %>
<%= f.input :user_id, :as => :hidden %>
<%= f.input :name %>
<%= f.input :description %>
<%= f.association :recipes %>
<%= f.button :submit %>
<% end %>
Here are the three models:
class Menu < ActiveRecord::Base
has_many :courses
has_many :recipes, through: :courses
accepts_nested_attributes_for :recipes,
reject_if: :all_blank
accepts_nested_attributes_for :courses,
reject_if: :all_blank
end
class Recipe < ActiveRecord::Base
has_many :courses
has_many :menus, through: :courses
accepts_nested_attributes_for :menus
end
class Course < ActiveRecord::Base
belongs_to :menu
belongs_to :recipe
end
And here is the params definition from the menus_controller:
def menu_params
params.require(:menu).permit(:user_id, :name, :description, :recipe_ids, :course_ids, :courses, :recipes,
recipes_attributes: [:id, :recipe_id, :_destroy], courses_attributes: [:id, :recipe_id, :menu_id, :_destroy]
)
end
I keep getting an unpermitted parameter error on the recipe_ids.
Started PATCH "/menus/1" for ::1 at 2015-10-01 20:54:56 -0500
Processing by MenusController#update as HTML
Parameters: {"utf8"=>"√", "authenticity_token"=>"i/7E27BWul9trszURDu1z8PtsHaG54byG9JOlEp3mn2oQZVveM2mSP4XTLzjWKAK+BNvwoi/pqBbQPrPTcnaDw==", "menu"=>{"name"=>"Menu 1", "description"=>"First test menu", "recipe_ids"=>["", "1", "3", "4"]}, "
commit"=>"Update Menu", "id"=>"1"}
Menu Load (1.0ms) SELECT "menus".* FROM "menus" WHERE "menus"."id" = ? LIMIT 1 [["id", 1]]
Unpermitted parameter: recipe_ids
(1.0ms) begin transaction
(0.0ms) commit transaction
Redirected to http://localhost:3000/menus/1
Completed 302 Found in 11ms (ActiveRecord: 2.0ms)
I'm sure it is something simple I've missed. I have been scratching my head for a whole day on this. Can someone help?
I knew it was something simple. This takes care of the whole problem.
params.require(:menu).permit(:user_id, :name, :description, { :recipe_ids => [] } )
To add to your answer, there are a bunch of issues with your structure.
Object
You're calling setup_menu in your view; this should at least be called in your controller (unless you're using a partial... even then it should be passed as a local var).
<%= simple_form_for #menu do |f| %>
<%= f.hidden_field :user_id %>
<%= f.input :name %>
<%= f.input :description %>
<%= f.association :recipes %>
<%= f.button :submit %>
<% end %>
This has to be backed up with the appropriate controller action. Again, if you're using this in the likes of a partial, you'll be able to assign the action at the same time you're defining #menu:
#app/controllers/menus_controller.rb
class MenusController < ApplicationController
def new
#menu = setup_menu x
end
end
Associative Data
Because you're using a has_many :recipes association, you should be able to set :recipes in your strong params. Failing that, your recipe_ids should be okay, but I think your encapsulation in parentheses is incorrect:
params.require(:menu).permit(:user_id, :name, :description, recipe_ids: [])
As an aside, if you had a has_and_belongs_to_many relationship set up, you'll be able to pass recipes as follows:
params.require(:menu).permit(:user, :name, :description, :recipes)
I see no reason why this would not work for your has_many :through
Definitions
Finally, you should be able to set multiple definitions in your model for accepts_nested_attributes_for:
#app/models/menu.rb
class Menu < ActiveRecord::Base
has_many :courses
has_many :recipes, through: :courses
accepts_nested_attributes_for :recipes, :courses, reject_if: :all_blank
end
One of the most important, and simple, ways of keeping your code efficient is to make it readable. Above is an example of this - repeating yourself unnecessarily not only clutters your code, but prevents efficient management.
Related
This is a new error to me, and struggling to resolve it. It also states: Roaster(#70130698993440) expected, got "1" which is an instance of String(#70130675908140)
It's highlighting my create method in my Roasts Controller:
def create
#roast = Roast.new(roast_params)
The scenario is that I'm trying to create a triple nested form. for three models Roasts Countries and Regions where roasts has many countries and countries has many regions.
I'm assuming there is something wrong with the roast params, but I can see what it is. I have added the associations there for the nested models
def roast_params
params.require(:roast).permit(:roaster, :name, :bestfor, :beans, :roast, :tastingnotes, :notes, :slug, :avatar, :countries_attributes => [:country_name, :regions_attributes => [:region_name]])
end
my form
<div class="form-group">
<%= form.fields_for :countries do |countries_form| %>
<%= countries_form.label :country %>
<%= countries_form.text_field :name, class: "form-control" %>
</div>
<div class="form-group">
<%= form.fields_for :regions do |regions_form| %>
<%= regions_form.label :region %>
<%= regions_form.text_field :region_name, class: "form-control" %>
<% end %>
<% end %>
</div>
Roast Controller
...
def new
#roast = Roast.new
#roast.countries.build.regions.build
end
...
roast model
class Roast < ApplicationRecord
has_many :tastings
has_many :countries
has_many :notes, through: :tastings
has_many :comments, as: :commentable
belongs_to :roaster
accepts_nested_attributes_for :countries
country model
class Country < ApplicationRecord
has_many :regions, inverse_of: :country
accepts_nested_attributes_for :regions
belongs_to :roasts
region model
class Region < ApplicationRecord
belongs_to :country
I've nested the regions params in the country params, is that correct? I also saw on SO other issues with suggestions for setting config.cache_classes to true in development.rb but that didn't help here.
Update
So looking at this further, I believe it's not related to the nested forms, but rather a collection_select I'm using.
<%= form.label :roaster, class: 'control-label' %>
<%= form.collection_select(:roaster, Roaster.order(:roaster_name).all, :id, :roaster_name, prompt: true, class: "form-control") %>
So this select is pulling the roaster_name from a model called Roaster.
My params now look like the below:
params.require(:roast).permit(:roaster_name, :roaster, :name, :bestfor, :beans, :roast, :tastingnotes, :notes, :slug, :avatar, :countries_attributes => [:country_id, :country_name, :regions_attributes => [:region_id, :region_name]])
And looking at the console when submitting the form, it seems that just the :id of Roaster is getting passed, rather than the value of :roaster_name.
{"utf8"=>"✓",
"authenticity_token"=>"EG+zty85IiVsgipm1pjSAEZ7M66ELWefLq8Znux+cf89sSnVXxielRr1IaSS9+cJvdQD8g1D4+v2KqtKEwh6gw==",
"roast"=>{"roaster"=>"1", "name"=>"Espress", "countries_attributes"=>{"0"=>{"country_name"=>"UK"}}, "regions"=>{"region_name"=>"Highlands"}, "bestfor"=>"", "roast"=>"", "tastingnotes"=>""},
"commit"=>"Create Roast"}
Can't work this out
ActiveRecord::AssociationTypeMismatch is raised when an association-setter (Roast#roaster= in this case) is called with a value that is not an instance of the expected class. Roaster was expected, got String.
The issue seems to be with passing roaster in as a param, which is "1" (String) in your example. I'm guessing this is actually an ID of a Roaster, the form code in the question does not show it.
Perhaps you meant to permit and pass a roaster_id param?
def roast_params
params.require(:roast).permit(:roaster_id, # ...
end
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 am trying to sort comments into events using a has_many :through association using checkboxes however the selected events are not saved. Here are my models:
class Comment < ActiveRecord::Base
has_many :categorizations
has_many :events, :through => :categorizations
end
class Event < ActiveRecord::Base
has_many :categorizations
has_many :comments, :through => :categorizations
end
class Categorization < ActiveRecord::Base
belongs_to :comment
belongs_to :event
end
My comments form looks like this:
<%= simple_form_for [#post, #comment] do |f| %>
<%= f.input :title %>
<%= f.association :events, :as => :check_boxes %>
<%= f.submit "Save" %>
After reading this answer, I added this to my event and comment controllers with no luck:
def comment_params
params.require(:comment).permit(:post_id, :title, :categorization_ids => [])
end
Try:
def comment_params
params.require(:comment).permit(:post_id, :title, :event_ids => [])
end
It's hard to know what's going on though without recreating it or seeing server logs, Hopefully this will solve it.
I want to create a form that has nested attributes, which populates a record within a rich join table. (That created record within the rich join table of course should have the appropriate foreign keys.)
I have yet to find a thorough answer on creating nested form fields on a has_many :through relationship. Please help!
For this example, I have a user form. Within that form, I am also trying to populate a record within the users_pets table (rich join table).
Additional question: are rich join models supposed to be singular or plural? Example: app/models/owners_pets.rb or app/models/owners_pet.rb.
app/models/owner.rb
class Owner < ActiveRecord::Base
has_many :owners_pets, allow_destroy: true
has_many :pets, through: :owners_pets
end
app/models/pet.rb
class Pet < ActiveRecord::Base
has_many :owners_pets, allow_destroy: true
has_many :owners, through: :owners_pets
end
app/models/owners_pets.rb
class OwnersPet < ActiveRecord::Base
belongs_to :owners
belongs_to :pets
end
app/controller/owners.rb
def owner_params
params.require(:owner).permit(:first_name, owners_pets_attributes: [:id, :pet_name, :pet_id])
end
app/views/owners/_form.html.erb
<%= simple_form_for(#owner) do |f| %>
<%= f.input :first_name %>
<%= f.simple_fields_for :owners_pets do |ff|
<%= ff.input :pet_name %>
<% end %>
<div>
<%= f.button :submit %>
</div>
<% end %>
Here is the answer, thanks to a bunch of help from a mentor. It helps me to keep in mind that rich join naming conventions should NOT be pluralized at the very end, just like other non-rich-join models. Ex: book_page.rb NOT books_pages.rb. Even books_page.rb would work (just update your strong params and database table accordingly). The important part is that the entire model must follow the rails convention of the model being singular (no 's' on the end).
Below in the rich join model, I made the decision to name it the completely singular version: owner_pet.rb as opposed to the other version: owners_pet.rb. (Therefore of course, my database table is named: owner_pets)
app/models/owner.rb
class Owner < ActiveRecord::Base
has_many :owner_pets
has_many :pets, through: :owner_pets
accepts_nested_attributes_for :owner_pets, allow_destroy: true
end
app/models/pet.rb
class Pet < ActiveRecord::Base
has_many :owner_pets
has_many :owners, through: :owner_pets
end
app/models/owner_pet.rb
class OwnerPet < ActiveRecord::Base
belongs_to :owner
belongs_to :pet
end
app/controller/owners.rb
def new
#owner = Owner.new
#owner.owner_pets.build
end
private
def owner_params
params.require(:owner).permit(:first_name, owner_pets_attributes: [:_destroy, :id, :pet_name, :pet_id, :owner_id])
end
app/views/owners/_form.html.erb
<%= simple_form_for(#owner) do |f| %>
<%= f.input :first_name %>
<%= f.simple_fields_for :owner_pets do |ff| %>
<%= ff.input :pet_name %>
<%= ff.input :pet_id, collection: Pet.all, label_method: "pet_type" %>
<% end %>
<div>
<%= f.button :submit %>
</div>
<% end %>
Your join table is the problem:
It should be belongs_to :owners belongs_to :pets for the join table to work
Plus the rich join model should be pluralised, as in: owners_pets
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