I have a situation where I am getting the error
Unpermitted parameter: incorporation
however I have it listed in the strong params:
def company_params
params.require(:company).permit(:id, :name, :employee_stock_options, :options_pool, :state_corp, :street, :city, :state, :zip, :_destroy,
incorporation_attributes: [:title, :trademark_search, :user_id, :employee_stock_options, :final_submit, :submit, :_destroy],
names_attributes: [:id, :name_string, :suffix, :approved, :snapshot, :company_id, :_destroy],
There's a bit of a catch that might be contributing to the issue:
The controller in question is actually the Incorporation controller. But, as you might notice, we are using it to create a parent model Company, which has_one :incorporation. I realize that this is a bit odd, but I have reasons for wanting my models to be structured this way AND for using the incorporations_controller for doing it.
Accordingly, I have my form structured in the following way:
<%= simple_form_for #company, url: url_for(action: #caction, controller: 'incorporations'), html: {id:"incorporationform"}, remote: false, update: { success: "response", failure: "error"} do |company| %>
<%= company.simple_fields_for #incorporation do |f| %>
<div class="padded-fields">
<div class="form_subsection">
<%= f.input :trademark_search, as: :radio_buttons, label: 'Would you like us to do a trademark search and provide advice regarding any issues we identify in relation to the name you have selected?', input_html: { class: 'form-control radio radio-false' } %>
</div>
</div>
<% end %>
....
<% end %>
Thanks in advance for any insight
Update: My new and create methods are as follows in incorporations_controller
def new
#user=current_user
#company = #user.companies.build
#incorporation = #company.build_incorporation
#action = "new"
#caction = "create"
end
def create
#snapshot="incorporation"
#company = current_user.companies.build(company_params)
#incorporation = #company.build_incorporation
if #company.save
current_user.companies << #company
if params[:final_submit]
redirect_to incorporations_index_path
else
redirect_to edit_incorporation_path(#incorporation), notice: "Successfuly saved incorporation info."
end
else
render 'new', notice: "Something went wrong; form unable to be saved."
# render :nothing => true
end
end
Update 2: In Case it helps, here are the parameters from the log:
"company"=>{"names_attributes"=>{"145\2853672570"=>{"name_string"=>"test19", "suffix"=>"INC", "_destroy"=>"false"}}, "fiscal_year_end_month"=>"", "fiscal_year_end_day"=>"", "street"=>"", "city"=>"", "state"=>"", "zip"\=>"", "issued_common_stock"=>"10,000,000", "employee_stock_options"=>"false", "options_pool"=>"0", "incorporation"=>{"submit"=>"0"}}, "commit"=>"Save"}
I noticed that (unlike other nested attributes) incorporation does not have the _attributes line after it. Might that be of some significance?
Update3: I also seem to be creating an incorporation entry in the incorporations table with the proper ownership assigned. However no other fields are filled out.
You shouldn't have incorporation in your submitted params anyway - it should be incorporation_attributes (as you've already got in your strong params).
--
If you're using fields_for, you should expect [association]_attributes to be passed as a parameter from your form.
Not having it means you've either not got accepts_nested_attributes_for in your parent model, or you have not built your child object:
#app/models/company.rb
class Company < ActiveRecord::Base
has_one :incorporation
accepts_nested_attributes_for :incorporation
end
--
#app/controllers/incorporations_controller.rb
class IncorporationsController < ApplicationController
def new
#company = Company.new
#company.build_incorporation #-> only needed if a new record
end
def create
#company = Company.new company_params
#company.save
end
end
Update
What a strange issue you have - you're passing names_attributes fine and yet incorporation doesn't work.
The one thing I would say, after looking at your params, is that your incorporation is only passing "submit" => "0". I don't see what that is; anyway there are numerous issues with your form:
def new
#company = current_user.companies.new
#company.build_incorporation
...
end
def create
#company = current_user.companies.new company_params
#company.save #-> don't need to "build" in create
end
This will allow you to...
<%= simple_form_for #company, url: url_for(action: #caction, controller: 'incorporations'), html: {id:"incorporationform"}, remote: false, update: { success: "response", failure: "error"} do |company| %>
<%= company.simple_fields_for :incorporation do |f| %>
<%= f.input ...
<% end %>
When using fields_for, you only need to pass the parent object (in your case #company). Building incorporation will automatically populate fields_for without explicitly declaring it.
The error indicates that we need to define this in company model:
accepts_nested_attributes_for :incorporation
attr_accessible :incorporation_attributes
Related
My goal is to when adding a new product with the new product form, to have an input where one can add a list of emails separated by a space. The list of emails in this string field would be saved as an array of emails in the email_list array attribute of the Product model. This way each product has many emails. (later an email will be sent to these users to fill out questionaire, once a user fills it out there name will be taken off this list and put on completed_email_list array.
I am relatively new to rails, and have a few questions regarding implementing this. I am using postgresql, which from my understanding I do not need to serialize the model for array format because of this. Below is what I have tried so far to implement this. These may show fundamental flaws in my thinking of how everything works.
My first thinking was that I can in my controllers create action first take params[:email].split and save that directly into the email_list attribute (#product.email_list = params[:email].split. It turns out that params[:email] is always nil. Why is this? (this is a basic misunderstanding I have)(I put :email as accepted param).
After spending a long time trying to figure this out, I tried the following which it seems works, but I feel this is probably not the best way to do it (in the code below), which involves creating ANOTHER attribute of string called email, and then splitting it and saving it in the email_list array :
#product.email_list = #product.email.split
What is the best way to actually implement this? someone can clear my thinking on this I would be very grateful.
Cheers
Products.new View
<%= simple_form_for #product do |f| %>
<%= f.input :title, label:"Product title" %>
<%= f.input :description %>
<%= f.input :email %>
<%= f.button :submit %>
<%end %>
Products Controller
class ProductsController < ApplicationController
before_action :find_product, only: [:show, :edit, :update, :destroy]
def index
if params[:category].blank?
#products= Product.all.order("created_at DESC")
else
#category_id=Category.find_by(name: params[:category]).id
#products= Product.where(:category_id => #category_id).order("created_at DESC")
end
end
def new
#product=current_user.products.build
#categories= Category.all.map{|c| [c.name, c.id]}
end
def show
end
def edit
#categories= Category.all.map{|c| [c.name, c.id]}
end
def update
#product.category_id = params[:category_id]
if #product.update(product_params)
redirect_to product_path(#product)
else
render 'new'
end
end
def destroy
#product.destroy
redirect_to root_path
end
def create
#product=current_user.products.build(product_params)
#product.category_id = params[:category_id]
#product.email_list = #product.email.split
if #product.save
redirect_to root_path
else
render 'new'
end
end
private
def product_params
params.require(:product).permit(:title, :description, :category_id, :video, :thumbnail,:email, :email_list)
end
def find_product
#product = Product.find(params[:id])
end
end
To solve your original issue
#product.email_list = params[:email].split. It turns out that params[:email] is always nil
:email is a sub key of :product hash, so it should be:
#product.email_list = params[:product][:email].split
Demo:
params = ActionController::Parameters.new(product: { email: "first#email.com last#email.com" })
params[:email] # => nil
params[:product][:email] # => "first#email.com last#email.com"
I'd say that what you have is perfectly fine, except for the additional dance that you're doing in #product.email_list=#product.email.split, which seems weird.
Instead, I'd have an emails param in the form and an #emails= method in the model (rather than email and #email=):
def emails=(val)
self.email_list = val.split
end
Alternatively, you could do that in the controller rather than having the above convenience #emails= method, similar to the way you're handling the category_id:
#product = current_user.products.build(product_params)
#product.category_id = params[:category_id]
#product.email_list = product_params[:emails].split
Because you need validations on your emails and to make it cleaner I would create an email table, make Product table accept Email attribues and use cocoon gem to have a nice dynamic nested form with multiple emails inputs.
1) models
class Product < ActiveRecord::Base
has_many :emails, dependent: :destroy
accepts_nested_attributes_for :emails, reject_if: :all_blank, allow_destroy: true
end
class Email < ActiveRecord::Base
belong_to :product
validates :address, presence: true
end
2) Controller
class ProductsController < ApplicationController
def new
#product = current_user.products.build
end
def create
#product = current_user.products.build(product_params)
if #product.save
redirect_to root_path
else
render 'new'
end
end
private
def product_params
params.require(:project).permit(:title, :description, :category_id, :video, :thumbnail, emails_attributes: [:id, :address, :_destroy])
end
end
3) View
<%= simple_form_for #product do |f| %>
<%= f.input :title, label:"Product title" %>
<%= f.input :description %>
<%= f.association :category %>
<div id="emails">
<%= f.simple_fields_for :emails do |email| %>
<%= render 'emails_fields', f: email %>
<div class="links">
<%= link_to_add_association 'add email', f, :emails %>
</div>
<%= end %>
</div>
<%= f.button :submit %>
<% end %>
In your _emails_fields partial:
<div class="nested-fields">
<%= f.input :address %>
<%= link_to_remove_association "Remove email", f %>
</div>
Then setup cocoon's gem and javascript and you'll be good.
Reference: https://github.com/nathanvda/cocoon
I have looked at various answers to similar questions and haven't quite cracked it.
A wine model is defined with has_one :register, :dependent => :destroy and rightly or wrongly I have added accepts_nested_attributes_for :register. A register is defined with belongs_to :wine.
The code within wines_controller.rb for create is:
def new
#wine = Wine.new
#register = Register.new
def create
#wine = Wine.new(wine_params)
#register = #wine.registers.build(register_params)
respond_to do |format|
if #wine.save
#success
else
format.json { render json: #wine.errors, status: :unprocessable_entity }
format.json { render json: #register.errors, status: :unprocessable_entity }
end
end
end
My form for creating a new wine has the following code:
<%= simple_form_for #wine do |f| %>
# various working elements
<div class="field">
<% f.fields_for :register do |r| %>
<%= r.label :short_name %>
<%= r.text_field :short_name %>
<%= r.label :barcode %>
<%= r.text_field :barcode %>
<% end %>
</div>
When this form is called up no fields are created from the f.fields_for command but this block is executed because I can add test buttons within it to prove it is accessed.
If I try to create a wine I get the following error message:
undefined method `registers' for #<Wine:0x007f1204375330> Did you mean? register register= register_id
I believe that using .build is there to ensure data integrity: I don't want to create a wine that does not have a corresponding register. I have tried thinking about it nested attributes but that seems to be considered a bad plan by many. This current approach feels correct but I think I am missing some understanding of syntax at the very least.
At a later date it will be necessary to have other models linked to register that will not be associated to wines. I was considering a similar approach but I am happy to be told to rethink!
If I understand you correctly you have 2 issues:
Firstly fields for register aren't being displayed - this is partly because #wine.register is nil.
You should change your new action to:
def new
#wine = Wine.new
#wine.register = Register.new
In addition because you are using simple_form_for you will need to use simple_fields_for instead of fields_for
Your second issue that results in the exception tells you everything... you are trying to access #wine.registers, and not #wine.register
Change in your create method to:
#register = #wine.register.build(register_params)
This will fix that issue ... however ... all you really need to do is build the #wine object from your params - your params should be configured to permit the right nested attributes - if it is set up correctly the register object will also be built when building the #wine object.
Your model is already set to accept_nested_attributes and thus will also validate and save the register object when calling #wine.save - no need to explicitly save the register object.
You should have something like:
def wine_params
params.require(:wine).permit(
:attribute1, :attribute2,
register_attributes: [:id, :short_name, :barcode])
end
Try this
Wine and Register models
class Wine < ApplicationRecord
has_one :register, inverse_of: :wine, :dependent => :destroy
accepts_nested_attributes_for :register
end
class Register < ApplicationRecord
belongs_to :wine, inverse_of: :register
validates_presence_of :wine
end
Wines Controller
class WinesController < ApplicationController
def new
#wine = Wine.new
#wine.build_register
end
def create
#wine = Wine.new(wine_params)
if #wine.save
redirect_to #wine
else
render :new
end
end
private
def wine_params
params.require(:wine).permit(:name, register_attributes: [:simple_name])
end
end
My wine_params are specific for
rails g model wine name:string
rails g model register name:string wine_id:integer
Lastly wine form should look like this
<%= form_for #wine do |f|%>
<p>
<%= f.label :name%>
<%= f.text_field :name%>
</p>
<%= f.fields_for :register do |r|%>
<p>
<%= r.label :simple_name%>
<%= r.text_field :simple_name%>
</p>
<% end %>
<%= f.submit %>
<% end %>
So you can modify wine_params and form partial for your application specifics
I have a Post and a MaterielLink models.
A post has_many materiel_links, and accepts_nested_attributes_for :materiel_links
I use the gem cocoon to create a nested form: on the post form, I want to be able to add links that will be created on submit of the form.
post/new.html.erb:
<%= simple_form_for #post, :html => { :id => "post_form", "data-post-id" => #post.id } do |f| %>
<%= f.simple_fields_for :materiel_links do |materiel_link| %>
<%= render 'materiel_link_fields', f: materiel_link %>
<% end %>
<%= link_to_add_association 'Ajouter', f, :materiel_links%>
<% end %>
_materiel_link_fields.html.erb:
<%= f.fields_for :materiel_links do |materiel_link| %>
<%= materiel_link.text_field :name %>
<%= materiel_link.text_field :link %>
<% end %>
In my post controller:
def update
#materiel_links = #post.materiel_links.build(post_params[:materiel_links_attributes]
if #post.update!(post_params)
session[:current_draft_post_id] = nil
redirect_to post_path(#post)
else
render :new
end
end
I am here in the update action since, for reasons specific to my rails app, the post is created when the posts/new page is rendered (It is created empty, and the user just updates it instead of actually creating it). So the post already exists, but not the materiel_links that I have to create in the update action.
And the params:
def post_params
params.require(:post).permit(:title, materiel_links_attributes: [:name,:link] )
end
I added a raise in the update action, and what is stange is that I can find the link/name for each materiel_link I've added when I type params but with a number before each couple:
>> params
{"utf8"=>"✓", "_method"=>"patch", "authenticity_token"=>"wqzWfaAcwrOOdxViYBO5HaV2bwsNsf5HsvDFEbBYapkOMAPXOJR7oT4zQHbc/hTW8T9a+iH5NRl1WUApxrIjkA==", "post"=>{"title"=>"my title", "materiel_links_attributes"=>{"1459431927732"=>{"materiel_links"=>{"name"=>"mon Lien 1", "link"=>"htttp1"}}, "1459431933881"=>{"materiel_links"=>{"name"=>" Mon lien 2", "link"=>"htttp2"}}}}, "controller"=>"posts", "action"=>"update", "id"=>"1250"}
But nothing in the materiel_links hashes when I type post_params:
>> post_params
=> {"title"=>"my title","materiel_links_attributes"=>{"1459431927732"=>{}, "1459431933881"=>{}}}
The instances of MaterielLink are created, but they are empty: they don't save the link/name.
Where did I go wrong ?
My guess is that because in your update action you used .build before .update, it somehow conflicted with .update because the materiel_links values are passed there once again. You do not need to build in update action anymore; but only in edit action, because the materiel_links will be automatically created/updated when .update(post_params) is called, as post_params already include materiel_links values. Try
def update
if #post.update!(post_params)
#materiel_links = #post.materiel_links
session[:current_draft_post_id] = nil
redirect_to post_path(#post)
else
render :new
end
end
You'd also need whitelist the ID of materiel_link in strong params, so that these materiel_links in the form can be updated (ID not needed to be whitelisted if just create, and no update). You might also want to allow destroy. Update into the following:
def post_params
params.require(:post).permit(:title, materiel_links_attributes: [:id, :name, :link, :_destroy] )
end
# post.rb
accepts_nested_attributes_for :materiel_links, allow_destroy: true
There are many related question on SO. I went through all of them but still struggle with my situation.
I have two models User and Booking
#model/user.rb
has_many :bookings
#modle/booking.rb
belongs_to :user
I want to create a booking and a user at the same time. If the user already exist, just add the new booking to the existing user.
My form for creating booking:
<%= simple_form_for :booking, url: bookings_path, :method => :post, do |f| %>
<%= f.fields_for :user, do |ff| %>
<%= ff.input_field :first_name %>
<%= ff.input_field :last_name %>
<%= ff.input_field :email %>
<%= ff.input_field :phone %>
<% end %>
...
<% end %>
And in the booking controller
#control/bookings_controller.rb
def create
#user = User.find_by(:email => booking_params[:user][:email])
if #user == nil
#user = User.new(booking_params[:user])
#user.username = User.autousername(#user)
#user.password = Devise.firendly_token(8)
else
#user.update(booking_params[:user])
end
#user.save
b_params = booking_params
b_params.delete("user")
#booking = Booking.new(b_params)
#booking.user_id = #user.id
#booking.save
...
end
def booking_params
params.require(:booking).permit(:status, :house_id, :check_in, :check_out, :adult_guest, :children_guest, :temp_profit,
:note, :check_in_note, :user => [:first_name, :last_name, :email, :phone])
end
I didn't use nested_attributes because I want to generate username and password myself rather than collect them using form.
What I got is ActiveRecord::AssociationTypeMismatch in BookingsController#create
User(#70121505047640) expected, got ActionController::Parameters(#70121556154400)
Most SO related problems want to create the child object under parent controller. In my case, it's reversed.
UPDATE
After trying every possible way, I found out that the CanCanCan load_and_authorize_resource seems to be the trouble maker. If I comment out it in my bookings_controller, everything works fine. Could someone tell me why?
Solution
Finally, I found out the reason. I'm using CanCanCan load_and_authorize_resource in my booking_controller. In order to create nested user instance under it, I have to load user resources. Just add load_and_authorize_resource :user will solve the problem!
Thanks for all the answers. Hope this will help people with the same problem.
This is probably happening when you try to do the #booking.save. Because you have a user param, it will try to use the user= to set it. In this case, the user= will apply a params object.
Try to delete the user param from the booking_params when you create the booking.
b_params.delete(:user)
or
b_params[:user] = #user
My nested form is not working properly no matter what I try and I searched all the StackExchange's for a solution to this seemingly easy problem. This is where I am right now to get it to work at show up in the view at all.
The form is using the Event controller create action from a non-restful location, hence the global variable (a pages controller, with a specific page, where the form is generated). My ticket model gets generated when the nested form is submitted, and the Event ID gets passed, but it doesn't fill in the "Name" field for the ticket model because it says "Unpermitted Parameters: Ticket." But they're defined as whitelisted in the Events controller! Argh! I'm thinking something is wrong with the form, but nothing I try seems to work.
Any help would be appreciated.
* UPDATED CODE THAT IS NOW WORKING *
Form.html.erb:
<div class="form-inputs">
<%= simple_form_for #event, :html => { :class => 'form-horizontal' } do |f| %>
<div class="row">
<div class="col-xs-6">
<%= f.input :name, class: "control-label" %>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<%= f.simple_fields_for :tickets do |ticket| %>
<%= ticket.input :name %>
<% end %>
</div>
</div>
<div class="form-actions">
<%= f.button :submit, :class => 'btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
launchpad_path, :class => 'btn btn-default' %>
<% end %>
</div>
</div>
Event_Controller.rb
def new (this is totally skipped and unnecessary)
#event = Event.new
#ticket = #event.tickets.build
end
def create
#event = current_user.events.build(event_params)
respond_to do |format|
if #event.save
format.html { redirect_to #event, notice: 'Your event was created.' }
else
format.html { render :new }
end
end
end
def event_params
params.require(:event).permit(:name, tickets_attributes: [ :name, :id, :event_id, :_destroy ])
end
Pages_Controller.rb (where the form originate
def new
#event = Event.new
#ticket = #event.tickets.build
end
Event.rb
class Event < ActiveRecord::Base
# Database Relationships
has_many :tickets, dependent: :destroy
accepts_nested_attributes_for :tickets, :allow_destroy => true
end
Ticket.rb
class Ticket < ActiveRecord::Base
belongs_to :event
end
Routes.rb
resources :events do
resources :tickets
end
As well as the information from Alejandro (which is correct), you also have f.simple_fields_for #ticket, ... whereas you should have f.simple_fields_for :tickets, ...
If you check your log/development.log for the Processing by EventsController#create the line after will be a Parameters: line, you'll see that the parameters that have been sent through are under a :ticket key instead of a :tickets_attributes key because of the fields_for error.
Fix that, and the permit line and you should be fine.
Update
Hopefully you realized that you also don't need the #ticket = #event.tickets.build(event_params[:ticket_attributes]) line at all once that fields_for is fixed too. The setting of all the associated tickets is all done via the Event object thanks to the accepts_nested_attributes_for helper.
Just, remove from create action this line:
#ticket = #event.tickets.build(event_params[:ticket_attributes])
And, change your event_params:
def event_params
params.require(:event).permit(:name, :main_event_image, tickets_attributes: [:id, :name, :cost, :event_id, :registration_id, :created_at])
end
Te field name must be: tickets_attributes: [ ... (tickets in plural). I think this do the trick.
Edit: I'm agree with #smathy, if no fix to f.simple_fields_for :tickets ... it can't work.
Your new method must look like this:
def new
#new_event = Event.new
#new_event.tickets.build
end
I'm a fan of standards, and I prefer use #event instead of #new_event as in your form (it's part of convention over configuration on rails)
I was stuck at the same problem like crazy and at the end I was able to fix it... Try placing the binding.pry in the first line of create method and print the event_params hash and check if you see ticket_attributes hash inside of it ... That's when it ll throw unpermitted parameter ... And I see event has_many tickets , so I am guessing ticket_attributes needs to be pluralized to be tickets_attributes