Undefined Method Error - Single Table Inheritance - Routing error - ruby-on-rails

I am creating a Single Table Inheritance model to build a comment thread and I am getting a confusing routing error
I have set up my Model
class Question < ApplicationRecord
has_many :answers, class_name: 'Questions::Answer'
end
class Answer < ApplicationRecord
has_many :answers, class_name: 'Answers::Answer'
end
with associated sub classes
module Questions
class Answer < ::Answer
belongs_to :question
validates :body, presence: true
validates :question, presence: true
end
end
module Answers
class Answer < ::Answer
belongs_to :answer
has_one :question, through: :answer
validates :body, presence: true
validates :answer, presence: true
end
end
Routes
resources :questions do
resources :answers, shallow: true
end
In my view, I render answers and a form to add an answer
<%= render #answers %></br>
<%= render "answers/form" %>
Which takes the following instances from my Question controller
def show
#answer = #question.answers.new
#answers = #question.answers.page(params[:page]).per(5)
end
However, this gives me an undefined method error:
undefined method `questions_answers_path'
In my routes, indeed the only paths are
question_answers GET /questions/:question_id/answers(.:format) answers#index
POST /questions/:question_id/answers(.:format) answers#create
new_question_answer GET /questions/:question_id/answers/new(.:format) answers#new
edit_answer GET /answers/:id/edit(.:format) answers#edit
answer GET /answers/:id(.:format) answers#show
PATCH /answers/:id(.:format) answers#update
PUT /answers/:id(.:format) answers#update
DELETE /answers/:id(.:format) answers#destroy
The question then is, why is it looking for the plural questions_answers_path, rather than question_answers_path.
The form is relatively standard:
<%= simple_form_for(#answer) do |f| %>
<%= f.error_notification %>
<%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>
<div class="form-inputs">
<%= f.input :body %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
When I force the path by using <%= simple_form_for #answer, url: question_answers_path(#question) do |f| %>
I get an error trying to submit the form. Body can't be blank
Any ideas on what is wrong with my code?
For completeness:
Answers Controller
class AnswersController < ApplicationController
before_action :set_answer, only: [:edit, :update, :destroy]
before_action :set_question
def create
#answer = #question.answers.build(answer_params)
respond_to do |format|
if #answer.save
format.html { redirect_to question_path(#question) }
format.json { render :show, status: :created, location: #answer }
else
format.html { render :new }
format.json { render json: #answer.errors, status: :unprocessable_entity }
end
end
end
def update
authorize #answer
respond_to do |format|
if #answer.update(answer_params)
format.html { redirect_to question_answers_path(#question), notice: 'Answer was successfully updated.' }
format.json { render :show, status: :ok, location: #answer }
else
format.html { render :edit }
format.json { render json: #answer.errors, status: :unprocessable_entity }
end
end
end
def destroy
authorize #answer
#answer = Answers.find(params[:id])
#answer.discard
respond_to do |format|
format.html { redirect_to question_answers_path(#question), notice: 'Answer was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_answer
#answer = Answer.find(params[:id])
end
def answer_params
params.fetch(:answer, {}).permit(:body, :type).merge(user_id: current_user.id, question_id: #question.id)
end
def set_question
#question = Question.find(params[:question_id])
end
end

Related

rails strong parameters not work correctly

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|

collection_select is not creating the association table

I'm currently trying to add a collection_select of ranches to my staff
And I saw that it's better to create an extra table to make this association.
And I follow some tutorial, but is not working on my side
This is my code :
Staffs/_form :
<%= form_for(#staff) do |f| %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<%= fields_for(#staff_ranch) do |x| %>
<div class="field">
<%= x.collection_select(:ranch_id, #all_ranch, :id, :name, { }, {:multiple => true}) %>
</div>
<%end%>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
My models :
- Ranch :
has_many :ranchstaffs
has_many :staffs, :through => :ranchstaffs
- Staff :
has_many :ranchstaffs
has_many :ranches, :through => :ranchstaffs
-Ranchstaff :
belongs_to :ranch
belongs_to :staff
Staff controller :
class StaffsController < ApplicationController
before_action :set_staff, only: [:show, :edit, :update, :destroy]
# GET /ranches
# GET /ranches.json
def index
#staffs = current_user.staffs
end
# GET /ranches/1
# GET /ranches/1.json
def show
end
# GET /ranches/new
def new
#staff = Staff.new
#all_ranch = current_user.ranches
#staff_ranch = #staff.ranchstaffs.build
end
# GET /ranches/1/edit
def edit
end
# POST /ranches
# POST /ranches.json
def create
#staff = Staff.new(staff_params)
#staff.update(user_id: current_user.id)
respond_to do |format|
if #staff.save
format.html { redirect_to #staff, notice: 'Staff was successfully created.' }
format.json { render :show, status: :created, location: #staff }
else
format.html { render :new }
format.json { render json: #staff.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /ranches/1
# PATCH/PUT /ranches/1.json
def update
respond_to do |format|
if #staff.update(staff_params)
format.html { redirect_to #staff, notice: 'Staff was successfully updated.' }
format.json { render :show, status: :ok, location: #staff }
else
format.html { render :edit }
format.json { render json: #staff.errors, status: :unprocessable_entity }
end
end
end
# DELETE /ranches/1
# DELETE /ranches/1.json
def destroy
#staff.destroy
respond_to do |format|
format.html { redirect_to staffs_url, notice: 'Ranch was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_staff
#staff = Staff.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def staff_params
params.require(:staff).permit(:name, :user_id, :cat, :ranch_id)
end
end
Can you explain me why the model ranchstaff was not created after a creation of a new staff ?
As you are using fields_for you are using nested form but you are not permitting the parameters properly. First make change in your form:
<%= f.fields_for(#staff_ranch) do |x| %>
<div class="field">
<%= x.collection_select(:ranch_id, #all_ranch, :id, :name, { }, {:multiple => true}) %>
</div>
<% end %>
And then in your controller:
def staff_params
params.require(:staff).permit(:name, :user_id, :cat, ranchstaff_attributes: [ranch_id: []])
end
And in your Staff model write:
accepts_nested_attributes_for :ranchstaffs
Then your ranchstaff should be created when the User is being created.
Your ranch_id is coming in an array. So u have to specify that ranch_id would be array in strong parameters.
so your staff_params method would look like this
def staff_params
params.require(:staff).permit(:name, :user_id, :cat, :staff_ranch_attributes =>[:ranch_id => []])
end

Rails 5 Nested attributes "Unpermitted parameter" - Whitelisted

Error: Unpermitted parameter: properties
I'm whitelisting the properties{} in the request_controller.rb
This usually works but not this time.
I'm not been able to save some of the data entered in a form. The 3 fields that are not saving are coming from a dynamic form "request_type". I followed Rails Cast episode 403 for this solution, which I have working well in another project but not in this one.
Source: http://railscasts.com/episodes/403-dynamic-forms
Sorry if this is a duplicate question, but I've looked at several other questions and I can't pin-point what I'm doing wrong here
I've researched several questions here, but I'm still not able to get it to work:
Rails 4 Nested Attributes Unpermitted Parameters
Nested attributes - Unpermitted parameters Rails 4
I'm omitting some stuff to make it easier to read the code. Please ask me if you need to see more.
Here's the log:
Processing by RequestsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"8EASewOIxY58b+SU+dxd2YAfpjt38IdwNSju69RPwl/OKfx3AfmvLav79igj8CqPbDwi0eJAwojRbtm+C9F6wg==", "request"=>{"name"=>"asdasddaa", "due_date(1i)"=>"2016", "due_date(2i)"=>"9", "due_date(3i)"=>"15", "user_id"=>"1", "project_id"=>"1", "request_type_id"=>"2", "properties"=>{"Name and last name"=>"asdasd", "Mobile"=>"asdada", "Office tel."=>"asdadas"}}, "commit"=>"Create Request"}
Unpermitted parameter: properties
Update
If I change the request_params to this:
def request_params
params.require(:request).permit(:name, :due_date, :group_id, :user_id, :project_id, :request_type_id, properties:{} ).tap do |whitelisted|
whitelisted[:properties] = params[:request][:properties]
end
end
See:
properties:{}
I get this Error:
Unpermitted parameters: Name and last name, Mobile, Office tel.
request_controller.rb
def new
#request = Request.new
#request_type = RequestType.find(params[:request_type_id])
#project = #request_type.project.id
end
def create
#request = Request.new(request_params)
respond_to do |format|
if #request.save
format.html { redirect_to #request, 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 request_params
params.require(:request).permit(:name, :due_date, :group_id, :user_id, :project_id, :request_type_id, :properties).tap do |whitelisted|
whitelisted[:properties] = params[:request][:properties]
end
end
request_types_controller.rb
def new
#request_type = RequestType.new
#project = Project.find(params[:project])
end
def create
#request_type = RequestType.new(request_type_params)
respond_to do |format|
if #request_type.save
format.html { redirect_to #request_type, notice: 'Request type was successfully created.' }
format.json { render :show, status: :created, location: #request_type }
else
format.html { render :new }
format.json { render json: #request_type.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #request_type.update(request_type_params)
format.html { redirect_to #request_type, notice: 'Request type was successfully updated.' }
format.json { render :show, status: :ok, location: #request_type }
else
format.html { render :edit }
format.json { render json: #request_type.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_request_type
#request_type = RequestType.find(params[:id])
end
def request_type_params
params.require(:request_type).permit(:name, :project_id, properties:{}, fields_attributes: [:name, :field_type, :required, :id, :_destroy])
# params.require(:product_type).permit(:name, :product_type_id)
end
models/request.rb
class Request < ApplicationRecord
belongs_to :group
belongs_to :user
belongs_to :project
belongs_to :request_type
serialize :properties, Hash
end
models/request_type.rb
class RequestType < ApplicationRecord
belongs_to :project
has_many :fields, class_name: "RequestField"
accepts_nested_attributes_for :fields, allow_destroy: true
has_many :requests
end
models/request_field.rb
class RequestField < ApplicationRecord
belongs_to :request_type
end
views/requests/new.html.erb
<%= form_for #request do |f| %>
<%= f.fields_for :properties, OpenStruct.new(#request.properties) do |builder| %>
<% #request_type.fields.each do |field| %>
<%= render "requests/fields/#{field.field_type}", field: field, f: builder %>
<% end %>
<% end %>
<div class="actions">
<%= f.submit class:"btn btn-primary" %>
</div>
<% end %>
Try removing :properties from your request_params in your request_controller like this:
def request_params
params.require(:request).permit(:name, :due_date, :group_id, :user_id, :project_id, :request_type_id).tap do |whitelisted|
whitelisted[:properties] = params[:request][:properties]
end
EDIT
def request_params
params.require(:request).permit(:id, :name, :due_date, :group_id, :user_id, :project_id, :request_type_id)
params.require(:properties).permit!
end!

Update child attributes rails

I have a customer model and book_room model
class Customer < ApplicationRecord
has_many :book_rooms
accepts_nested_attributes_for :book_rooms
end
class BookRoom < ApplicationRecord
belongs_to :customer
end
in the book_room controller the create method is from its parent
class BookRoomsController < ApplicationController
def create
#customer = Customer.find(params[:customer_id])
#customer_room = #customer.book_rooms.create(book_rooms_params)
flash[:notice] = "Customer has been added to room"
redirect_to customer_path(#customer)
end
def destroy
#customer = Customer.find(params[:customer_id])
#customer_room = #customer.book_rooms.find(params[:id])
#customer_room.destroy
flash[:notice] = "Customer room has been deleted"
redirect_to customer_path(#customer)
end
def edit
#customer = Customer.find(params[:customer_id])
end
def update
#customer = Customer.find(params[:customer_id])
#customer.book_rooms.update(book_rooms_params)
flash[:notice] = "Customer has checked out"
redirect_to #customer
end
private
def book_rooms_params
params.require(:book_room).permit(:room, :first_name, :last_name, :phone_number, :checked_out)
end
end
in the Customer show page
<%= form_for [#customer, #customer.book_rooms.build] do |f| %>
<% #room = Room.all %>
<%= f.label "Room: "%>
<%= f.select(:room, #room.collect { |a| [a.room_number, a.id] }) %>
<%= f.submit "Enter" %>
<div class="col-md-12"><%= render #customer.book_rooms.order("created_at DESC") %></div>
This works perfectly and all child objects get created. now when I try to edit the child attributes it doesn't update at all
heres the edit form in the book_room edit page/action
<%= form_for #customer do |f| %>
<%= f.fields_for :book_rooms, #customer.book_rooms do |f| %>
<%= f.check_box :checked_out %>
<% end %>
<%= f.submit "Enter" %>
is there something i am doing wrong? why doesn't it update?
Customers controller
class CustomersController < ApplicationController
before_action :set_customer, only: [:show, :edit, :update, :destroy]
# POST /customers.json
def create
#customer = Customer.new(customer_params)
respond_to do |format|
if #customer.save
format.html { redirect_to #customer, notice: 'Customer was successfully created.' }
format.json { render :show, status: :created, location: #customer }
else
format.html { render :new }
format.json { render json: #customer.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #customer.update(customer_params)
format.html { redirect_to #customer, notice: 'Customer was successfully updated.' }
format.json { render :show, status: :ok, location: #customer }
else
format.html { render :edit }
format.json { render json: #customer.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_customer
#customer = Customer.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def customer_params
params.require(:customer).permit(:first_name, :last_name, :phone_number, :sex, :book_rooms_attributes => [:checked_out])
end
In your customers controller :
Try to change your function customer_params like:
def customer_params
params.require(:customer).permit(:first_name, :last_name, :phone_number, :sex, {:book_rooms => [:checked_out]})
end
For more explications see here
Change your update method to:
def update
#customer = Customer.find(params[:customer_id])
if #customer.update_attributes(customer_params)
flash[:notice] = "Customer has checked out"
redirect_to #customer
else
...redirect to edit page with a flash error message ...
end
end
You also need to modify your edit page.
<%= form_for(:customer, :url => {:action => 'update', :id => #customer.id}, :method => 'PUT') do |f| %>
Try changing the URL to update and changing the method to patch you will go to update method.
<%= form_for :customer, url: customer_path(#customer),method: :patch do |f| %>
<%= f.fields_for :book_rooms, #customer.book_rooms do |f| %>
<%= f.check_box :checked_out %>
<% end %>
<%= f.submit "Enter" %>

Ruby on rails - adding multiple choice checkboxes - ERROR - undefined method `check_box_tag'

I'm tying do add a new kind of answers to my polls app. It will be a multiple choice with checkboxes. The user can choose one or more possible answers from the checkboxes presented.
I'm struggling to make it work, I'm getting the error:
NoMethodError in Replies#new
undefined method `check_box_tag' for #<ActionView::Helpers::FormBuilder:0x007fae8bd82f48>
right i have this models:
answer.rb
class Answer < ActiveRecord::Base
belongs_to :reply
belongs_to :question
belongs_to :possible_answer
end
poll.rb
class Poll < ActiveRecord::Base
validates_presence_of :title
has_many :questions
has_many :replies
end
possible_answer.rb
class PossibleAnswer < ActiveRecord::Base
belongs_to :question
end
question.rb
class Question < ActiveRecord::Base
belongs_to :poll
has_many :possible_answers
has_many :answers
accepts_nested_attributes_for :possible_answers, reject_if: proc { |attributes| attributes['title'].blank? }
end
reply.rb
class Reply < ActiveRecord::Base
belongs_to :poll
has_many :answers
accepts_nested_attributes_for :answers
end
In the views I have a reply/new.html.erb that already work for radio and open answer questions, by rendering the partial by kind:
<h1><%= #poll.title %></h1>
<%= form_for [ #poll, #reply ] do |f| %>
<%= f.fields_for :answers do |c| %>
<%= render c.object.question.kind, c: c %>
<% end %>
<p>
<%=f.submit 'Finish poll', class: 'btn btn-primary'%>
</p>
<% end %>
and the partial for the checkbox:
<p>
<%= c.label :value, c.object.question.title %>
</p>
<div class="checkbox">
<% c.object.question.possible_answers.each do |possible_answer| %>
<p>
<label>
<%= c.check_box_tag :possible_answer_id, possible_answer.id %>
<%= possible_answer.title %>
<%= c.hidden_field :question_id %>
</label>
</p>
<% end %>
</div>
replies_controller.rb
class RepliesController < ApplicationController
def new
#poll = Poll.find params[:poll_id]
#reply = #poll.replies.build
#poll.questions.each { |question| #reply.answers.build question: question }
end
def create
#poll = Poll.find params[:poll_id]
#reply = #poll.replies.build reply_params
if #reply.save
redirect_to #poll, notice: 'Thank you for the taking the poll.'
else
render :new
end
end
private
def reply_params
params.require(:reply).permit(:poll_id, {
answers_attributes: [:value, :question_id, :reply_id, :possible_answer_id] })
end
end
questions_controller
class QuestionsController < ApplicationController
before_action :set_question, only: [:show, :edit, :update, :destroy]
before_action :set_poll
before_action :set_kind_questions
def index
#questions = Question.all
end
def show
end
def new
##question = Question.new
#question = #poll.questions.build
5.times { #question.possible_answers.build }
end
def edit
end
def create
##question = Question.new(question_params)
#question = #poll.questions.build(question_params)
respond_to do |format|
if #question.save
format.html { redirect_to #poll, notice: 'Question was successfully created.' }
format.json { render :show, status: :created, location: #question }
else
format.html { render :new }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #question.update(question_params)
format.html { redirect_to #question, notice: 'Question was successfully updated.' }
format.json { render :show, status: :ok, location: #question }
else
format.html { render :edit }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
def destroy
#question.destroy
respond_to do |format|
format.html { redirect_to #question, notice: 'Question was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_question
#question = Question.find(params[:id])
end
def question_params
params.require(:question).permit(:title, :kind, :poll_id, { possible_answers_attributes: [:title, :question_id] })
end
def set_kind_questions
#kind_options = [
['Open Answer','open'],
['Multiple Radio Choice', 'radio'],
['Multiple Checkbox Choice','checkbox']
]
end
def set_poll
#poll = Poll.find params[:poll_id]
end
end
Answers migration table
class CreateAnswers < ActiveRecord::Migration
def change
create_table :answers do |t|
t.references :reply, index: true, foreign_key: true
t.references :question, index: true, foreign_key: true
t.references :possible_answer, index: true, foreign_key: true
t.string :value
t.timestamps null: false
end
end
end
Probably I have to use has_and_belongs_to_many association in the answers model but I'm not getting how. Can someone help me?
Thanks!
Please try to just use check_box_tag as below:
<%= check_box_tag( 'possible_answer_ids['+ possible_answer.id.to_s+']', possible_answer.id) %>

Resources