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
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 three models City, Area and User
In new user form after clicking on submit button server/app is not redirecting to show action
(my routes file config/routes)
Rails.application.routes.draw do
resources :areas
resources :cities
get 'users/update_cities'
resources :users
(user controller app/controllers/users_controller.rb )
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
def update_cities
#areas = Area.where("city_id = ?", params[:city_id])
respond_to do |format|
format.js
end
end
# GET /users
# GET /users.json
def index
#users = User.all
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
#user = User.new
#cities = City.all
#areas = Area.where("city_id = ?", City.first.id)
end
# GET /users/1/edit
def edit
end
# POST /users
# POST /users.json
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
#user.area_ids = [params[:user][:area_id]]
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:name, :brief,:area_id)
end
end
and form (app/views/users/_form.html.erb)
(labels not included just to clean up d code a bit )
<%= form_for(#user, remote: true) do |f| %>
<%= f.text_field :name %>
<%= f.select :city_id, options_for_select(#cities.collect { |city|
[city.name.titleize, city.id] }), {include_blank: 'Select Something'}, { id: 'cities_select'} %>
<%= f.select :area_id, options_for_select(#areas.collect { |area|
[area.name.titleize, area.id] }, 0), {}, { id: 'areas_select' } %>
<%= f.submit %>
please help.. !
The remote: true parameter in your form is causing the problem. This setting is useful when you want to update/create an object, without updating the view you're in.
For more information you can check ruby on rails API
I'm trying to build a shopping cart that is assigned to a user. What happens now though is when an item is added to the shopping cart, it's added for every user. It seems every user is using the same cart and I can't get users from being able to add to to other users carts. How can I make it so that each user has a unique cart and can only add to theirs?
Here's what I have:
class CartsController < ApplicationController
before_action :set_cart, only: [:show, :edit, :update, :destroy]
before_action :logged_in_user, only: [:create, :edit, :update, :destroy, :show]
rescue_from ActiveRecord::RecordNotFound, with: :invalid_cart
# 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 action: 'show', status: :created, location: #cart }
else
format.html { render action: '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 { head :no_content }
else
format.html { render action: '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]
session[:cart_id] = nil
respond_to do |format|
format.html { redirect_to store_url, notice: "Your cart is currently empty" }
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[:cart]
end
def invalid_cart
logger.error "Attempt to access invalid cart #{params[:id]}"
redirect_to store_url, notice: "Invalid Cart"
end
end
current_cart.rb
module CurrentCart
extend ActiveSupport::Concern
private
def set_cart
#cart = Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
#cart = Cart.create
session[:cart_id] = #cart.id
end
end
line_item_controller.rb
class LineItemsController < ApplicationController
include CurrentCart
before_action :set_cart, only: [:new, :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
product = Product.find(params[:product_id])
#line_item = #cart.add_product(product: product)
respond_to do |format|
if #line_item.save
format.html { redirect_to #line_item.cart, notice: 'Line item was successfully created.' }
format.json { render action: 'show', status: :created, location: #line_item }
else
format.html { render action: '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.cart, notice: 'Line item was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: '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
#line_item.destroy
respond_to do |format|
format.html { redirect_to line_items_url }
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(:product_id )
end
end
Instead of Cart.create and Cart.find in CurrentCart.rb, you should do something like:
def set_cart
#cart = current_user.carts.find_by(id: session[:cart_id]) || current_user.carts.create
session[:cart_id] = #cart.id
end
find_by doesn't throw an error if it can't find it; it just returns nil, so you don't have to worry about rescuing.
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.
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 %>.