I am having trouble structuring my nested attributes for my model Request.
The data is being passed in the correct way from my POST action.
What am I missing to whitelist these parameters?
Appreciate any help.
Console Output
Started POST "/requests" for 127.0.0.1 at 2017-06-08 10:57:15 -0400
Processing by RequestsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"fmvhoPxVpcHoqOd32mO/HJMrfaPUd+KbNqDJiSRs78U44Y0uL3prpTfU6wmw7PAwv0b+mRHXOGMLvD9bsZpxnw==", "request"=>{"concierge_name"=>"Alex", "concierge_number"=>"954-123-4567", "concierge_email"=>"alex#email.com", "client_name"=>"Adam", "client_number"=>"954-765-4321", "client_email"=>"adam#email.com", "hotel_employee"=>"0", "concierge_service"=>"0", "vip_promoter"=>"0", "arriving_with_client"=>"1", "client_alone"=>"0", "males"=>"", "females"=>"1", "table_minimum"=>"1000", "arrival_time(1i)"=>"2017", "arrival_time(2i)"=>"6", "arrival_time(3i)"=>"8", "arrival_time(4i)"=>"14", "arrival_time(5i)"=>"56", "table_location_ids"=>["1"], "drink_attributes"=>[{"id"=>"1", "quantity"=>"1"}, {"id"=>"2", "quantity"=>""}, {"id"=>"3", "quantity"=>""}, {"id"=>"4", "quantity"=>""}], "chaser_ids"=>["1"], "comments"=>""}, "commit"=>"Submit"}
Completed 500 Internal Server Error in 8ms (ActiveRecord: 0.0ms)
ActiveModel::UnknownAttributeError (unknown attribute 'drink_attributes' for Request.):
app/models/request.rb
class Request < ApplicationRecord
has_many :request_drinks
has_many :drinks, through: :request_drinks
accepts_nested_attributes_for :drinks
end
app/model/drink.rb
class Drink < ApplicationRecord
has_many :request_drinks
has_many :requests, through: :request_drinks
end
app/model/request_drink.rb
class RequestDrink < ApplicationRecord
belongs_to :request
belongs_to :drink
end
app/controllers/request_controller.rb
class RequestsController < ApplicationController
before_action :set_request, only: [:show,
:edit,
:update,
:destroy]
def index
#requests = Request.search(params[:term], params[:filter], params[:page])
end
def show
end
def new
#request = Request.new
#drinks = Drink.active
end
def edit
end
def create
#request = Request.new(request_params)
respond_to do |format|
if #request.save
format.html { redirect_to thanks_path, notice: 'Request was successfully created.' }
format.json { render :show, status: :created, location: #request }
else
format.html { render :new }
format.json { render json: #request.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #request.update(request_params)
format.html { redirect_to #request, notice: 'Request was successfully updated.' }
format.json { render :show, status: :ok, location: #request }
else
format.html { render :edit }
format.json { render json: #request.errors, status: :unprocessable_entity }
end
end
end
def destroy
#request.destroy
respond_to do |format|
format.html { redirect_to requests_url, notice: 'Request was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_request
#request = Request.find(params[:id])
end
def request_params
params.require(:request).permit(:concierge_name,
:concierge_number,
:concierge_email,
:client_name,
:client_number,
:client_email,
:hotel_employee,
:concierge_service,
:vip_promoter,
:arriving_with_client,
:client_alone,
:people,
:males,
:females,
:table_minimum,
:arrival_time,
:comments,
:drink_attributes => [:id, :quantity]
)
end
end
app/views/requests/_form.html.erb
...
<div class="field-3">
<h4>Drinks</h4>
<% #drinks.all.each do |d| %>
<%= hidden_field_tag "request[drink_attributes][][id]", d.id %>
<%= number_field_tag "request[drink_attributes][][quantity]" %>
<%= d.name %>
<br />
<% end %>
</div>
...
You need to use the plural form of the object (i.e. drinks) when using nested attributes.
So, in your request_params change:
:drink_attributes => [:id, :quantity]
to:
:drinks_attributes => [:id, :quantity]
An you need to update your form too:
...
<%= hidden_field_tag "request[drinks_attributes][][id]", d.id %>
<%= number_field_tag "request[drinks_attributes][][quantity]" %>
...
Related
I am trying to create a nested attribute form for my Request model.
My parameters are not saving correctly when the Create action is triggered. Though in my console, the data is structured correctly for how I want it to be entered.
The :quantity attribute is on the JoinTable model of RequestDrink.
How can I white-list these parameters correctly?
Console Output
Started POST "/requests" for 127.0.0.1 at 2017-06-08 12:38:40 -0400
Processing by RequestsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"3ljcH44E7ZrEXNztlgGacyA0nyumNsTX6NyMMu9N+3SY0rCRXSsj/hsg0JP8jtVfDFkcEWOWHi/VwHrgertlLg==", "request"=>{"concierge_name"=>"Alex", "concierge_number"=>"954-123-4567", "concierge_email"=>"alex#email.com", "client_name"=>"Adam", "client_number"=>"954-765-4321", "client_email"=>"adam#email.com", "hotel_employee"=>"0", "concierge_service"=>"0", "vip_promoter"=>"0", "arriving_with_client"=>"1", "client_alone"=>"0", "males"=>"", "females"=>"1", "table_minimum"=>"1000", "event_date_id"=>"1", "arrival_time(1i)"=>"2017", "arrival_time(2i)"=>"6", "arrival_time(3i)"=>"8", "arrival_time(4i)"=>"16", "arrival_time(5i)"=>"38", "drinks_attributes"=>[{"id"=>"1", "quantity"=>"1"}, {"id"=>"2", "quantity"=>""}, {"id"=>"3", "quantity"=>""}, {"id"=>"4", "quantity"=>""}], "commit"=>"Submit"}
Completed 404 Not Found in 18ms (ActiveRecord: 0.0ms)
ActiveRecord::RecordNotFound (Couldn't find Drink with ID=1 for Request with ID=):
app/controllers/requests_controller.rb:34:in `create'
app/models/request.rb
class Request < ApplicationRecord
has_many :request_drinks
has_many :drinks, through: :request_drinks
accepts_nested_attributes_for :drinks
end
app/models/drinks.rb
class Drink < ApplicationRecord
has_many :request_drinks
has_many :requests, through: :request_drinks
end
app/models/request_drink.rb
class RequestDrink < ApplicationRecord
belongs_to :request
belongs_to :drink
end
app/controllers/request_controller.rb
class RequestsController < ApplicationController
before_action :set_request, only: [:show,
:edit,
:update,
:destroy]
def index
redirect_to root_path unless admin_signed_in?
#requests = Request.search(params[:term], params[:filter], params[:page])
end
def show
end
def new
#request = Request.new
#drinks = Drink.active
#chasers = Chaser.active
#table_locations = TableLocation.active
#event_dates = EventDate.active
end
def edit
end
def create
#request = Request.new(request_params)
#request.people = (#request.males || 0) + (#request.females || 0)
#drinks = Drink.active
#chasers = Chaser.active
#table_locations = TableLocation.active
#event_dates = EventDate.active
respond_to do |format|
if #request.save
format.html { redirect_to thanks_path, notice: 'Request was successfully created.' }
format.json { render :show, status: :created, location: #request }
else
format.html { render :new }
format.json { render json: #request.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #request.update(request_params)
format.html { redirect_to #request, notice: 'Request was successfully updated.' }
format.json { render :show, status: :ok, location: #request }
else
format.html { render :edit }
format.json { render json: #request.errors, status: :unprocessable_entity }
end
end
end
def destroy
#request.destroy
respond_to do |format|
format.html { redirect_to requests_url, notice: 'Request was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_request
#request = Request.find(params[:id])
end
def request_params
params.require(:request).permit(:concierge_name,
:concierge_number,
:concierge_email,
:client_name,
:client_number,
:client_email,
:hotel_employee,
:concierge_service,
:vip_promoter,
:arriving_with_client,
:client_alone,
:people,
:males,
:females,
:table_minimum,
:arrival_time,
:comments,
:event_date_id,
:drinks_attributes => [:id, :quantity]
)
end
end
app/views/requests/_form.html.erb
<%= form_with(model: request, local: true) do |f| %>
...
<h4>Drinks</h4>
<% #drinks.all.each do |d| %>
<%= hidden_field_tag "request[drinks_attributes][][id]", d.id %>
<%= number_field_tag "request[drinks_attributes][][quantity]", 0, in: 0..10 %>
<%= d.name %>
<br />
<% end %>
...
<% end %>
The :quantity attribute is on the JoinTable model of RequestDrink.
Yet your are using drinks instead of request_drinks. Try changing your code to use the latter:
Model:
class Request < ApplicationRecord
has_many :request_drinks
has_many :drinks, through: :request_drinks
accepts_nested_attributes_for :request_drinks
end
View:
...
<%= hidden_field_tag "request[request_drinks_attributes][][id]", d.id %>
<%= number_field_tag "request[request_drinks_attributes][][quantity]", 0, in: 0..10 %>
...
Controller:
class RequestsController < ApplicationController
# other actions
def request_params
params.require(:request).permit(..., :request_drinks_attributes => [:id, :quantity])
end
end
Thank you, this worked as well as tweaking my parameters a little more. This is the completed code
app/models/request.rb
class Request < ApplicationRecord
has_many :request_drinks
has_many :drinks, through: :requests
accepts_nested_attributes_for :request_drinks
end
app/controllers/request_controller.rb
class RequestController < ApplicationRecord
...
def request_params
params.require(:request).permit(:concierge_name,
:concierge_number,
:concierge_email,
:client_name,
:client_number,
:client_email,
:hotel_employee,
:concierge_service,
:vip_promoter,
:arriving_with_client,
:client_alone,
:people,
:males,
:females,
:table_minimum,
:arrival_time,
:comments,
:is_deleted,
:approved,
:attended,
:event_date_id,
:request_drinks_attributes => [:request_id, :drink_id, :quantity]
:table_location_ids => []
)
end
end
app/views/requests/_form.html.erb
...
<h4>Drinks</h4>
<% #drinks.all.each do |d| %>
<%= hidden_field_tag "request[request_drinks_attributes][][request_id]", request.id %>
<%= hidden_field_tag "request[request_drinks_attributes][][drink_id]", d.id %>
<%= number_field_tag "request[request_drinks_attributes][][quantity]", 0, in: 0..10 %>
<%= d.name %>
<br />
<% end %>
i have a rails app. i have strange problem in saving form
this is my ticket model .
class Ticket < ApplicationRecord
belongs_to :user
has_many :ticketissues , inverse_of: :ticket
accepts_nested_attributes_for :ticketissues, :reject_if => lambda { |a| a[:body].blank? }
end
this is ticketisue model
class Ticketissue < ApplicationRecord
belongs_to :user
belongs_to :ticket
validates :body, presence: true
end
this is ticket controller
class TicketsController < ApplicationController
before_action :set_ticket, only: [:show, :edit, :update, :destroy]
# GET /tickets
# GET /tickets.json
def index
#tickets = Ticket.all
end
# GET /tickets/1
# GET /tickets/1.json
def show
end
# GET /tickets/new
def new
#ticket = Ticket.new
end
# GET /tickets/1/edit
def edit
end
# POST /tickets
# POST /tickets.json
def create
#ticket = Ticket.new(ticket_params)
#ticket.user_id = current_user.id
#ticket.ticketissues.build
respond_to do |format|
if #ticket.save
format.html { redirect_to #ticket, notice: 'Ticket was successfully created.' }
format.json { render :show, status: :created, location: #ticket }
else
format.html { render :new }
format.json { render json: #ticket.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /tickets/1
# PATCH/PUT /tickets/1.json
def update
respond_to do |format|
if #ticket.update(ticket_params)
format.html { redirect_to #ticket, notice: 'Ticket was successfully updated.' }
format.json { render :show, status: :ok, location: #ticket }
else
format.html { render :edit }
format.json { render json: #ticket.errors, status: :unprocessable_entity }
end
end
end
# DELETE /tickets/1
# DELETE /tickets/1.json
def destroy
#ticket.destroy
respond_to do |format|
format.html { redirect_to tickets_url, notice: 'Ticket was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_ticket
#ticket = Ticket.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def ticket_params
params.require(:ticket).permit(:subject, :subsubject, :user_id, ticketissues_attributes: [
:body, :id, :_destroy] )
#params.require(:ticket).permit!
end
end
and my view is like this
<%= f.input :subject , collection: [ "تغییر اطلاعات کسب و کار",
"تغییر اطلاعات یک کوپن",
"سایر موارد"] %>
<%= f.input :subsubject %>
<!-- <%= f.association :user %> -->
</div>
<%= f.simple_fields_for :ticketissue do |p| %>
<%= p.input :body %>
<% end %>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
but when i want to create a ticket , form will not save to database
and i get this error:
Started POST "/tickets" for 127.0.0.1 at 2017-04-11 23:52:33 +0430
Processing by TicketsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"fsl6nTe0PjmBKpeuh16BRFlYOw0MB93LEYDVEAl6TtT/uu/LwGTA0P2q0bRxIxBUqHqZINXHntrZLt7MuCG84Q==", "ticket"=>{"subject"=>"تغییر اطلاعات کسب و کار", "subsubject"=>"lk", "ticketissue"=>{"body"=>"lkjkjkjkjkkjkj"}}, "commit"=>"Create Ticket"}
Unpermitted parameter: ticketissue
but when i use console and this command:
Ticket.create(subject: 'test' , subsubject: 'ticket test' , ticketissues_attributes: [{body: "[some thing" }] )
every things work fines and all data save.
tanks for read and help.
You must use the plural here
= f.simple_fields_for :ticketissues do |p|
After clicking on create comment, i got error like this
coment controller:
`
I used FriendlyId instead of post id.
error:
ActiveRecord::RecordNotFound in CommentsController#create
Couldn't find Post with 'id'=
class CommentsController < ApplicationController
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create(params[:comment].permit(:name, :body))
redirect_to post_path(#post)
end
comments form: _comments.html.erb
`<%= form_for([#post,#post.comments.build]) do |f| %>
<p>
<%= f.label :name %>
<%= f.text_field :name %>
</p>
<p>
<%= f.label :body %><br>
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>`
posts controller: post_controller.rb
`class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
def index
#posts = Post.all.order("created_at DESC")
end
def show
end
def new
#post = Post.new
end
def edit
end
def create
#post = Post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_post
#post = Post.friendly.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :description, :image)
end
end
`
model: post.rb
class Post < ApplicationRecord
has_many :comments
extend FriendlyId
friendly_id :title, use: :slugged
has_attached_file :image, styles: { medium: "900x380#", thumb: "300x165>" }
validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
end
Do:
#post = Post.friendly.find(params[:post_id])
After you add this, add a new column to your database table by running
rails g migration AddSlugToPosts slug:uniq
After you have done this, locate your post model and add:
extend FriendlyId
friendly_id :first_name, use: :slugged
Note: I use first_name for my slug. It's up to you which one you want to use, you can read more about how to setup friendly here.
I am creating an ruby on rails 5 application. It is a todolist kind of application and using simple_form, haml-rails and cocoon gem. This is a application with nested form.
Generated a scaffold for goal and created model for action
Goal.rb and Action.rb
class Goal < ApplicationRecord
has_many :actions
accepts_nested_attributes_for :actions, reject_if: :all_blank
end
class Action < ApplicationRecord
belongs_to :goal
end
Then added the actions_attribute to permit in the params
class GoalsController < ApplicationController before_action :set_goal, only: [:show, :edit, :update, :destroy] def index
#goals = Goal.all end def show end def new
#goal = Goal.new end def edit end def create
#goal = Goal.new(goal_params)
respond_to do |format|
if #goal.save
format.html { redirect_to #goal, notice: 'Goal was successfully created.' }
format.json { render :show, status: :created, location: #goal }
else
format.html { render :new }
format.json { render json: #goal.errors, status: :unprocessable_entity }
end
end end def update
respond_to do |format|
if #goal.update(goal_params)
format.html { redirect_to #goal, notice: 'Goal was successfully updated.' }
format.json { render :show, status: :ok, location: #goal }
else
format.html { render :edit }
format.json { render json: #goal.errors, status: :unprocessable_entity }
end
end end def destroy
#goal.destroy
respond_to do |format|
format.html { redirect_to goals_url, notice: 'Goal was successfully destroyed.' }
format.json { head :no_content }
end end private
def set_goal
#goal = Goal.find(params[:id])
end
def goal_params
params.require(:goal).permit(:name, :purpose, :deadline, actions_attributes: [:step])
end
end
Forms for both form.html and action.html
_form.html.haml
= simple_form_for(#goal) do |f|
= f.error_notification
.form-inputs
= f.input :name
= f.input :purpose
= f.input :deadline
%h3 Actions
#tasks
= f.simple_fields_for :actions do |action|
= render 'action_fields', f: action
.links
= link_to_add_association 'Add', f, :actions
.form-actions
= f.button :submit
// action.html.haml
.nested-fields
= f.input :step
= f.input :done, as: :boolean
= link_to_remove_association "remove task", f
log in the console when i submit form
Processing by GoalsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"jel0g+oCkNaspe7T9dz7suDczIOdoKJqPqPDK9ta0WLPbwaSPBwshrDD2BrNAFeLoDx+0/soe11MWaZaH8cQoA==", "goal"=>{"name"=>"ja", "purpose"=>"asdfd", "deadline"=>"asdfasd", "actions_attributes"=>{"0"=>{"step"=>"ARasd", "done"=>"1", "_destroy"=>"false"}, "1475080334356"=>{"step"=>"", "done"=>"0", "_destroy"=>"false"}}}, "commit"=>"Create Goal"}
Unpermitted parameter: _destroy
Unpermitted parameter: _destroy
(0.5ms) BEGIN
(0.5ms) ROLLBACK
Rendering goals/new.html.haml within layouts/application
Rendered goals/_action_fields.html.haml (18.5ms)
Rendered goals/_action_fields.html.haml (26.5ms)
Rendered goals/_action_fields.html.haml (19.0ms)
Rendered goals/_form.html.haml (252.5ms)
Rendered goals/new.html.haml within layouts/application (309.0ms)
Completed 200 OK in 932ms (Views: 898.5ms | ActiveRecord: 1.0ms)
The console log shows: Unpermitted parameter: done
This is because in your controller, only these parameters are permitted:
params.require(:goal).permit(:name, :purpose, :deadline, actions_attributes: [:step])
I have model for properties, residents and people(people outside city so have to be not residents) and then I have owner join table where I set if property belongs to resident, or person
here are my models
class Property < ActiveRecord::Base
has_many :owners, dependent: :destroy
has_many :residents, through: :owners
has_many :people, through: :owners
belongs_to :ptype
end
class Resident < ActiveRecord::Base
has_many :owners, dependent: :destroy
has_many :properties, through: :owners
end
class Person < ActiveRecord::Base
has_many :owners, dependent: :destroy
has_many :properties, through: :owners
end
class Owner < ActiveRecord::Base
belongs_to :resident
belongs_to :property
belongs_to :person
end
I want to have view where I show the relation so if owner.resident show properties or if owner.person show properties
<% if #owner.resident %>
<ol><% #residents.properties.each do |property| %>
<li><%= property.ptype.name %> , <%= property.address %></li>
<% end %>
</ol>
<% end %>
<% if #owner.person %>
<ol><% #people.properties.each do |property| %>
<li><%= property.ptype.name %> , <%= property.address %></li>
<% end %>
</ol><% end %>
when I want to show relation where owner is a resident, I got error no method properties for nil:class for #people and when I want to show relation where owner is a person I got oposite, error no method properties for nil:class for #residents
I understand that it is because it returns no record, but thats why I put there that if
what am I doing wrong?
EDIT:
I use default controllers generated by rails
class PeopleController < ApplicationController
before_action :set_person, only: [:show, :edit, :update, :destroy]
def index
#people = Person.all
end
def show
end
def new
#person = Person.new
end
def edit
end
def create
#person = Person.new(person_params)
respond_to do |format|
if #person.save
format.html { redirect_to #person, notice: 'Person was successfully created.' }
format.json { render :show, status: :created, location: #person }
else
format.html { render :new }
format.json { render json: #person.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #person.update(person_params)
format.html { redirect_to #person, notice: 'Person was successfully updated.' }
format.json { render :show, status: :ok, location: #person }
else
format.html { render :edit }
format.json { render json: #person.errors, status: :unprocessable_entity }
end
end
end
def destroy
#person.destroy
respond_to do |format|
format.html { redirect_to people_url, notice: 'Person was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_person
#person = Person.find(params[:id])
end
def person_params
params.require(:person).permit(:name, :email, :tel)
end
end
class ResidentsController < ApplicationController
before_action :set_resident, only: [:show, :edit, :update, :destroy]
def index
#residents = Resident.all
end
def show
#residents = Resident.find(params[:id])
end
def new
#resident = Resident.new
end
def edit
end
def create
#resident = Resident.new(resident_params)
respond_to do |format|
if #resident.save
format.html { redirect_to #resident, notice: 'Záznam bol úspešne vytvorený.' }
format.json { render :show, status: :created, location: #resident }
else
format.html { render :new }
format.json { render json: #resident.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #resident.update(resident_params)
format.html { redirect_to #resident, notice: 'Záznam bol úspešne upravený.' }
format.json { render :show, status: :ok, location: #resident }
else
format.html { render :edit }
format.json { render json: #resident.errors, status: :unprocessable_entity }
end
end
end
def destroy
#resident.destroy
respond_to do |format|
format.html { redirect_to residents_url, notice: 'Záznam bol úspešne zmazaný.' }
format.json { head :no_content }
end
end
private
def set_resident
#resident = Resident.find(params[:id])
end
def resident_params
params.require(:resident).permit(:name, :birthdate, :birthId, :address, :email, :tel)
end
end
ok I did it all wrong from begining
this is a solution
<% if #owner.resident.present? %>
<ol><% #owner.resident.properties.each do |property| %>
<li><%= property.ptype.name %> , <%= property.address %></li>
<% end %>
</ol>
<% end %>
<% if #owner.person.present? %>
<ol><% #owner.person.properties.each do |property| %>
<li><%= property.ptype.name %> , <%= property.address %></li>
<% end %>
</ol>
<% end %>
IIRC #owner.person and #owner.resident will return proxy objects until something is done with them - try #owner.person.present? and #owner.resident.present?