Todo has many Items. I am trying to add a link to delete an item from the todo list. I have tried variations to find an item by id under the todo list and I can't figure it out. This is the most recent error based of the the changes I made. I don't know how to fix this.
Error message: No route matches [DELETE] "/todos/6/items"
Todo Controller:
class TodosController < ApplicationController
respond_to :html, :js
before_action :set_todo, only: [:show, :edit, :update, :destroy]
# GET /todos
# GET /todos.json
def index
#todos = Todo.all
#todo = Todo.new
end
# GET /todos/1
# GET /todos/1.json
def show
end
# GET /todos/new
def new
#todo = Todo.new
#3.times{#todo.items.build}
end
# GET /todos/1/edit
def edit
end
# POST /todos
# POST /todos.json
def create
#todo = Todo.new(todo_params)
##todo.items.build
respond_to do |format|
if #todo.save
format.html { redirect_to todos_path, notice: 'Todo was successfully created.' }
format.json { render :show, status: :created, location: #todo }
else
format.html { render :new }
format.json { render json: #todo.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /todos/1
# PATCH/PUT /todos/1.json
def update
#todo = Todo.find(params[:id])
respond_to do |format|
if #todo.update(todo_params)
format.html { redirect_to #todo, notice: 'Todo was successfully updated.' }
format.json { render :show, status: :ok, location: #todo }
else
format.html { render :edit }
format.json { render json: #todo.errors, status: :unprocessable_entity }
end
end
end
# DELETE /todos/1
# DELETE /todos/1.json
def destroy
#todo.destroy
#todo.items.destroy
respond_to do |format|
format.html { redirect_to todos_url, notice: 'Todo was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_todo
#todo = Todo.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def todo_params
params.require(:todo).permit(:title, :completed, items_attributes: [:content,:completed, :_destroy])
end
end
Items Controller:
class ItemsController < ApplicationController
before_action :set_item, only: [:show, :edit, :update, :destroy]
before_action :set_todo
respond_to :html, :js
# GET /items
# GET /items.json
def index
#items = Item.all
end
# GET /items/1
# GET /items/1.json
def show
#item = Item.find(params[:id])
end
# GET /items/new
def new
#item = #todo.items.build
end
# GET /items/1/edit
def edit
#item = Items.find(params[:id])
end
# POST /items
# POST /items.json
def create
#item = #todo.items.build(item_params)
respond_to do |format|
if #item.save
format.html { redirect_to [#todo,#item], notice: 'Item was successfully created.' }
format.json { render :show, status: :created, location: #item }
else
format.html { render :new }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /items/1
# PATCH/PUT /items/1.json
def update
#item = Item.find(params[:id])
respond_to do |format|
if #item.update(item_params)
format.html { redirect_to [#todo, #item], notice: 'Item was successfully updated.' }
format.json { render :show, status: :ok, location: #item }
else
format.html { render :edit }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
# DELETE /items/1
# DELETE /items/1.json
def destroy
#todo.items.destroy
#item = Item.find(params[:id])
#item.destroy
respond_to do |format|
format.html { redirect_to #todo, notice: 'Item was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_item
#item = Item.find(params[:id])
end
def set_todo
#todo = Todo.find(params[:todo_id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def item_params
params.require(:item).permit(:content, :todo_id)
end
end
Routes:
Prefix Verb URI Pattern Controller#Action
todo_items GET /todos/:todo_id/items(.:format) items#index
POST /todos/:todo_id/items(.:format) items#create
new_todo_item GET /todos/:todo_id/items/new(.:format) items#new
edit_todo_item GET /todos/:todo_id/items/:id/edit(.:format) items#edit
todo_item GET /todos/:todo_id/items/:id(.:format) items#show
PATCH /todos/:todo_id/items/:id(.:format) items#update
PUT /todos/:todo_id/items/:id(.:format) items#update
DELETE /todos/:todo_id/items/:id(.:format) items#destroy
todos GET /todos(.:format) todos#index
POST /todos(.:format) todos#create
new_todo GET /todos/new(.:format) todos#new
edit_todo GET /todos/:id/edit(.:format) todos#edit
todo GET /todos/:id(.:format) todos#show
PATCH /todos/:id(.:format) todos#update
PUT /todos/:id(.:format) todos#update
DELETE /todos/:id(.:format) todos#destroy
and my index page:
<h1>Listing todos</h1>
<ul>
<% #todos.each do |todo| %>
<li><%= link_to todo.title ,edit_todo_path(todo)%></li>
<ul>
<% todo.items.each do |item| %></br>
<li><%= item.content %></li>
<li><%= link_to 'Delete Item',todo_item_path(item.id), method: :delete, data: { confirm: "Are you sure you want to delete this item?"} %></li>
<% end %>
</ul>
<% end %>
</ul>
<%= link_to 'New Todo', new_todo_path %>
Please try using <%= link_to "delete", [todo, item], :method => :delete %>.
Related
I have three models:
Tracks, LineItems and Cart
By using line item associations, I'm adding tracks (for purchase) to a cart. Yet when I click 'add to cart' the following error message gets thrown:
No route matches [POST] "/line_items/1"
Despite extensively reviewing my code; I can't seem to find the problem, is it in my controller for line_items? It appears as though it is trying to post a line_item with id = 1 which doesn't exist?
line_items_controller.rb
class LineItemsController < ApplicationController
include CurrentCart
before_action :set_line_item, only: [:show, :edit, :update, :destroy]
before_action :set_cart, only: [:create]
# GET /line_items
# GET /line_items.json
def index
#line_items = LineItem.all
end
# GET /line_items/1
# GET /line_items/1.json
def show
end
# GET /line_items/new
def new
#line_item = LineItem.new
end
# GET /line_items/1/edit
def edit
end
# POST /line_items
# POST /line_items.json
def create
#track = Track.find(params[:track_id])
#line_item = #cart.add_track(track)
respond_to do |format|
if #line_item.save
format.html { redirect_to #line_item, notice: 'Line item was successfully created.' }
format.json { render :show, status: :created, location: #line_item }
else
format.html { render :new }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /line_items/1
# PATCH/PUT /line_items/1.json
def update
respond_to do |format|
if #line_item.update(line_item_params)
format.html { redirect_to #line_item, notice: 'Line item was successfully updated.' }
format.json { render :show, status: :ok, location: #line_item }
else
format.html { render :edit }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
# DELETE /line_items/1
# DELETE /line_items/1.json
def destroy
#cart = Cart.find(session[:cart_id])
#line_item.destroy
respond_to do |format|
format.html { redirect_to cart_path(#cart), notice: 'Line item was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_line_item
#line_item = LineItem.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def line_item_params
params.require(:line_item).permit(:track_id)
end
end
carts_controller.rb
class CartsController < ApplicationController
rescue_from ActiveRecord::RecordNotFound, with :invalid_cart
before_action :set_cart, only: [:show, :edit, :update, :destroy]
# GET /carts
# GET /carts.json
def index
#carts = Cart.all
end
# GET /carts/1
# GET /carts/1.json
def show
end
# GET /carts/new
def new
#cart = Cart.new
end
# GET /carts/1/edit
def edit
end
# POST /carts
# POST /carts.json
def create
#cart = Cart.new(cart_params)
respond_to do |format|
if #cart.save
format.html { redirect_to #cart, notice: 'Cart was successfully created.' }
format.json { render :show, status: :created, location: #cart }
else
format.html { render :new }
format.json { render json: #cart.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /carts/1
# PATCH/PUT /carts/1.json
def update
respond_to do |format|
if #cart.update(cart_params)
format.html { redirect_to #cart, notice: 'Cart was successfully updated.' }
format.json { render :show, status: :ok, location: #cart }
else
format.html { render :edit }
format.json { render json: #cart.errors, status: :unprocessable_entity }
end
end
end
# DELETE /carts/1
# DELETE /carts/1.json
def destroy
#cart.destroy if cart.id == session[:cart_id] #hook into current client session instead of user
session[:cart_id] = nil
respond_to do |format|
format.html { redirect_to root-path, notice: 'Cart was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_cart
#cart = Cart.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def cart_params
params.fetch(:cart, {})
end
def invalid_cart
logger.error "Attempt to access invalid cart #{params[:id]}"
redirect_to root_path, notice: "That cart doesn't exist"
end
end
views > carts > show.html.haml
.keep-shopping.pv1.mt4.has-text-right
= link_to 'Keep Shopping', tracks_path, class: 'button is-warning'
%hr/
%section.section
= render(#cart.line_items)
.columns
.column
= button_to 'Empty Cart', #cart, method: :delete, data: { confirm: "Are you sure? " }, class: "button is-danger"
.column.total.has-text-right
%h4.title.is-4
%span.f5.has-text-grey Total:
= number_to_currency(#cart.total_price)
views > _line_items.html.haml (line helper partial)
.columns.align-items-center
.column.is-1
= line_item.quantity
.column.is-2
%figure.is-128x128.image
= image_tag(line_item.track.image_url(:thumb))
.column.is-9
%strong= line_item.track.name
.columns.align-items-center
.content.column.is-9
= truncate(line_item.track.description, length: 140)
.column.is-3.has-text-right
%strong.f4= number_to_currency(line_item.total_price)
.has-text-right
= link_to 'Remove Item', line_item, method: :delete, data: { confirm: "Are you sure? " }, class: "button is-small mb4"
= succeed "/" do
%hr/
I have come across this issue before. I am most definitely from your "add to cart button". I suppose your LineItem belongs_to The Cart and the product. If so when you're passing your button data to your line_item "add to cart" button, you might wanna set the current cart also so that you send over both IDs.
If possible you might want to share more code snippets of your button and your relationships.
I have 3 models: Cart, LineItems and Tracks
I add tracks to my cart via associations with line_items.
I can successfully add a track to a cart, but when I go to remove it the following error is thrown:
undefined method 'line_items' for nil:NilClass
Which is weird considering the method that throws the error doesn't raise the same error when an item gets added; any idea what gives?
The application maintains a cart attached to a user's session and uses the session id to recognise a unique cart.
helpers > application_helper.rb
module ApplicationHelper
def cart_count_over_one
if cart_has_items
return "<span class='tag is-dark'>#{cart_has_items}</span>".html_safe
end
end
def cart_has_items
total = #cart.line_items.map{ |item| item.quantity }.sum #error occurs here
return total if total > 0
end
end
views > layouts> application.html.haml
!!!
%html
%head
%title Home
%meta{:content => "width=device-width, initial-scale=1", :name => "viewport"}/
= stylesheet_link_tag 'https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css'
= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
= javascript_include_tag 'modernizr'
= csrf_meta_tags
%body{:class => yield(:body_class)}
- if flash[:notice]
.notification.is-success.global-notification
%p.notice= notice
- if flash[:alert]
.notification.is-danger.global-notification
%p.alert= alert
%nav.navbar.is-warning{"aria-label" => "main navigation", :role => "navigation"}
.navbar-brand
= link_to root_path, class:"navbar-item" do
%h1.title.is-centered Cscades
.navbar-burger.burger{"data-target" => "navbar"}
%span
%span
%span
#navbar.navbar-menu
.navbar-end
.navbar-item
.field.is-grouped
- if cart_has_items #method gets called here
= link_to cart_path(#cart), class:"navbar-item button is-warning" do
%span.icon.is-small
%i.fa.fa-shopping-cart
%span
Cart
\#{cart_count_over_one}
- if user_signed_in?
= link_to 'Sell', new_track_path, class: "navbar-item button is-dark"
.navbar-item.has-dropdown.is-hoverable
= link_to 'Account', edit_user_registration_path, class: "navbar-link"
.navbar-dropdown.is-right
= link_to current_user.name, edit_user_registration_path, class:"navbar-item"
= link_to "Log Out", destroy_user_session_path, method: :delete, class:"navbar-item"
- else
= link_to "Sign In", new_user_session_path, class:"navbar-item button is-warning"
= link_to "Sign up", new_user_registration_path, class:"navbar-item button is-warning"
= yield(:header)
.container
= yield
line_items_controller.rb
class LineItemsController < ApplicationController
include CurrentCart
before_action :set_cart, only: [:create]
before_action :set_line_item, only: [:show, :edit, :update, :destroy]
# GET /line_items
# GET /line_items.json
def index
#line_items = LineItem.all
end
# GET /line_items/1
# GET /line_items/1.json
def show
end
# GET /line_items/new
def new
#line_item = LineItem.new
end
# GET /line_items/1/edit
def edit
end
# POST /line_items
# POST /line_items.json
def create
#track = Track.find(params[:track_id])
#line_item = #cart.add_track(#track)
respond_to do |format|
if #line_item.save
format.html { redirect_to #line_item, notice: 'Line item was successfully created.' }
format.json { render :show, status: :created, location: #line_item }
else
format.html { render :new }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /line_items/1
# PATCH/PUT /line_items/1.json
def update
respond_to do |format|
if #line_item.update(line_item_params)
format.html { redirect_to #line_item, notice: 'Line item was successfully updated.' }
format.json { render :show, status: :ok, location: #line_item }
else
format.html { render :edit }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
# DELETE /line_items/1
# DELETE /line_items/1.json
def destroy
#cart = Cart.find(session[:cart_id])
#line_item.destroy
respond_to do |format|
format.html { redirect_to cart_path(#cart), notice: 'Line item was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_line_item
#line_item = LineItem.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def line_item_params
params.require(:line_item).permit(:track_id)
end
end
carts_controller.rb
class CartsController < ApplicationController
rescue_from ActiveRecord::RecordNotFound, with: :invalid_cart
before_action :set_cart, only: [:show, :edit, :update, :destroy]
# GET /carts
# GET /carts.json
def index
#carts = Cart.all
end
# GET /carts/1
# GET /carts/1.json
def show
end
# GET /carts/new
def new
#cart = Cart.new
end
# GET /carts/1/edit
def edit
end
# POST /carts
# POST /carts.json
def create
#cart = Cart.new(cart_params)
respond_to do |format|
if #cart.save
format.html { redirect_to #cart, notice: 'Cart was successfully created.' }
format.json { render :show, status: :created, location: #cart }
else
format.html { render :new }
format.json { render json: #cart.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /carts/1
# PATCH/PUT /carts/1.json
def update
respond_to do |format|
if #cart.update(cart_params)
format.html { redirect_to #cart, notice: 'Cart was successfully updated.' }
format.json { render :show, status: :ok, location: #cart }
else
format.html { render :edit }
format.json { render json: #cart.errors, status: :unprocessable_entity }
end
end
end
# DELETE /carts/1
# DELETE /carts/1.json
def destroy
#cart.destroy if cart.id == session[:cart_id] #hook into current client session instead of user
session[:cart_id] = nil
respond_to do |format|
format.html { redirect_to root-path, notice: 'Cart was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_cart
#cart = Cart.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def cart_params
params.fetch(:cart, {})
end
def invalid_cart
logger.error "Attempt to access invalid cart #{params[:id]}"
redirect_to root_path, notice: "That cart doesn't exist"
end
end
The error message says:
undefined method 'line_items' for nil:NilClass
Which as you say points to:
def cart_has_items
total = #cart.line_items.map{ |item| item.quantity }.sum #error occurs here
return total if total > 0
end
You're trying to call line_items on #cart, which in this case is apparently nil.
Try putting a check in before, changing it to something like:
def cart_has_items
return false unless #cart
total = #cart.line_items.map{ |item| item.quantity }.sum #error occurs here
return total if total > 0
end
I'm getting this error undefined method 'comments' in my rails application. I know I shouldn't do a >level 1 nested resources, but I don't know how to apply the correct way in this case.
Currently this is my routes:
resources :performance_indicators do
resources :improvement_actions do
member do
put "like" => "improvement_actions#upvote"
put "unlike" => "improvement_actions#downvote"
end
resources :comments
end
end
As I said I'm getting this error:
NoMethodError in PerformanceIndicators#show
Showing .../app/views/comments/_form.html.erb where line #1 raised:
undefined method `comments' for nil:NilClass
I don't know if my problem is in the controller. Anyone can help? :)
EDIT:
My comment/_form:
<%= form_for([#performance_indicator, #improvement_action, #improvement_action.comments.build]) do |f| %>
<div class="field">
<%= f.label :body %><br>
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
This is my CommentsController:
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
before_action :set_improvement_action
# GET /comments
# GET /comments.json
def index
end
# GET /comments/1
# GET /comments/1.json
def show
end
# GET /comments/new
def new
#comment = #improvement_action.comments.new
end
# GET /comments/1/edit
def edit
end
# POST /comments
# POST /comments.json
def create
#comment = #improvement_action.comments.new(comment_params)
if #comment.save
format.html { redirect_to [#improvement_action.performance_indicator, #improvement_action], notice: 'Comment was successfully created.' }
format.json { render :show, status: :created, location: [#improvement_action, #comment] }
else
format.html { render :new }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
# PATCH/PUT /comments/1
# PATCH/PUT /comments/1.json
def update
respond_to do |format|
if #comment.update(comment_params)
format.html { redirect_to #comment, notice: 'Comment was successfully updated.' }
format.json { render :show, status: :ok, location: #comment }
else
format.html { render :edit }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /comments/1
# DELETE /comments/1.json
def destroy
#comment.destroy
respond_to do |format|
format.html { redirect_to comments_url, notice: 'Comment was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
#comment = Comment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.require(:comment).permit(:body)
end
def set_improvement_action
#improvement_action = ImprovementAction.includes(:comments).find(params[:improvement_action_id])
end
end
Here Is my PerformanceIndicatorController:
class PerformanceIndicatorsController < ApplicationController
before_action :set_performance_indicator, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
# GET /performance_indicators
# GET /performance_indicators.json
def index
#performance_indicators = PerformanceIndicator.all
end
# GET /performance_indicators/1
# GET /performance_indicators/1.json
def show
##performance_indicators = PerformanceIndicator.all.order("created_at DESC")
end
# GET /performance_indicators/new
def new
#performance_indicator = PerformanceIndicator.new
#comments = Comment.new
end
# GET /performance_indicators/1/edit
def edit
end
# POST /performance_indicators
# POST /performance_indicators.json
def create
#performance_indicator = PerformanceIndicator.new(performance_indicator_params)
respond_to do |format|
if #performance_indicator.save
format.html { redirect_to #performance_indicator, notice: 'Performance indicator was successfully created.' }
format.json { render :show, status: :created, location: #performance_indicator }
else
format.html { render :new }
format.json { render json: #performance_indicator.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /performance_indicators/1
# PATCH/PUT /performance_indicators/1.json
def update
respond_to do |format|
if #performance_indicator.update(performance_indicator_params)
format.html { redirect_to #performance_indicator, notice: 'Performance indicator was successfully updated.' }
format.json { render :show, status: :ok, location: #performance_indicator }
else
format.html { render :edit }
format.json { render json: #performance_indicator.errors, status: :unprocessable_entity }
end
end
end
# DELETE /performance_indicators/1
# DELETE /performance_indicators/1.json
def destroy
#performance_indicator.destroy
respond_to do |format|
format.html { redirect_to performance_indicators_url, notice: 'Performance indicator was successfully destroyed.' }
format.json { head :no_content }
end
end
def set_comment
#improvement_action = ImprovementAction.find(params[:improvement_action_id])
#comment = Comment.find(params[:id])
end
private
# Use callbacks to share common setup or constraints between actions.
def set_performance_indicator
#performance_indicator = PerformanceIndicator.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def performance_indicator_params
params.require(:performance_indicator).permit(:name, :numberTimesIdentifiedProblems, :numberTimesAnalysed)
end
end
Lets start by fixing the deep nesting.
resources :performance_indicators, shallow: true do
resources :improvement_actions
end
resources :improvement_actions, only: [] do
member do
put "like" => "improvement_actions#upvote"
put "unlike" => "improvement_actions#downvote"
end
resources :comments
end
only: [] is a clever trick that nests routes under a resource but suppresses the generation of routes. We want that since the first block actually declares all the routes we need.
Prefix Verb URI Pattern Controller#Action
performance_indicator_improvement_actions GET /performance_indicators/:performance_indicator_id/improvement_actions(.:format) improvement_actions#index
POST /performance_indicators/:performance_indicator_id/improvement_actions(.:format) improvement_actions#create
new_performance_indicator_improvement_action GET /performance_indicators/:performance_indicator_id/improvement_actions/new(.:format) improvement_actions#new
edit_performance_indicator_improvement_action GET /performance_indicators/:performance_indicator_id/improvement_actions/:id/edit(.:format) improvement_actions#edit
performance_indicator_improvement_action GET /performance_indicators/:performance_indicator_id/improvement_actions/:id(.:format) improvement_actions#show
PATCH /performance_indicators/:performance_indicator_id/improvement_actions/:id(.:format) improvement_actions#update
PUT /performance_indicators/:performance_indicator_id/improvement_actions/:id(.:format) improvement_actions#update
DELETE /performance_indicators/:performance_indicator_id/improvement_actions/:id(.:format) improvement_actions#destroy
performance_indicators GET /performance_indicators(.:format) performance_indicators#index
POST /performance_indicators(.:format) performance_indicators#create
new_performance_indicator GET /performance_indicators/new(.:format) performance_indicators#new
edit_performance_indicator GET /performance_indicators/:id/edit(.:format) performance_indicators#edit
performance_indicator GET /performance_indicators/:id(.:format) performance_indicators#show
PATCH /performance_indicators/:id(.:format) performance_indicators#update
PUT /performance_indicators/:id(.:format) performance_indicators#update
DELETE /performance_indicators/:id(.:format) performance_indicators#destroy
like_improvement_action PUT /improvement_actions/:id/like(.:format) improvement_actions#upvote
unlike_improvement_action PUT /improvement_actions/:id/unlike(.:format) improvement_actions#downvote
improvement_action_comments GET /improvement_actions/:improvement_action_id/comments(.:format) comments#index
POST /improvement_actions/:improvement_action_id/comments(.:format) comments#create
new_improvement_action_comment GET /improvement_actions/:improvement_action_id/comments/new(.:format) comments#new
edit_improvement_action_comment GET /improvement_actions/:improvement_action_id/comments/:id/edit(.:format) comments#edit
improvement_action_comment GET /improvement_actions/:improvement_action_id/comments/:id(.:format) comments#show
PATCH /improvement_actions/:improvement_action_id/comments/:id(.:format) comments#update
PUT /improvement_actions/:improvement_action_id/comments/:id(.:format) comments#update
DELETE /improvement_actions/:improvement_action_id/comments/:id(.:format) comments#destroy
Un-nesting the resources means there will be a lot less hoops to jump through.
class CommentsController < ApplicationController
before_action :set_improvement_action
# GET /improvement_actions/:improvement_action_id/comments/new
def new
#comment = #improvement_action.comments.new
end
# POST /improvement_actions/:improvement_action_id/comments
def create
#comment = #improvement_action.comments.new(comment_params) do |c|
# #todo - you should associate comment with the user who created it at some point.
# c.author = current_user
end
# note that you where saving the record twice!
if #comment.save
format.html { redirect_to [#improvement_action.performance_indicator, #improvement_action], notice: 'Comment was successfully created.' }
format.json { render :show, status: :created, location: [#improvement_action, #comment] }
else
format.html { render :new }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
# ...
private
def comment_params
params.require(:comment).permit(:body)
end
def set_improvement_action
#improvement_action = ImprovementAction.includes(:comments)
.find(params[:improvement_action_id])
end
end
You should handle seeding with new records on the controller side if possible.
<%= form_for([#improvement_action, #comment]) do |f| %>
<div class="field">
<%= f.label :body %><br>
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I checked the other simple_form posts and they didn't quite hit on my problem. I have a nested resource for restaurant reviews in my routes.rb here:
Rails.application.routes.draw do
devise_for :users
resources :restaurants do
resources :reviews, except: [:show, :index]
end
My review controller seems to be set properly here:
class ReviewsController < ApplicationController
before_action :authenticate_user!
before_action :set_restaurant
before_action :set_review, only: [:edit, :update, :destroy]
# GET /reviews/new
def new
#review = Review.new
end
# GET /reviews/1/edit
def edit
end
# POST /reviews
# POST /reviews.json
def create
#review = Review.new(review_params)
#review.user_id = current_user.id
#review.restaurant_id = #restaurant.id
respond_to do |format|
if #review.save
format.html { redirect_to root_path, notice: 'Review was successfully created.' }
format.json { render :show, status: :created, location: #review }
else
format.html { render :new }
format.json { render json: #review.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /reviews/1
# PATCH/PUT /reviews/1.json
def update
respond_to do |format|
if #review.update(review_params)
format.html { redirect_to #review, notice: 'Review was successfully updated.' }
format.json { render :show, status: :ok, location: #review }
else
format.html { render :edit }
format.json { render json: #review.errors, status: :unprocessable_entity }
end
end
end
# DELETE /reviews/1
# DELETE /reviews/1.json
def destroy
#review.destroy
respond_to do |format|
format.html { redirect_to reviews_url, notice: 'Review was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_review
#review = Review.find(params[:id])
end
def set_restaurant
#restuarant = Restaurant.find(params[:restaurant_id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def review_params
params.require(:review).permit(:rating, :comment)
end
end
My restaurant controller is here:
class RestaurantsController < ApplicationController
before_action :set_restaurant, only: [:show, :edit, :update, :destroy]
# GET /restaurants
# GET /restaurants.json
def index
#restaurants = Restaurant.all
end
# GET /restaurants/1
# GET /restaurants/1.json
def show
end
# GET /restaurants/new
def new
#restaurant = Restaurant.new
end
# GET /restaurants/1/edit
def edit
end
# POST /restaurants
# POST /restaurants.json
def create
#restaurant = Restaurant.new(restaurant_params)
respond_to do |format|
if #restaurant.save
format.html { redirect_to #restaurant, notice: 'Restaurant was successfully created.' }
format.json { render :show, status: :created, location: #restaurant }
else
format.html { render :new }
format.json { render json: #restaurant.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /restaurants/1
# PATCH/PUT /restaurants/1.json
def update
respond_to do |format|
if #restaurant.update(restaurant_params)
format.html { redirect_to #restaurant, notice: 'Restaurant was successfully updated.' }
format.json { render :show, status: :ok, location: #restaurant }
else
format.html { render :edit }
format.json { render json: #restaurant.errors, status: :unprocessable_entity }
end
end
end
# DELETE /restaurants/1
# DELETE /restaurants/1.json
def destroy
#restaurant.destroy
respond_to do |format|
format.html { redirect_to restaurants_url, notice: 'Restaurant was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_restaurant
#restaurant = Restaurant.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def restaurant_params
params.require(:restaurant).permit(:name, :address, :phone, :website, :image)
end
end
and my simple_form_for is super straight forward:
<%= simple_form_for [#restaurant, #review] do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :rating %>
<%= f.input :comment %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
So, I don't know why I am getting this error :(
You need to provide the value of #restaurant which since you mispelled it as #restuarant will not work.
My application consists of Items. They have a status attribute that's a boolean. I added it to items by doing rails g migration AddStatusToItems status:boolean. To show the status of an item as either complete or pending, in the view, I just do
<% if status? %>
Complete
<% else %>
Pending
<% end %>
Oh yeah, I also added :status to the params hash in the controller.
It works as it should locally, but on Heroku the status just goes back to pending. Here's the log on Heroku. How can I get this working?
class ItemsController < ApplicationController
before_action :set_item, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show, :upvote]
# GET /items
# GET /items.json
def index
#items = Item.all.order('created_at DESC')
end
# GET /items/1
# GET /items/1.json
def show
end
# GET /items/new
def new
#item = Item.new
end
# GET /items/1/edit
def edit
end
# POST /items
# POST /items.json
def create
#item = current_user.items.new(item_params)
respond_to do |format|
if #item.save
format.html { redirect_to root_path, notice: 'Item was successfully created.' }
format.json { render action: 'show', status: :created, location: #item }
else
format.html { render action: 'new' }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /items/1
# PATCH/PUT /items/1.json
def update
respond_to do |format|
if #item.update(item_params)
format.html { redirect_to #item, notice: 'Item was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
# DELETE /items/1
# DELETE /items/1.json
def destroy
#item.destroy
respond_to do |format|
format.html { redirect_to items_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_item
#item = Item.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def item_params
params.require(:item).permit(:name, :quantity, :boughtfor, :soldfor, :user_id, :status)
end
end