So I'm getting the following error:
undefined method `errors' for #<Comment::ActiveRecord_Associations_CollectionProxy:0x00007f1a3e2ecf48>
I can get the comment count and other things like that, however, I can't display any errors of the validations.
Here is what I have in terms of my code
_new_comment
<% if signed_in? %>
<div class="row">
<%= form_with(model: [#product, #product.comments.build], local: true) do |f| %>
<% if #product.comments.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#product.comments.errors.count, "error") %> prohibited this comment from being saved:</h2>
<ul>
<% #product.comments.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
comments_controller
class CommentsController < ApplicationController
def create
#product = Product.find(params[:product_id])
#comment = #product.comments.new(comment_params)
#comment.user = current_user
#comment.save
respond_to do |format|
if #comment.save
format.html { redirect_to #product, notice: 'Review was successfully created.' }
format.json { render :show, status: :created, location: #product }
else
format.html { redirect_to #product, alert: 'Review was not saved successfully.' }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
def destroy
end
private
def comment_params
params.require(:comment).permit(:user_id, :body, :rating)
end
end
Any help here is appreciated.
Issues
You can not access errors on an ActiveRecord::Relation object, but on individual Comment objects.
In your controller action create, you do redirect_to(#product) on failing to save the comment, which will ignore already built #comment object and build a new one (through form_with(model: [#product, #product.comments.build])) when rendering the comment form. Instead, you need to only render the product page with already built #comment object.
You have #comment.save twice in your create action.
Solution
products_controller.rb
def show
# your current logic
#comment = #product.comments.build
# render
end
comments_controller.rb
class CommentsController < ApplicationController
def create
#product = Product.find(params[:product_id])
#comment = #product.comments.new(comment_params)
#comment.user = current_user
respond_to do |format|
if #comment.save
format.html { redirect_to #product, notice: 'Review was successfully created.' }
format.json { render :show, status: :created, location: #product }
else
format.html { render 'products/show', alert: 'Review was not saved successfully.' }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
private
def comment_params
params.require(:comment).permit(:user_id, :body, :rating)
end
end
_new_comment.html.erb
<%= form_with(model: [#product, #comment], local: true) do |f| %>
<% if #comment.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#comment.errors.count, "error") %> prohibited this comment from being saved:</h2>
<ul>
<% #comment.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<% end %>
Related
I have 2 models, one of patients and another of indicadions, I think I have the relationships between the models correctly placed, what I cannot make it work is that the patient_id is placed in the hidden field
my models:
patient: has_many :prescription, dependent: :destroy
indication: belongs_to :patient
my view:
<%= form_with(model: prescription) do |form| %>
<% if prescription.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(prescription.errors.count, "error") %> prohibited this prescription from being saved:</h2>
<ul>
<% prescription.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= form.hidden_field :patient_id, value: "patient_id" %>
<div class="form-group">
<%= form.label :content %>
<%= form.text_area :content, class:'form-control' %>
</div>
<%= form.submit "SAVE",class:'btn save' %>
<% end %>
The controller:
class PrescriptionsController < ApplicationController
before_action :set_prescription, only: %i[ show edit update destroy ]
# GET /prescriptions or /prescriptions.json
def index
#prescriptions = Prescription.all
end
# GET /prescriptions/1 or /prescriptions/1.json
def show
end
# GET /prescriptions/new
def new
#prescription = Prescription.new
end
# GET /prescriptions/1/edit
def edit
end
# POST /prescriptions or /prescriptions.json
def create
#prescription = Prescription.new(prescription_params)
respond_to do |format|
if #prescription.save
format.html { redirect_to #prescription, notice: "La receta se creó con éxito." }
format.json { render :show, status: :created, location: #prescription }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #prescription.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /prescriptions/1 or /prescriptions/1.json
def update
respond_to do |format|
if #prescription.update(prescription_params)
format.html { redirect_to #prescription, notice: "Prescription was successfully updated." }
format.json { render :show, status: :ok, location: #prescription }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #prescription.errors, status: :unprocessable_entity }
end
end
end
# DELETE /prescriptions/1 or /prescriptions/1.json
def destroy
#prescription.destroy
respond_to do |format|
format.html { redirect_to prescriptions_url, notice: "Prescription was successfully destroyed." }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_prescription
#prescription = Prescription.find(params[:id])
end
# Only allow a list of trusted parameters through.
def prescription_params
params.require(:prescription).permit(:content, :patient_id)
end
end
Instead of using a hidden input you might actually want to nest the routes to makes the relationship explicit instead of implicit:
resources :patients do
resources :perscriptions, shallow: true
end
class PrescriptionsController < ApplicationController
before_action :set_patient
before_action :set_prescription, only: %i[ show edit update destroy ]
# GET /patients/1/prescriptions or /patients/1/prescriptions.json
def index
#prescriptions = #patient.perscriptions
end
# GET /prescriptions/1 or /prescriptions/1.json
def show
end
# GET /patients/1/prescriptions/new
def new
#prescription = Prescription.new
end
# GET /prescriptions/1/edit
def edit
end
# POST /patients/1/prescriptions or /patients/1/prescriptions.json
def create
#prescription = #patient.perscriptions.new(prescription_params)
respond_to do |format|
if #prescription.save
format.html { redirect_to #prescription, notice: "La receta se creó con éxito." }
format.json { render :show, status: :created, location: #prescription }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #prescription.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /prescriptions/1 or /prescriptions/1.json
def update
respond_to do |format|
if #prescription.update(prescription_params)
format.html { redirect_to #prescription, notice: "Prescription was successfully updated." }
format.json { render :show, status: :ok, location: #prescription }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #prescription.errors, status: :unprocessable_entity }
end
end
end
# DELETE /prescriptions/1 or /prescriptions/1.json
def destroy
#prescription.destroy
respond_to do |format|
format.html { redirect_to prescriptions_url, notice: "Prescription was successfully destroyed." }
format.json { head :no_content }
end
end
private
def set_patient
#patient = Patient.find(params[:patient_id])
end
def set_prescription
#prescription = Prescription.find(params[:id])
end
# Only allow a list of trusted parameters through.
def prescription_params
params.require(:prescription).permit(:content)
end
end
<%= form_with(model: [#patient, #perscription]) do |form| %>
<% if prescription.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(prescription.errors.count, "error") %> prohibited this prescription from being saved:</h2>
<ul>
<% prescription.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= form.label :content %>
<%= form.text_area :content, class:'form-control' %>
</div>
<%= form.submit "SAVE", class:'btn save' %>
<% end %>
Working in a Rails app with a model called Shootings. It has several fields in it, so I'm using the Wicked gem to collect them in several steps.
I'm able to create Shooting records correctly, and I'm able to start the Wicked wizard correctly if I manually type the path. However I'm not able to set the redirection after the Shooting creationg with the first step of the wizard.
I get this error in the build_controller.rb once I try to redirect after I create the shooting, to the first step of the wizard
No route matches {:action=>"show", :controller=>"shootings/build", :shooting_id=>#<Shooting id: 100, title: "cwe AVER", created_at: "2021-02-13 20:01:26.212909000 +0000", updated_at: "2021-02-13 20:01:26.212909000 +0000", user_id: 1, typeshooting: nil, numberimages: nil, proservices: nil, goals: nil, status: nil>}, missing required keys: [:id]
I'll let the code speak for itself
shootings_controller.rb
class ShootingsController < ApplicationController
before_action :set_shooting, only: %i[ show edit update destroy ]
# GET /shootings/new
def new
#shooting = Shooting.new
end
# POST /shootings or /shootings.json
def create
#shooting = Shooting.new(shooting_params)
respond_to do |format|
if #shooting.save
format.html { redirect_to shooting_build_path(#shooting), notice: "Shooting was successfully created." }
format.json { render :show, status: :created, location: #shooting }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #shooting.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /shootings/1 or /shootings/1.json
def update
respond_to do |format|
if #shooting.update(shooting_params)
format.html { redirect_to #shooting, notice: "Shooting was successfully updated." }
format.json { render :show, status: :ok, location: #shooting }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #shooting.errors, status: :unprocessable_entity }
end
end
end
end
build_controler.rb (in controllers > shootings)
class Shootings::BuildController < ApplicationController
include Wicked::Wizard
steps :add_typeshooting, :add_numberimages, :add_proservices, :add_goals
def show
#shooting = Shooting.find(params[:shooting_id])
render_wizard
end
def update
#shooting = Shooting.find(params[:shooting_id])
params[:shooting][:status] = 'active' if step == steps.last
#shooting.update(shooting_params)
render_wizard #shooting
end
def create
#shooting = Shooting.create
redirect_to wizard_path(steps.first, shooting_id: #shooting.id)
end
private
def redirect_to_finish_wizard options = nil, params = {}
redirect_to root_url, notice: 'Thanks for your shooting'
end
# Only allow a list of trusted parameters through.
def shooting_params
params.require(:shooting).permit(:title, :user_id, :typeshooting, :numberimages, :proservices, :goals)
end
def set_shooting
#shooting = Shooting.find(params[:id])
end
end
routes.rb
Rails.application.routes.draw do
resources :users
resources :shootings do
resources :build, controller: 'shootings/build'
end
resources :photos
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
root "shootings#index"
end
and rail routes
shooting_build_index GET /shootings/:shooting_id/build(.:format) shootings/build#index
POST /shootings/:shooting_id/build(.:format) shootings/build#create
new_shooting_build GET /shootings/:shooting_id/build/new(.:format) shootings/build#new
edit_shooting_build GET /shootings/:shooting_id/build/:id/edit(.:format) shootings/build#edit
shooting_build GET /shootings/:shooting_id/build/:id(.:format) shootings/build#show
PATCH /shootings/:shooting_id/build/:id(.:format) shootings/build#update
PUT /shootings/:shooting_id/build/:id(.:format) shootings/build#update
DELETE /shootings/:shooting_id/build/:id(.:format) shootings/build#destroy
shootings GET /shootings(.:format) shootings#index
POST /shootings(.:format) shootings#create
new_shooting GET /shootings/new(.:format) shootings#new
edit_shooting GET /shootings/:id/edit(.:format) shootings#edit
shooting GET /shootings/:id(.:format) shootings#show
PATCH /shootings/:id(.:format) shootings#update
PUT /shootings/:id(.:format) shootings#update
DELETE /shootings/:id(.:format) shootings#destroy
shootings form
<%= form_with(model: shooting) do |form| %>
<% if shooting.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(shooting.errors.count, "error") %> prohibited this shooting from being saved:</h2>
<ul>
<% shooting.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :title %>
<%= form.text_field :title %>
</div>
<div class="field">
<%= form.label :user_id %>
<%= form.text_field :user_id %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
You have to change following url, and it is working
format.html {
flash.now[:notice] = 'Shooting was successfully created.'
redirect_to shooting_build_index_path(#shooting)
}
Or rails way
format.html do
flash.now[:notice] = 'Shooting was successfully created.'
redirect_to shooting_build_index_path(#shooting)
end
But personally I think it should work like above but some how it is not working.
I'm trying to create a has-many association within a ruby on rails app where a user has-many goals and a goal has-many steps
I can't seem to figure out how to link the creation of a Step for a certain Goal. I've been playing around with it for a while and looking around on here but haven't found a solution.
Below are my Goal_controller, Step_Controller, Step form, and Goal form
Goal Controller:
class GoalsController < ApplicationController
before_action :set_goal, only: [:show, :edit, :update, :destroy]
before_filter :authorize
# GET /goals
# GET /goals.json
def index
#goals = Goal.all
end
# GET /goals/1
# GET /goals/1.json
def show
#goal = Goal.find(params[:id])
session[:current_goal] = #goal.id
end
# GET /goals/new
def new
#goal = Goal.new
end
# GET /goals/1/edit
def edit
end
# POST /goals
# POST /goals.json
def create
#goal = current_user.goals.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
# PATCH/PUT /goals/1
# PATCH/PUT /goals/1.json
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
# DELETE /goals/1
# DELETE /goals/1.json
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
# Use callbacks to share common setup or constraints between actions.
def set_goal
#goal = Goal.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def goal_params
params.require(:goal).permit(:Goal, :Description, :Date, :DueDate, :user_id)
end
end
Step Controller:
class StepsController < ApplicationController
#before_action :set_step, only: [:show, :edit, :update, :destroy]
before_filter :authorize
# GET /steps
# GET /steps.json
def index
#steps = Goal.find(params[:goal_id]).steps.all
end
def new
#step = Goal.find(params[:goal_id]).steps.new
end
# GET /steps/1
# GET /steps/1.json
def show
end
# GET /steps/1/edit
def edit
end
def create
#step = Goal.find(params[:goal_id]).steps.new(step_params)
respond_to do |format|
if #step.save
format.html { redirect_to #step, notice: 'Step was successfully created.' }
format.json { render :show, status: :created, location: #step }
else
format.html { render :new }
format.json { render json: #step.errors, status: :unprocessable_entity }
end
end
redirect_to(goal_steps_url(#goal))
end
def update
#step.update(step_params)
respond_to do |format|
if #step.update(step_params)
format.html { redirect_to #step, notice: 'Step was successfully updated.' }
format.json { render :show, status: :ok, location: #step }
else
format.html { render :edit }
format.json { render json: #step.errors, status: :unprocessable_entity }
end
end
end
# POST /steps
# POST /steps.json
def destroy
#step.destroy
respond_to do |format|
format.html { redirect_to steps_url, notice: 'Step was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_step
#step = Goal.find(params[:goal_id]).Step.find(params[:id])
end
def step_params
params.require(:step).permit(:requirement, :completionTime, :goal_id)
end
end
Step Form:
<%= form_for(#step) do |f| %>
<% if #step.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#step.errors.count, "error") %> prohibited this step from being saved:</h2>
<ul>
<% #step.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :requirement %><br>
<%= f.text_field :requirement %>
</div>
<div class="field">
<%= f.label :completionTime %><br>
<%= f.number_field :completionTime %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Goal Form:
<%= form_for(#goal) do |f| %>
<% if #goal.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#goal.errors.count, "error") %> prohibited this goal from being saved:</h2>
<ul>
<% #goal.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :Goal %><br>
<%= f.text_field :Goal %>
</div>
<div class="field">
<%= f.label :Description %><br>
<%= f.text_area :Description %>
</div>
<div class="field">
<%= f.label :Date %><br>
<%= f.date_select :Date %>
</div>
<div class="field">
<%= f.label :DueDate %><br>
<%= f.date_select :DueDate %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
It looks like you will be missing your goal_id when you submit your step creation form. You will need to store it either in a hidden field in your step form, or as part of the route (e.g. POST /goals/10/steps).
I'm very new to Ruby on Rails, so forgive if this is a stupid mistake.
I used a rails generate scaffold command to generate a "board" scaffold with a title:string and message:text. Now, I'm trying to go to localhost:3000/boards/new and I'm getting a "NoMethodError in Boards#show" error when I try to access board.message. I don't get any error when I try to access board.title.
Code:
form.html.erb
<%= form_for(#board) do |f| %>
<% if #board.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#board.errors.count, "error") %> prohibited this board from being saved:</h2>
<ul>
<% #board.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :message %><br />
<%= f.text_area :message %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I'm specifically getting the error on line 20 (<%= f.text_area :message %>)
board.rb
class Board < ActiveRecord::Base
attr_accessible :message, :title
has_many :posts
end
*boards_controller.rb*
class BoardsController < ApplicationController
# GET /boards
# GET /boards.json
def index
#boards = Board.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #boards }
end
end
# GET /boards/1
# GET /boards/1.json
def show
#board = Board.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #board }
end
end
# GET /boards/new
# GET /boards/new.json
def new
#board = Board.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #board }
end
end
# GET /boards/1/edit
def edit
#board = Board.find(params[:id])
end
# POST /boards
# POST /boards.json
def create
#board = Board.new(params[:board])
respond_to do |format|
if #board.save
format.html { redirect_to #board, notice: 'Board was successfully created.' }
format.json { render json: #board, status: :created, location: #board }
else
format.html { render action: "new" }
format.json { render json: #board.errors, status: :unprocessable_entity }
end
end
end
# PUT /boards/1
# PUT /boards/1.json
def update
#board = Board.find(params[:id])
respond_to do |format|
if #board.update_attributes(params[:board])
format.html { redirect_to #board, notice: 'Board was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #board.errors, status: :unprocessable_entity }
end
end
end
# DELETE /boards/1
# DELETE /boards/1.json
def destroy
#board = Board.find(params[:id])
#board.destroy
respond_to do |format|
format.html { redirect_to boards_url }
format.json { head :no_content }
end
end
end
routes.rb
Anonymous::Application.routes.draw do
resources :boards
resources :posts
root :to => "boards#index"
end
Can anyone please explain this to me?
this form (views/workers/_form.html.erb) redirects me to the index of tasksadmins, after I push the 'create tasksadmin' button.
I want it to redirect me to "workers/index" and change the button to 'update the task'.
how can I do that please?
<%= form_for(#tasksadmin) do |f| %>
<% if #tasksadmin.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#tasksadmin.errors.count, "error") %> prohibited this tasksadmin from being saved:</h2>
<ul>
<% #tasksadmin.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.hidden_field :admin_mail, :value => #tasksadmin.admin_mail %>
<%= f.hidden_field :worker_mail, :value => #worker_mail %>
<%= f.hidden_field :task, :value => #tasksadmin.task %>
<div class="field">
<%= f.label :done %><br />
<%= f.check_box :done %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
and this is my workers_controller:
class WorkersController < ApplicationController
# GET /workers
# GET /workers.json
def index
#tasks_worker = Tasksadmin.where(:worker_mail => "alon.shmiel#gmail.com")
respond_to do |format|
format.html # index.html.erb
format.json { render json: #workers }
end
end
# GET /workers/1
# GET /workers/1.json
def show
#task_worker = Tasksadmin.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #worker }
end
end
# GET /workers/new
# GET /workers/new.json
def new
#worker = Worker.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #worker }
end
end
# GET /workers/1/edit
def edit
#tasksadmin = Tasksadmin.find(params[:id])
#worker_mail = "alon.shmiel#gmail.com"
end
# POST /workers
# POST /workers.json
def create
#worker = Worker.new(params[:worker])
respond_to do |format|
if #worker.save
format.html { redirect_to "#worker", notice: 'Worker was successfully created.' }
format.json { render json: #worker, status: :created, location: #worker }
else
format.html { render action: "new" }
format.json { render json: #worker.errors, status: :unprocessable_entity }
end
end
end
# PUT /workers/1
# PUT /workers/1.json
def update
#worker = Tasksadmin.find(params[:id])
respond_to do |format|
if #worker.update_attributes(params[:worker])
format.html { render action: "index", notice: 'Worker was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #worker.errors, status: :unprocessable_entity }
end
end
end
# DELETE /workers/1
# DELETE /workers/1.json
def destroy
#worker = Tasksadmin.find(params[:id])
#worker.destroy
respond_to do |format|
format.html { render action: "index" }
format.json { render json: #worker }
end
end
end
In your controller, you have to redirect to the appropriate path like so:
def update
redirect_to "workers/index"
end
I would suggest using path helpers so if you have your routes set up as resources, you can do this:
redirect_to workers_path
As for changing the the button text, just change it to:
f.submit("update the task")
You create a form for an object #tasksadmin, which in your WorkersController#edit is set as follows:
#tasksadmin = Tasksadmin.find(params[:id]
This means that that parameter contains an object of class Tasksadmin, if you let rails build the path for the a Tasksadmin, it will send you to the TasksadminsController#update, and that is why your code does not work. You never get to the WorkersController#update. Check your logs to verify that.
Let me be very clear about this: you should not edit Tasksadmin objects in the WorkersController.
I do not understand why you would do that.