Unknown parameter in Rails 5.1 strong parameters issue - ruby-on-rails

So my reconciliation model looks like this:
class Reconciliation < ApplicationRecord
belongs_to :location
belongs_to :company
has_and_belongs_to_many :inventory_items
accepts_nested_attributes_for :inventory_items, allow_destroy: true
end
My InventoryItem model looks like this:
class InventoryItem < ApplicationRecord
belongs_to :product
belongs_to :location, inverse_of: :inventory_items
has_and_belongs_to_many :reconciliations
end
In my ReconciliationsController, this is what my reconciliation_params looks like:
def new
#location = Location.find(params[:location_id])
#reconciliation = #location.reconciliations.new
#inventory_items = #location.inventory_items
#start_index = 0
#next_index = #start_index + 1
end
def reconciliation_params
params.require(:reconciliation).permit(:inventory_item_id, :location_id, :display_id, :inventory_items,
inventory_items_attributes: [:id, :quantity_left, :quantity_delivered, :_destroy]
)
end
This is the relevant section of my routes.rb:
resources :locations, shallow: true do
resources :inventory_items
resources :reconciliations
end
This is my views/reconciliations/_form.html.erb:
<%= simple_form_for #reconciliation, url: :location_reconciliations do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :location_id, as: :hidden %>
<%= f.simple_fields_for :inventory_item do |inventory| %>
<%= inventory.input :quantity_left %>
<%= inventory.input :quantity_delivered %>
<% end %>
</div>
<div class="form-actions">
<%= f.button :submit, "Update", class: "btn btn-primary" %>
</div>
<% end %>
This is my app/views/reconciliations/new.html.erb:
<% if params[:next].nil? %>
<%= render 'form', reconciliation: #reconciliation, inventory_item: #inventory_items[#start_index] %>
<% else %>
<%= render 'form', reconciliation: #reconciliation, inventory_item: #inventory_items[#next_index] %>
<% end %>
This is my log when I try to create a reconciliation object:
Started POST "/locations/2/reconciliations" for 127.0.0.1 at 2018-03-24 23:16:33 -0500
Processing by ReconciliationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"JZvhwloo0+XM9bmptxXGfnDw==", "reconciliation"=>{"location_id"=>"2", "inventory_item"=>{"quantity_left"=>"1", "quantity_delivered"=>"170"}}, "commit"=>"Update", "location_id"=>"2"}
Unpermitted parameter: :inventory_item
Location Load (0.9ms) SELECT "locations".* FROM "locations" WHERE "locations"."id" = $1 LIMIT $2 [["id", 2], ["LIMIT", 1]]
(0.6ms) BEGIN
(0.7ms) ROLLBACK
Rendering reconciliations/new.html.erb within layouts/application
InventoryItem Load (1.0ms) SELECT "inventory_items".* FROM "inventory_items" WHERE "inventory_items"."location_id" = $1 [["location_id", 2]]
Product Load (1.0ms) SELECT "products".* FROM "products" WHERE "products"."id" = $1 LIMIT $2 [["id", 2], ["LIMIT", 1]]
Rendered reconciliations/_form.html.erb (45.9ms)
Rendered reconciliations/new.html.erb within layouts/application (66.8ms)
Rendered shared/_navbar.html.erb (1.3ms)
Completed 200 OK in 202ms (Views: 115.1ms | ActiveRecord: 29.1ms)
I have tried simply adding :inventory_item to my params.require(:reconciliation).permit(..), but that doesn't work.
What am I missing?
Edit 1
When I checked the HTML for the inputs on my form, within the simple_fields_for, the HTML seems to be fine:
<input class="string required" type="text" name="reconciliation[inventory_item][quantity_left]" id="reconciliation_inventory_item_quantity_left">
Edit 2
When I change the simple_fields_for call to be plural, i.e. :inventory_items, rather than :inventory_item like this:
That entire portion of the form disappears altogether.
This is what the HTML looks like:
<div class="form-inputs">
<div class="input hidden reconciliation_location_id"><input class="hidden" type="hidden" value="2" name="reconciliation[location_id]" id="reconciliation_location_id"></div>
</div>
This is how the HTML looks when that simple_field_for :inventory_item is singular:
<div class="form-inputs">
<div class="input hidden reconciliation_location_id"><input class="hidden" type="hidden" value="2" name="reconciliation[location_id]" id="reconciliation_location_id"></div>
<div class="input string required reconciliation_inventory_item_quantity_left"><label class="string required" for="reconciliation_inventory_item_quantity_left"><abbr title="required">*</abbr> Quantity left</label><input class="string required" type="text" name="reconciliation[inventory_item][quantity_left]" id="reconciliation_inventory_item_quantity_left"></div>
<div class="input string required reconciliation_inventory_item_quantity_delivered"><label class="string required" for="reconciliation_inventory_item_quantity_delivered"><abbr title="required">*</abbr> Quantity delivered</label><input class="string required" type="text" name="reconciliation[inventory_item][quantity_delivered]" id="reconciliation_inventory_item_quantity_delivered"></div>
</div>

I have tried simply adding :inventory_item to my params.require(:reconciliation).permit(..), but that doesn't work.
If you want permit inventory_item, you must specify its structure, because it is not a simple field, but a hash:
def reconciliation_params
params.require(:reconciliation).permit(:location_id, :display_id, inventory_item: [:id, :quantity_left, :quantity_delivered] )
end
By looking at your log, you are not passing the inventory_item_id, which might be needed to update this specific item:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"JZvhwloo0+XM9bmptxXGfnDw==",
"reconciliation"=>{"location_id"=>"2", "inventory_item"=>
{"quantity_left"=>"1", "quantity_delivered"=>"170"}},
"commit"=>"Update", "location_id"=>"2"}
You could add it as a hidden field in the nested form.

Form of association should be plural f.simple_fields_for :inventory_items.
You should initialize a new inventory_item object in the new controller's action
def new
#reconciliation = Reconciliation.new
# you can create as many new items as you want
#reconciliation.inventory_items.build
end
If you want to dynamically add items to the form i advise you to use https://github.com/nathanvda/cocoon
BUT it looks like you want to add existing inventory_item to a new reconciliation, you better use has_many through assocations http://guides.rubyonrails.org/association_basics.html#choosing-between-has-many-through-and-has-and-belongs-to-many
Its easier to add a join model objects with neccessary fields and associations.
Another advise: do not send local variable to partial if you are using instance variable in this partial
# render partial
render 'form', reconciliation: #reconciliation
# partial with form for local variable
simple_form_for reconciliation
and i think your form partial will not work for the edit action because of hardcoded url, you can pass url in a variable:
# new html
render 'form', reconciliation: #reconciliation, url_var: location_reconciliations(#location)
# edit
render 'form', reconciliation: #reconciliation, url_var: reconciliations(#reconciliation)
# form
simple_form_for reconciliation, url: url_var

Related

Devise after_sign_up_for path not working

I read all the thread on this, but I still can't figure out what is wrong. I have gone through all the devise implementation guides and followed them but after a new user registration, the redirect goes to the users controller, specifically users#show.
The initial call to a new registration is going through my registrations controller. That has been verified. But after the registration it doesn't pass through the registrations controller again. It goes through the users controller. I put a break in the two overriding methods in the new registrations controller and they never hit.
/routes.rb
Rails.application.routes.draw do
root to: 'app#index'
devise_for :users, controllers: { registrations: "registrations" }
resources :users do
member do
put 'follow', to: 'users#follow'
put 'unfollow', to: 'users#unfollow'
end
end
end
registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
protected
#call for new registration does pass through here
#after new registration does not pass through here
def after_inactive_sign_up_path_for(resource)
#never gets here after new registration
other_path(resource)
end
def after_sign_up_path_for(resource)
#never gets here after new registration
other_path(resource)
end
end
new registration form:
<form action="index.html">
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="form-group">
<%= f.email_field :email, autofocus: true, placeholder: "Email", class: "form-control rounded input-lg text-center no-border" %>
</div>
<div class="form-group">
<% if #minimum_password_length %>
<em>(<%= #minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "off", placeholder: "Password", class: "form-control rounded input-lg text-center no-border" %>
</div>
<div class="form-group">
<%= f.password_field :password_confirmation, autocomplete: "off", placeholder: "Confirm Password", class: "form-control rounded input-lg text-center no-border" %>
</div>
<div class="checkbox i-checks m-b">
<label class="m-l">
<input type="checkbox" checked=""><i></i> Agree the terms and policy
</label>
</div>
<button type="submit" class="btn btn-lg btn-warning lt b-white b-2x btn-block btn-rounded"><i class="icon-arrow-right pull-right"></i><span class="m-r-n-lg">Sign up</span></button>
<% end %>
<div class="text-center m-t m-b"><small><%= link_to "Already have an account?", new_session_path(resource_name) %></small></div>
console:
Started GET "/users/index.html?utf8=%E2%9C%93&authenticity_token=KlAk4ctYpw%2F2eHGqZ0OsAymf5BxUPxeBiFzeOatn2JDUQJdPk8fGoB%2BmuN4oeN3KviQdVwN%2FxMfnjH4zIVooOg%3D%3D&user%5Bemail%5D=asdf%40asdf.com&user
%5Bpassword%5D=[FILTERED]&user%5Bpassword_confirmation%5D=[FILTERED]" for ::1 at 2016-10-25 22:10:37 -0400
Processing by UsersController#show as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"KlAk4ctYpw/2eHGqZ0OsAymf5BxUPxeBiFzeOatn2JDUQJdPk8fGoB+muN4oeN3KviQdVwN/xMfnjH4zIVooOg==", "user"=>{"email"=>"asdf#asdf.com", "password"=>"[FILTERED]
", "password_confirmation"=>"[FILTERED]"}, "id"=>"index"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 0], ["LIMIT", 1]]
Completed 404 Not Found in 3ms (ActiveRecord: 0.3ms)
ActiveRecord::RecordNotFound (Couldn't find User with 'id'=index):
app/controllers/users_controller.rb:6:in `show'
Rendering /Users/Joe/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout
Rendering /Users/Joe/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_source.html.erb
Rendered /Users/Joe/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_source.html.erb (3.7ms)
Rendering /Users/Joe/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
Rendered /Users/Joe/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (1.8ms)
Rendering /Users/Joe/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
Rendered /Users/Joe/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (2.0ms)
Rendered /Users/Joe/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (69.3ms)
request params:
{"utf8"=>"✓",
"authenticity_token"=>"KlAk4ctYpw/2eHGqZ0OsAymf5BxUPxeBiFzeOatn2JDUQJdPk8fGoB+muN4oeN3KviQdVwN/xMfnjH4zIVooOg==",
"user"=>{"email"=>"asdf#asdf.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"},
"id"=>"index",
"format"=>"html"}
If you want to go to users#show, the correct path helper should be user_path(resource), is it what you want?
It looks like the issue is two-fold. The registrations controller is looking for the incorrect path but it also needs a proper id. I think the solution here is to pass it user_path(#user.id) instead of having resource as an argument where you have it in new_user_path(resource).
It's attempting to query for a User that has an ID of "Index" which doesn't exist and therefore it's throwing an error. You'll want to find the id of your new user and insert that to the route so that it finds that specific User profile. I used #user as an example. You can define that variable in the code or work with whatever variable you wish. I hope that helps!

Rails 4 nested attribute hash keys showing as unpermitted

I have a Category model and a Standard model. A category has many standards through a "join table" model CategoryStandard. In my view, I have a form where I can edit the category description, and then add or remove standards from that category. So, my nested attributes are for :category_standards, because I'm not editing the standard itself, just adding or removing relationships, if that makes sense.
Here's the important part of the view:
<%= form_for(#category) do |f| %>
...
<div class="field">
<%= f.label :description %>
<%= f.text_field :description %>
</div>
<%= label_tag nil, "Standards in this Category" %>
<div id="standard-list">
<%= f.fields_for :category_standards do |ff| %>
<div class="field">
<%= ff.object.standard.number_with_exceptions %>
<%= ff.hidden_field :standard_id %>
<%= ff.hidden_field :_destroy %>
<%= link_to "<span class='glyphicon glyphicon-remove'></span>".html_safe, "", class: "del-std-btn", title: "Remove standard from category" %>
</div>
<% end %>
<div class="hidden" id="std-add-new-template">
<div class="field">
<%= f.fields_for :category_standards, CategoryStandard.new, child_index: "new_id" do |ff| %>
<%= ff.collection_select :standard_id, #standards - #category.standards, :id, :number_with_exceptions, prompt: "Select a standard to add" %>
<% end %>
</div>
</div>
</div>
...
<% end %>
There's some jQuery under the hood to manipulate the "rows", but that works fine and I don't think it's part of my problem, so I'll omit it.
In my Category model, I have:
class Category < ActiveRecord::Base
has_many :category_standards, dependent: :destroy
has_many :standards, through: :category_standards
validates :description, presence: true,
uniqueness: true
accepts_nested_attributes_for :category_standards, allow_destroy: true, reject_if: proc { |attributes| attributes['standard_id'].blank?}
end
And in my Categories controller, I have:
def category_params
params.require(:category).permit(:description, category_standards_attributes: [:id, :standard_id, :_destroy])
end
But when I try to add a standard to a category, I get these lines in my server log (reformatted in the hopes of making it more readable):
Parameters: {"utf8"=>"✓",
"authenticity_token"=>"***********",
"category"=>{
"description"=>"Drinking Water System Components",
"category_standards_attributes"=>{
"0"=>{
"standard_id"=>"2",
"_destroy"=>"false",
"id"=>"1"
},
"new_id"=>{
"standard_id"=>""
},
"1424899001814"=>{
"standard_id"=>"1"
}
}
},
"commit"=>"Save Changes",
"id"=>"2"
}
User Load (5.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
Category Load (4.0ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = $1 LIMIT 1 [["id", "2"]]
Unpermitted parameters: 0, new_id, 1424899001814
(4.0ms) BEGIN
Category Exists (6.0ms) SELECT 1 AS one FROM "categories" WHERE ("categories"."description" = 'Drinking Water System Components' AND "categories"."id" != 2) LIMIT 1
SQL (6.0ms) UPDATE "categories" SET "description" = $1, "updated_at" = $2 WHERE "categories"."id" = 2 [["description", "Drinking Water System Components"], ["updated_at", Wed, 25 Feb 2015 21:16:44 UTC +00:00]]
It updates the description field just fine, but what's up with the Unpermitted parameters? My attributes hash comes out just like the example in the Rails Guide on nested forms, and it even says "The keys of the :addresses_attributes hash are unimportant, they need merely be different for each address." And yet it's the keys that are getting denied for me.
Where have I gone wrong? Thanks!
Figured it out, after a lot of reading. The missing piece was here.
Hashes with integer keys are treated differently and you can declare the attributes as if they were direct children. You get these kinds of parameters when you use accepts_nested_attributes_for in combination with a has_many association:
# To whitelist the following data:
# {"book" => {"title" => "Some Book",
# "chapters_attributes" => { "1" => {"title" => "First Chapter"},
# "2" => {"title" => "Second Chapter"}}}}
params.require(:book).permit(:title, chapters_attributes: [:title])
The important part of that was "Hashes with integer keys". My hash keys were passing as "0", "new_id", "1240934304343". It isn't important that I use "new_id", because that's just a placeholder value that gets changed in my jQuery when new rows are added. Only the template row retains that value, which is fine, because it gets filtered out by my reject_if clause.
But the fact that "new_id" isn't an integer apparently was the thing that was mucking it all up. So I changed it to "-1", which Rails accepts (even though it is still filtered out by reject_if, as it should be).
<div class="hidden" id="std-add-new-template">
<div class="field">
<%= f.fields_for :category_standards, CategoryStandard.new, child_index: "-1" do |ff| %>
<%= ff.collection_select :standard_id, #standards - #category.standards, :id, :number_with_exceptions, prompt: "Select a standard to add" %>
<% end %>
</div>
</div>
Your attribute keys don't seem to match what you are expecting in your strong parameters, "new_id" and "1424899001814" certainly will not be permitted.
"new_id"=>{
"standard_id"=>""
},
"1424899001814"=>{
"standard_id"=>"1"
}
I suspect the way you are constructing your form is invalid. Try breaking it down to the simplest working form.. like:
<div id="standard-list">
<%= link_to "<span class='glyphicon glyphicon-remove'></span>".html_safe, "", class: "del-std-btn", title: "Remove standard from category" %>
<div class="hidden" id="std-add-new-template">
<div class="field">
<%= f.fields_for :category_standards do |ff| %>
<%= ff.object.standard.number_with_exceptions %>
<%= ff.hidden_field :standard_id %>
<%= ff.hidden_field :_destroy %>
<%= ff.collection_select :standard_id, #standards - #category.standards, :id, :number_with_exceptions, prompt: "Select a standard to add" %>
<% end %>
</div>
</div>
</div>
The intention is to have only one nested form, and by stripping it down create only one nested hash.
"category_standards_attributes"=>{
"0"=>{
"standard_id"=>"2",
"_destroy"=>"false",
"id"=>"1"
}
}
What happens with this?

Trying to insert data for models that has polymorphic associations

I'm having a problem in trying to insert data into the db which has complex form involving two models and I searched every post on Stackoverflow to find the best possible answer, but I couldn't get anywhere near close in getting it right.
In my Models
class ClientIndividual < ActiveRecord::Base
has_one :client_assignment, :as => :clientassignmentable
accepts_nested_attributes_for :client_assignment
end
class ClientAssignment < ActiveRecord::Base
belongs_to :clientassignmentable, :polymorphic => true
end
In my ClientIndividual Controller
class ClientIndividualsController < ApplicationController
before_action :set_client_individual, only: [:show, :edit, :update, :destroy]
before_filter :authenticate_user!
def new
#client_individual = ClientIndividual.new
end
def create
#client_individual = ClientIndividual.new(client_individual_params)
respond_to do |format|
if #client_individual.save
format.html { redirect_to #client_individual, notice: 'Client individual was successfully created.' }
format.json { render action: 'show', status: :created, location: #client_individual }
else
format.html { render action: 'new' }
format.json { render json: #client_individual.errors, status: :unprocessable_entity }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_client_individual
#client_individual = ClientIndividual.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def client_individual_params
params.require(:client_individual).permit(:title, :first_name, :middle_name,
:last_name, :date_of_birth, :work_phone, :home_phone, :mobile_phone, :email_address,
:preferred_contact_type, :residential_address, :residential_suburb, :residential_state,
:residential_postcode, :same_as_residential, :postal_address, :postal_suburb,
:postal_state, :postal_postcode, :emergency_contact_person, :emergency_phone_no,
:industry_type, :has_referral, :notes, clientassignmentable_attributes:
[:assignment_types_id, :employees_id, :start_date, :manager_id, :client_type] )
end
end
In my Client_Individual#new view
<%= form_for(#client_individual) do |f| %>
<div class="add_data_section">
<%= f.fields_for (:clientassignmentable) do |client_assignment_form| %>
........
........
<div class="row_container">
<div class="field 1" style="width: 409px;">
<%=client_assignment_form.label :assignment_types_id, "Assignment Type*"%>
</div>
<div class="dropdown">
<label>
<%= select('client_individual[clientassignmentable]', 'assignment_types_id', AssignmentType.all.collect {|assignment_type| [assignment_type.name, assignment_type.id ] }, {prompt: 'Select Assignment Type'}, :style =>"width: 264px;")%>
</label>
</div>
</div>
<div class="row_container">
<div class="field " style="width: 409px;">
<%=client_assignment_form.label :start_date, "Assignment Start Date"%>
</div>
<div class="inputfield">
<%=client_assignment_form.text_field :start_date, :class=>'assignmentdatepicker', :style=>'width: 260px;'%>
</div>
</div>
<div class="row_container">
<div class="field " style="width: 409px;">
<%=client_assignment_form.label :manager_id, "Manager Appointed*"%>
</div>
<div class="dropdown">
<label>
<%= select('client_individual[clientassignmentable]', 'manager_id', Employee.all.select{ |manager| manager.staff_rank_id == 2}.collect{|employee| [employee.first_name + " " + employee.last_name, employee.id ] }, {prompt: 'Select ManagerList'}, :style =>"width: 264px;")%>
</label>
</div>
</div>
<div class="row_container">
<div class="field 1" style="width: 409px;">
<%=client_assignment_form.label :employees_id, "Staff Appointed*"%>
</div>
<div class="dropdown">
<label>
<%= select('client_individual[clientassignmentable', 'employees_id', Employee.all.select{ |employee| employee.user_id == current_user_id}.collect{|employee| [employee.first_name + " " + employee.last_name, employee.id ] }, {prompt: 'Select CurrentUser'}, :style =>"width: 264px;")%>
</label>
</div>
</div>
<%=client_assignment_form.hidden_field :client_type%>
<% end %>
......
<% end %>
So what I have is that I got a ClientIndividual Model that has one ClientAssignment Model. So the ClientAssignment Model has ClientIndividual FK thus upon creating a new ClientIndividual data, I would expect a new ClientAssignment data that gets generated on the form. Thus in my controller, I declare my strong params like so
clientassignmentable_attributes: [:assignment_types_id, :employees_id, :start_date, :manager_id, :client_type]
But I click to save the new data, nothing's inserted into the db...
Then I check my development.log and it said the following.
Started POST "/client_individuals" for 127.0.0.1 at 2014-03-30 19:58:52 +1100
Processing by ClientIndividualsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"0Z+BJcjQE7oa+uzdo/2sKRPiV01EQDXfedMkLE7pTjg=", "groups"=>{"id"=>"1"}, "client_individual"=>{"clientassignmentable"=>{"assignment_types_id"=>"1", "start_date"=>"03/31/2014", "manager_id"=>"13", "employees_id"=>"25", "client_type"=>""}, "title"=>"t", "first_name"=>"t", "middle_name"=>"t", "last_name"=>"t", "date_of_birth"=>"", "work_phone"=>"", "home_phone"=>"", "mobile_phone"=>"", "email_address"=>"admin#example.com", "residential_address"=>"t", "residential_suburb"=>"t", "residential_state"=>"t", "residential_postcode"=>"t", "same_as_residential"=>"0", "postal_address"=>"t", "postal_suburb"=>"t", "postal_postcode"=>"t", "emergency_contact_person"=>"", "emergency_phone_no"=>"22223", "industry_type"=>"", "notes"=>""}, "CREATE"=>"Create Client"}
[1m[36mUser Load (0.7ms)[0m [1mSELECT `users`.* FROM `users` WHERE `users`.`id` = 1 ORDER BY `users`.`id` ASC LIMIT 1[0m
Unpermitted parameters: clientassignmentable
[1m[35m (0.3ms)[0m BEGIN
[1m[36m (0.2ms)[0m [1mROLLBACK[0m
I keep getting this unpermitted parameters: clientassignmentable. But I've already whitelisted in the my controller as one of the strong params so why is it complaining???
Surely this couldn't be hard to figure out if you know what's the correct association laid out in front of you already?
What else could I be missing?!?! I've been on this for the whole day, looking very confused....
You should write
fields_for :client_assignment
and change this accordingly everywhere else you use :clientassignmentable
further reading:
http://guides.rubyonrails.org/form_helpers.html#understanding-parameter-naming-conventions
http://guides.rubyonrails.org/association_basics.html#polymorphic-associations
To solve the problem with fields not rendering in new form, in controller you need to do
#client_individual.build_client_assignment
I think where I did go wrong with this.....
It's so embarrassing after reading the basics of setting up polymorphic associations, I realised my polymorphic association was completely utterly wrong!!
As a consequence of that, I wasted almost 2 days of trying to save the form's data when clearly my initial steps of database design was utterly wrong! What a complete utter waste!!!
ARRRGGGH!!!!!
Now I need to go back to the drawing board and find what how to revert it!!!

Saving multiple records with params.require in ruby

I'm trying to update multiple records. The form generates fine and submits fine and the data is sent. The records are looked up to update, but no data is ever saved. I have my controller logic, form logic and console dump below. I'm trying to duplicate what Anthony Lewis put together but I have a feeling I am not passing the right data into or defining correctly the params.require().permit() method. Thanks in advance for your help!
class ConfigController < ApplicationController
def edit
#services = Service.all
end
def update
params["service"].keys.each do |id|
#service = Service.find(id.to_i)
#service.update_attributes!(service_params)
end
redirect_to config_url
end
private
def service_params
params.require(:service).permit(:id, :client_id, :client_secret)
end
end
Form code is:
<%= form_for :service, :url => update_config_path, :html => { :class => "form-horizontal", :method => "put", :remote => true } do %>
<% #services.each do |s| %>
<%= fields_for "service[]", s do |service_field| %>
<fieldset>
<legend><%= s.name %></legend>
<div class="form-group">
<%= service_field.label :client_id, "Consumer Key", :class => "col-sm-2 control-label" %>
<div class="col-sm-10">
<%= service_field.text_field :client_id, :class => "form-control" %>
</div>
</div>
<div class="form-group">
<%= service_field.label :client_secret, "Consumer Secret", :class => "col-sm-2 control-label" %>
<div class="col-sm-10">
<%= service_field.text_field :client_secret, :class => "form-control" %>
</div>
</div>
</fieldset>
<% end %>
<% end %>
<%= submit_tag %>
<% end %>
Console reads:
Started PUT "/config" for 127.0.0.1 at 2013-11-22 15:44:08 -0800
Processing by ConfigController#update as JS
Parameters: {"utf8"=>"✓", "service"=>{"1"=>{"client_id"=>"testid", "client_secret"=>"testsecret"}, "2"=>{"client_id"=>"testkey", "client_secret"=>""}, "3"=>{"client_id"=>"", "client_secret"=>""}}, "commit"=>"Save changes"}
Service Load (0.3ms) SELECT "services".* FROM "services" WHERE "services"."id" = $1 LIMIT 1 [["id", 1]]
Unpermitted parameters: 1, 2, 3
(0.1ms) BEGIN
(0.1ms) COMMIT
Unpermitted parameters: 1, 2, 3
{}
Service Load (0.2ms) SELECT "services".* FROM "services" WHERE "services"."id" = $1 LIMIT 1 [["id", 2]]
Unpermitted parameters: 1, 2, 3
(0.1ms) BEGIN
(0.1ms) COMMIT
Unpermitted parameters: 1, 2, 3
{}
Service Load (0.2ms) SELECT "services".* FROM "services" WHERE "services"."id" = $1 LIMIT 1 [["id", 3]]
Unpermitted parameters: 1, 2, 3
(0.1ms) BEGIN
(0.1ms) COMMIT
Unpermitted parameters: 1, 2, 3
{}
Redirected to http://localhost:3000/config
Completed 302 Found in 6ms (ActiveRecord: 1.1ms)
I found a solution, but perhaps it isn't the best. Let me know if someone has a better idea and I'd be happy to try it!
In the solution I updated my controllers update action and the service_params.
I passed id to service_params and called fetch method on the require method to get the correct params. I noticed that in the console it read Unpermitted parameters: 1, 2, 3 when it was saving each record indicating the params were an array and I also noticed in #Vijay's solution he tried to narrow down the params as well. After some Googling and console logging I came up with the code below.
def update
params["service"].keys.each do |id|
#service = Service.find(id.to_i)
#service.update_attributes!(service_params(id))
end
redirect_to config_url
end
def service_params(id)
params.require(:service).fetch(id).permit( :client_id, :client_secret )
end
What do you think?
Try this...
params.require(:service).permit( id: [ :client_id, :client_secret ] )
Your strong parameters line should be
params.require(:service).permit( [:id, :client_id, :client_secret ] )
This permits arrays of values
http://guides.rubyonrails.org/action_controller_overview.html#more-examples
Try this one and it will work.
Let me know if you get any issue
def service_params
params.require(:service).map do |_, p|
p.permit(:id, :client_id, :client_secret)
end
end
http://blog.sensible.io/2013/08/17/strong-parameters-by-example.html
Please try:
def update
Service.update(service_params.keys, service_params.values
end
def service_params
params.permit(service: [:client_id, :client_secret]).require(:service)
end

setting up search model to wrap around user model

I was finally able to come up with some sort of structure for my advanced search. The idea is to have a search that pulls data from the User model. So I built a search model which will be a kind of wrapper around the user model. For example: when I say Search.search_for(options), in the search_for method it will use the options to search on the User model and return the results, which you can display on the page. I came up with this method as I was told I have to duplicate the values, but I figured I just need to make Search call the underlying (already existing) User model.
So I have a view from where users can search. I have to collect all the options they have specified that they want to search on (gender, age, zip code, do they have kids, religion and ethnicity). Collect the options and submit the form to SearchController.
I have the concept down, but am struggling with the execution since I am new to Rails. The code below is essentially what I have (minus User model as it's filled with other parts from app). I'm not sure how to finish the rest of the coding to pull this off.
Searches_controller:
def new
#search = Search.new
end
def create
#search = Search.new(params[:search])
if #search.save
redirect_to #search
else
render 'new'
end
end
def show
#search = Search.find(params[:id])
#users = Users.search(params)
end
end
search model:
attr_accessible :age, :children, :ethnicity, :gender, :religion, :zip_code
def users
#users ||= find_users
end
def self.search(params)
end
private
def find_users
users = User.order(:id)
users = users.where(gender: gender) if gender
users = users.where(:ethnicity => ethnicity) if ethnicity
end
new.html (advanced search page):
<%= form_for #search do |f| %>
<div class="field">
<%= f.label :gender %><br />
<%= f.select :gender, ['man', 'woman'], :include_blank => true %>
</div>
<div class="field">
<%= f.label :zip_code %><br />
<%= f.text_field :zip_code %>
</div>
<div class="field">
<%= f.label :children %><br />
<%= f.select :children, ['Yes, they live with me', 'I want kids now', "I want one someday", "Not for me"], :include_blank => true %>
</div>
<div class="field">
<%= f.label :religion %><br />
<%= f.select :religion, ["Agnostic", "Atheist", "Christian", "Catholic", "Buddhist", "Hindu", "Jewish", "Muslim", "Spiritual without affiliation", "Other", "None", "Prefer not to say"], :include_blank => true %>
</div>
<div class="field">
<%= f.label :ethnicity %><br />
<%= f.select :ethnicity, ["Asian", "Biracial", "Indian", "Hispanic/Latin", "Middle Eastern", "Native American", "Pacific Islander", "White", "Other"], :include_blank => true %>
</div>
<div class="actions"><%= f.submit "Search" %></div>
<% end %>
show.html (view to show results):
<%= render #search.users %>
development log:
Started POST "/searches" for 127.0.0.1 at 2013-05-06 14:00:54 -0400
Processing by SearchesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Pher65dG6gRU9NGgv2q1ot0cfjq+MELgXE6dOtvcrY0=", "search"=>{"gender"=>"", "zip_code"=>"", "children"=>"", "religion"=>"", "ethnicity"=>"Asian"}, "commit"=>"Search"}
[1m[36m (0.2ms)[0m [1mBEGIN[0m
[1m[35mSQL (107.5ms)[0m INSERT INTO `searches` (`age`, `children`, `created_at`, `ethnicity`, `gender`, `religion`, `updated_at`, `zip_code`) VALUES (NULL, NULL, '2013-05-06 18:00:54', 0, NULL, NULL, '2013-05-06 18:00:54', '')
[1m[36m (60.1ms)[0m [1mCOMMIT[0m
Redirected to http://localhost:3000/searches/25
Completed 302 Found in 276ms (ActiveRecord: 167.7ms)
Started GET "/searches/25" for 127.0.0.1 at 2013-05-06 14:00:54 -0400
Processing by SearchesController#show as HTML
Parameters: {"id"=>"25"}
[1m[35mSearch Load (0.5ms)[0m SELECT `searches`.* FROM `searches` WHERE `searches`.`id` = 25 LIMIT 1
[1m[36mUser Load (73.2ms)[0m [1mSELECT `users`.* FROM `users` WHERE `users`.`zip_code` = '' AND `users`.`ethnicity` = '0' ORDER BY id[0m
Rendered collection (0.0ms)
Rendered searches/show.html.erb within layouts/application (81.4ms)
[1m[35mUser Load (0.6ms)[0m SELECT `users`.* FROM `users` WHERE `users`.`auth_token` = 'LTzif2q6921TM4pQzfmEGg' LIMIT 1
Completed 200 OK in 309ms (Views: 224.6ms | ActiveRecord: 74.3ms)
Ok, first of all make sure that the User model and the Search model have exactly the same attributes, so gender, zip_code, children, religion and ethnicity.
The only time you would need to have differing column names is if you want to do something a bit more "complex", such as searching a range, for example if the users table has age, then the searches table might have min_age and max_age.
Searches controller:
def new
#search = Search.new
end
def create
#search = Search.new(params[:search])
if #search.save
redirect_to #search
else
render 'new'
end
end
def show
#search = Search.find(params[:id])
#users = #search.users
end
Searches model:
def users
users = User.order(:id)
users = users.where(gender: gender) if gender
users = users.where(zip_code: zip_code) if zip_code
users = users.where(children: children) if children
users = users.where(religion: religion) if religion
users = users.where(ethnicity: ethnicity) if ethnicity
users
end
In app/views/searches/show.html.erb:
<h1>Search results</h1>
<%= render #users %>
And make sure that you have the partial app/views/users/_user.html.erb with something like:
<p><%= user.name %> - <%= user.email %></p> # or whatever
Now go to the search form and create a new search object, get the ID from the URL (lets say it's 34).
Then go into rails console and do:
#search = Search.find(34)
# should return something like: gender: "male", zip_code: nil, children: "Yes"..
# then try the users method:
#search.users
Not sure why your view isn't working. Make sure you have #users = #search.users in your searches controller under the show action, then go to views/searches/show.html.erb and do:
<% #users.each do |user| %>
<p><%= user.name %></p>
<% end %>
And see if that works.

Resources