{"user":["must exist"]} Error with Rails Nested Resources and Authentication - ruby-on-rails

I'm relatively new to Rails and have what I think is a relatively straightforward set-up that I'd like to use. I have users, lists, and items. Each user has many lists and each list has many items. I'm having trouble creating items after logging in.
User model:
class User < ApplicationRecord
include Authentication
has_many :examples
has_many :lists
has_many :items
end
List model:
class List < ApplicationRecord
belongs_to :user
has_many :items
end
Item model:
class Item < ApplicationRecord
belongs_to :user
belongs_to :list
end
Here are the relevant routes:
Rails.application.routes.draw do
resources :lists do
resources :items
end
I can create/read/update/delete lists with the following controller:
class ListsController < ProtectedController
before_action :set_list, only: [:show, :update, :destroy]
# GET /lists
def index
#lists = current_user.lists
render json: #lists
end
# GET /lists/1
def show
render json: List.find(params[:id])
end
# POST /lists
def create
#list = current_user.lists.build(list_params)
if #list.save
render json: #list, status: :created, location: #list
else
render json: #list.errors, status: :unprocessable_entity
end
end
# PATCH/PUT /lists/1
def update
if #list.update(list_params)
render json: #list
else
render json: #list.errors, status: :unprocessable_entity
end
end
# DELETE /lists/1
def destroy
#list.destroy
end
private
# Use callbacks to share common setup or constraints between actions.
def set_list
#list = current_user.lists.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def list_params
params.require(:list).permit(:name)
end
end
However, I can't create an item successfully. Here is my item controller:
class ItemsController < ProtectedController
before_action :set_item, only: [:show, :update, :destroy]
# GET /items
def index
#items = current_user.items
render json: #items
end
# GET /items/1
def show
render json: #item
end
# POST /items
def create
#list = List.find(params[:list_id])
#item = #list.items.create(item_params)
if #item.save
render json: #item, status: :created, location: #item
else
render json: #item.errors, status: :unprocessable_entity
end
end
# PATCH/PUT /items/1
def update
if #item.update(item_params)
render json: #item
else
render json: #item.errors, status: :unprocessable_entity
end
end
# DELETE /items/1
def destroy
#item.destroy
end
private
# Use callbacks to share common setup or constraints between actions.
def set_item
#item = current_user.items.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def item_params
params.require(:item).permit(:name, :quantity, :price, :store, :category, :notes, :user_id, :list_id)
end
end
I sign in, create a list, and then try to post an item to that list but get the following error:
{"user":["must exist"]}
Here is the message from the server:
Started POST "/lists/4/items" for 127.0.0.1 at 2017-08-09 22:47:19 -0400
Processing by ItemsController#create as */*
Parameters: {"item"=>{"name"=>"Test Item", "quantity"=>"1", "price"=>"9.99", "store"=>"Fruit Center", "category"=>"Dairy", "notes"=>"Important Note"}, "list_id"=>"4"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."token" = $1 LIMIT $2 [["token", "27e3e2a67d86cb9d3f46d20651370b74"], ["LIMIT", 1]]
List Load (0.3ms) SELECT "lists".* FROM "lists" WHERE "lists"."id" = $1 LIMIT $2 [["id", 4], ["LIMIT", 1]]
(0.1ms) BEGIN
(0.2ms) COMMIT
(0.1ms) BEGIN
(0.1ms) ROLLBACK
[active_model_serializers] Rendered ActiveModel::Serializer::Null with ActiveModel::Errors (0.06ms)
Completed 422 Unprocessable Entity in 8ms (Views: 0.5ms | ActiveRecord: 1.1ms)
Alternatively, I've tried changing the Create action for item to be this:
def create
#item = current_user.items.create(item_params)
if #item.save
render json: #item, status: :created, location: #item
else
render json: #item.errors, status: :unprocessable_entity
end
end
Doing it this way, results in a slightly different error: {"list":["must exist"]}
From the server:
Started POST "/lists/4/items" for 127.0.0.1 at 2017-08-09 23:09:20 -0400
Processing by ItemsController#create as */*
Parameters: {"item"=>{"name"=>"Test Item", "quantity"=>"1", "price"=>"9.99", "store"=>"Fruit Center", "category"=>"Dairy", "notes"=>"Important Note"}, "list_id"=>"4"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."token" = $1 LIMIT $2 [["token", "27e3e2a67d86cb9d3f46d20651370b74"], ["LIMIT", 1]]
(0.1ms) BEGIN
(0.2ms) COMMIT
(0.1ms) BEGIN
(0.1ms) ROLLBACK
[active_model_serializers] Rendered ActiveModel::Serializer::Null with ActiveModel::Errors (0.07ms)
Completed 422 Unprocessable Entity in 32ms (Views: 2.2ms | ActiveRecord: 4.1ms)
It does appear that the list_id is getting passed through in the parameters, but it's not being picked up in the create method.
I feel like I may be missing something simple. Any ideas?

Notice in your log that list_id is not inside of the item params:
Parameters: {"item"=>{"name"=>"Test Item", "quantity"=>"1", "price"=>"9.99", "store"=>"Fruit Center", "category"=>"Dairy", "notes"=>"Important Note"}, "list_id"=>"4"}
params[:list_id] # => 4
params[:item][:list_id] # => nil
You have white listed params[:item][:list_id] in your item_params, but list_id is not nested in params[:item] because in your item form you do not have a field to pass it along (would need a form input with name='item[list_id]'). Instead params[:list_id] = 4 is being set for the request based on the route /lists/4/items. You can do
def create
#item = current_user.items.build(item_params)
#item.list_id = params[:list_id]
if #item.save
render json: #item, status: :created, location: #item
else
render json: #item.errors, status: :unprocessable_entity
end
end
Note that I have called current_user.items.build instead of current_user.items.create. Using current_user.items.create will attempt to save the record immediately which you don't want to do in this case (it seems).

Related

undefined method `amoeba' rails 5.2

I'm following this tutorial for implementing a bookingsystem to my rails app. I'm currently stuck, because when I hit the 'New booking' button I get this error
undefined method `amoeba' for #<Class:0x00007fa37f7862a0>
![NoMethodError in BookingsController#create
]1
I have included gem 'amoeba' in my gem file, but it still doesn't work. Anyone know how to fix it? It would be very much appreciated.
schedule.rb
class Schedule < ApplicationRecord
# Tenant Of
belongs_to :account, :inverse_of => :schedules
accepts_nested_attributes_for :account
belongs_to :practitioner, :inverse_of => :schedules
accepts_nested_attributes_for :practitioner
has_many :bookings, :inverse_of => :schedule
accepts_nested_attributes_for :bookings
validates :start, uniqueness: { scope: :practitioner_id, message: "You have already made this time available" }
amoeba do
enable
exclude_associations :bookings
end
end
bookings_controller.rb
class BookingsController < ApplicationController
before_action :set_booking, only: [:show, :edit, :update, :destroy]
# GET /bookings
# GET /bookings.json
def index
#bookings = Booking.all
end
# GET /bookings/1
# GET /bookings/1.json
def show
end
# GET /bookings/new
def new
#booking = Booking.new
end
# GET /bookings/1/edit
def edit
end
# POST /bookings
# POST /bookings.json
def create
#booking = Booking.new(booking_params)
respond_to do |format|
if #booking.save
format.html { redirect_to #booking, notice: 'Booking was successfully created.' }
format.json { render :show, status: :created, location: #booking }
else
format.html { render :new }
format.json { render json: #booking.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /bookings/1
# PATCH/PUT /bookings/1.json
def update
respond_to do |format|
if #booking.update(booking_params)
format.html { redirect_to #booking, notice: 'Booking was successfully updated.' }
format.json { render :show, status: :ok, location: #booking }
else
format.html { render :edit }
format.json { render json: #booking.errors, status: :unprocessable_entity }
end
end
end
# DELETE /bookings/1
# DELETE /bookings/1.json
def destroy
#booking.destroy
respond_to do |format|
format.html { redirect_to bookings_url, notice: 'Booking was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_booking
#booking = Booking.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def booking_params
params.require(:booking).permit(:status, :title, :cost, :start, :cancellation_reason, :refunded, :practitioner_id, :schedule_id, :lesson_id, :account_id)
end
end
Log
Started POST "/bookings" for ::1 at 2020-03-23 12:42:06 +0100
Processing by BookingsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"IE78VI28UqOkuhXUnyY5bdvsN1S4wHw38Uu5BTZ+7ZdT0+6Ii50EThTELTiUWHuQOsOjy+MO4Dw6HyOwxJwWEw==", "booking"=>{"status"=>"Testing", "title"=>"Testing title", "cost"=>"3", "start(1i)"=>"2020", "start(2i)"=>"3", "start(3i)"=>"23", "start(4i)"=>"11", "start(5i)"=>"39", "cancellation_reason"=>"", "refunded"=>"0", "practitioner_id"=>"2", "schedule_id"=>"-1", "lesson_id"=>"2", "account_id"=>"1"}, "commit"=>"Create Booking"}
User Load (1.4ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 104 ORDER BY `users`.`id` ASC LIMIT 1
↳ /Users/kaspervalentin/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activerecord-5.2.4.1/lib/active_record/log_subscriber.rb:98
(0.3ms) BEGIN
↳ app/controllers/bookings_controller.rb:30
Account Load (0.4ms) SELECT `accounts`.* FROM `accounts` WHERE `accounts`.`id` = 1 LIMIT 1
↳ app/controllers/bookings_controller.rb:30
Lesson Load (0.4ms) SELECT `lessons`.* FROM `lessons` WHERE `lessons`.`id` = 2 LIMIT 1
↳ app/controllers/bookings_controller.rb:30
(0.3ms) ROLLBACK
↳ app/controllers/bookings_controller.rb:30
Completed 500 Internal Server Error in 63ms (ActiveRecord: 2.8ms)
NoMethodError (undefined method `amoeba' for #<Class:0x00007fa37f7862a0>):
app/models/schedule.rb:15:in `<class:Schedule>'
app/models/schedule.rb:1:in `<main>'
app/controllers/bookings_controller.rb:30:in `block in create'
app/controllers/bookings_controller.rb:29:in `create'
First of all try to inherit your model class from ActiveRecord::Base also when you are using amoeba in model you can avoid enable method which you called in amoeba do block cause you don't need to write enable if you are using somth like include_association or exclude_association

cant add to cart rails 5

my rails version is 5.0.5, i am currently developing an online store. i am following the steps on Agile web development (rails 5). i have followed the steps accordingly, i can create new products, edit products,and delete products, i am stuck at the stage where i am to add a product to cart(the "Add to cart" button shows) when i click "Add to cart" it gives me an error{cant find product with id}..........this is the error guys.
ruby 2.4.1p111 (2017-03-22 revision 58053) [i386-mingw32]
C:\Users\COMPUTER>cd desktop
C:\Users\COMPUTER\Desktop>cd trial
C:\Users\COMPUTER\Desktop\trial>cd depot
C:\Users\COMPUTER\Desktop\trial\depot>rails s
=> Booting Puma
=> Rails 5.0.5 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
*** SIGUSR2 not implemented, signal based restart unavailable!
*** SIGUSR1 not implemented, signal based restart unavailable!
*** SIGHUP not implemented, signal based logs reopening unavailable!
Puma starting in single mode...
* Version 3.10.0 (ruby 2.4.1-p111), codename: Russell's Teapot
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:3000
Use Ctrl-C to stop
Started GET "/" for 127.0.0.1 at 2017-10-22 17:44:40 +0100
ActiveRecord::SchemaMigration Load (0.0ms) SELECT "schema_migrations".* FROM "schema_migrations"
Processing by StoreController#index as HTML
Rendering store/index.html.erb within layouts/application
Product Load (4.0ms) SELECT "products".* FROM "products" ORDER BY "products"."title" ASC
Rendered store/index.html.erb within layouts/application (620.0ms)
Completed 200 OK in 1888ms (Views: 1385.1ms | ActiveRecord: 20.0ms)
Started POST "/line_items" for 127.0.0.1 at 2017-10-22 17:46:14 +0100
Processing by LineItemsController#create as HTML
Parameters: {"authenticity_token"=>"tysgjA3w3dfMA1ACBRWeigDDnDM9WDiwBDKotUwmXVVxVy0+msnR4gmkB3QV8qU8dKdLdnb5yEOS5FmdUs7LyQ=="}
Cart Load (4.0ms) SELECT "carts".* FROM "carts" WHERE "carts"."id" = ? LIMIT ? [["id", nil], ["LIMIT", 1]]
(4.0ms) begin transaction
SQL (48.0ms) INSERT INTO "carts" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2017-10-22 16:46:15.531901"], ["updated_at", "2017-10-22 16:46:15.531901"]]
(108.0ms) commit transaction
Product Load (4.0ms) SELECT "products".* FROM "products" WHERE "products"."id" = ? LIMIT ? [["id", nil], ["LIMIT", 1]]
Completed 404 Not Found in 644ms (ActiveRecord: 180.0ms)
ActiveRecord::RecordNotFound (Couldn't find Product with 'id'=):
app/controllers/line_items_controller.rb:29:in `create'
Rendering C:/Ruby24/lib/ruby/gems/2.4.0/gems/actionpack-5.0.5/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout
Rendering C:/Ruby24/lib/ruby/gems/2.4.0/gems/actionpack-5.0.5/lib/action_dispatch/middleware/templates/rescues/_source.html.erb
Rendered C:/Ruby24/lib/ruby/gems/2.4.0/gems/actionpack-5.0.5/lib/action_dispatch/middleware/templates/rescues/_source.html.erb (52.0ms)
Rendering C:/Ruby24/lib/ruby/gems/2.4.0/gems/actionpack-5.0.5/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
Rendered C:/Ruby24/lib/ruby/gems/2.4.0/gems/actionpack-5.0.5/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (24.0ms)
Rendering C:/Ruby24/lib/ruby/gems/2.4.0/gems/actionpack-5.0.5/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
Rendered C:/Ruby24/lib/ruby/gems/2.4.0/gems/actionpack-5.0.5/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (16.0ms)
Rendered C:/Ruby24/lib/ruby/gems/2.4.0/gems/actionpack-5.0.5/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (8928.0ms)
also below is the store(the default homepage that shows the products) view file.....
<p id="notice"><%= notice %></p>
<h1>Your Pragmatic Catalog</h1>
<% cache #products do %>
<% #products.each do |product| %>
<% cache #product do %>
<div class="entry">
<h3><%= product.title %></h3>
<%= image_tag(product.image_url) %>
<%= sanitize(product.description) %>
<div class="price_line">
<span class="price"><%= number_to_currency (product.price) %></span>
<%= button_to 'Add to Cart' , line_items_path %>
</div>
</div>
<% end %>
<% end %>
<% end %>
als below is the routes......
Rails.application.routes.draw do
resources :line_items
resources :carts
root 'store#index', as: 'store_index'
resources :products
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
and below is the products model ......
class Product < ApplicationRecord
validates :title, :description, :image_url, presence: true
validates :price, numericality: {greater_than_or_equal_to: 0.01}
validates :title, uniqueness: true
validates :image_url, allow_blank: true, format: {
with: %r{\.(gif|jpg|png)\Z}i,
message: 'must be a URL for GIF, JPG or PNG image.'
}
has_many :line_items
before_destroy :ensure_not_referenced_by_any_line_item
#...
private
# ensure that there are no line items referencing this product
def ensure_not_referenced_by_any_line_item
unless line_items.empty?
errors.add(:base, 'Line Items present')
throw :abort
end
end
end
below is the carts model....
class Cart < ApplicationRecord
has_many :line_items, dependent: :destroy
end
def add_product (lineitem, product_id)
current_item = line_items.find_by(product_id: product.id)
if current_item
current_item.quantity += 1
else
current_item = line_items.build(product_id: product.id)
end
current_item
end
line items model....
class LineItem < ApplicationRecord
belongs_to :product
belongs_to :cart
end
application_record.rb........
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
carts controller....
class CartsController < ApplicationController
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
respond_to do |format|
format.html { redirect_to carts_url, 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
end
application controller.....
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
end
line items controller....
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
product = Product.find (params[:product_id])
#line_item = #cart.line_items.build(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 :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
#line_item.destroy
respond_to do |format|
format.html { redirect_to line_items_url, 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(:product_id, :cart_id)
end
end
products controller...
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
# GET /products
# GET /products.json
def index
#products = Product.all
end
# GET /products/1
# GET /products/1.json
def show
end
# GET /products/new
def new
#product = Product.new
end
# GET /products/1/edit
def edit
end
# POST /products
# POST /products.json
def create
#product = Product.new(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render :show, status: :created, location: #product }
else
format.html { render :new }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /products/1
# PATCH/PUT /products/1.json
def update
respond_to do |format|
if #product.update(product_params)
format.html { redirect_to #product, notice: 'Product was successfully updated.' }
format.json { render :show, status: :ok, location: #product }
else
format.html { render :edit }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# DELETE /products/1
# DELETE /products/1.json
def destroy
#product.destroy
respond_to do |format|
format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_product
#product = Product.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def product_params
params.require(:product).permit(:title, :description, :image_url, :price)
end
end
store controller.....
class StoreController < ApplicationController
def index
#products = Product.order(:title)
end
end
Your error is ActiveRecord::RecordNotFound (Couldn't find Product with 'id'=):. This means that the controller doesn't know which product you want to add to the cart. This would be done by adding a product_id to the params of your POST.
In your view:
<%= button_to 'Add to Cart' , line_items_path %>
The line_items_path probably isn't correct. You probably want line_item_path(product_id: product.id). This will add the product's ID to the request and make it available when the controller tries to find the record here:
product = Product.find (params[:product_id])
In the view you have to send the correct product_id as suggested by Daniel Westendorf
<%= button_to 'Add to Cart' , line_items_path(product_id: product.id) %>
So, in this way when you create a new LineItem in new method of LinesItemController, you have it params
def new
#line_item = LineItem.new(params[:product_id])
end
For using the debug mode you can use byebug and you can use this step_by_step installation guide.
pry is another alternative.

Code School Screencast - Rails App From Scratch - Part 1 Error: Couldn't find Trip with 'id'=

Following codeschool.com's ruby screencast on making an app and ran into this error.
Full error is
ActiveRecord::RecordNotFound in DestinationsController#show
Couldn't find Trip with 'id'=
The error applies to the #trip instance below
GET /destinations/1.json
def show
#trip = Trip.find(params[:trip_id])
Here is the applicable code from the destinations_controller.rb:
def show
#trip = Trip.find(params[:trip_id])
#destination = Destination.find(params[:id])
end
Here is the Trip model
class Trip < ActiveRecord::Base
has_many :destinations
end
And the Destination model
class Destination < ActiveRecord::Base
belongs_to :trip
end
Routes
Rails.application.routes.draw do
resources :destinations
resources :trips do
resources :destinations
end
root to: 'trips#index'
Any help is greatly appreciated. :) :) :)
Update 1: From log files
Started GET "/destinations/4" for ::1 at 2016-03-31 00:50:08 +0900
Processing by DestinationsController#show as HTML Parameters:
{"id"=>"4"}
[1m[35mDestination Load (0.6ms)[0m SELECT "destinations".* FROM
"destinations" WHERE "destinations"."id" = ? LIMIT 1 [["id", 4]]
[1m[36mTrip Load (0.3ms)[0m [1mSELECT "trips".* FROM "trips"
WHERE "trips"."id" = ? LIMIT 1[0m [["id", nil]]
Completed 404 Not Found in 20ms (ActiveRecord: 1.8ms)
ActiveRecord::RecordNotFound (Couldn't find Trip with 'id'=):
app/controllers/destinations_controller.rb:14:in `show'*
Update 2 : the destinations_controller in its entirety.
class DestinationsController < ApplicationController
before_action :set_destination, only: [:show, :edit, :update, :destroy]
# GET /destinations
# GET /destinations.json
def index
#destinations = Destination.all
end
# GET /destinations/1
# GET /destinations/1.json
def show
Rails.logger.debug params.inspect
#trip = Trip.find(params[:trip_id])
#destination = Destination.find(params[:id])
end
# GET /destinations/new
def new
#trip = Trip.find(params[:trip_id])
#destination = Destination.new
end
# GET /destinations/1/edit
def edit
#trip = Trip.find(params[:trip_id])
#destination = Destination.find(set_destination)
end
# POST /destinations
# POST /destinations.json
def create
#trip = Trip.find(params[:trip_id])
#destination = #trip.destinations.new(destination_params)
respond_to do |format|
if #destination.save
format.html { redirect_to trip_destination_path(#trip, #destination), notice: 'Destination was successfully created.' }
format.json { render :show, status: :created, location: #destination }
else
format.html { render :new }
format.json { render json: #destination.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /destinations/1
# PATCH/PUT /destinations/1.json
def update
respond_to do |format|
if #destination.update(destination_params)
format.html { redirect_to #destination, notice: 'Destination was successfully updated.' }
format.json { render :show, status: :ok, location: #destination }
else
format.html { render :edit }
format.json { render json: #destination.errors, status: :unprocessable_entity }
end
end
end
# DELETE /destinations/1
# DELETE /destinations/1.json
def destroy
#destination.destroy
respond_to do |format|
format.html { redirect_to destinations_url, notice: 'Destination was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_destination
#destination = Destination.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def destination_params
params.require(:destination).permit(:name, :description)
end
end
Change the show action to this:
def show
#trip = #destination.trip
end
Edit: Removed #destination assignment here because of the before_action running set_destination.
The Destination model has one Trip:
class Destination < ActiveRecord::Base
belongs_to :trip
end
Since you're setting the #destination because id is actually passed over, you can just get #trip through association.
In your routes you currently have a nested route for destinations:
resources :trips do
resources :destinations
end
This means a destination is expected to be accessed in the context of its trip.
e.g. GET /trips/1/destinations/1.json where you'll have a trip_id parameter for the trip and an id parameter for the id of the destination.
You're also defining an non-nested route for destinations:
resources :destinations
but your DestinationController's show action assumes the nested version is being used when it does:
#trip = Trip.find(params[:trip_id])
#destination = Destination.find(params[:id])
Have a check that the GET request matches what's being shown in the screencast - or post a link to the exact screencast you're following.

Rails can't render JSON undefined method `new' for nil:NilClass

Background
I'm making a Rails application which has two namespaces, which are admin (for administrator purpose) and api for mobile & web client.
A weird thing happened yesterday. I made a new table facilities which consists of id, name, created_at, updated_at in my PostgreSQL database.
Problem
I tried to get all facilities using admin namespace http://localhost:3000/admin/facilities and it works well (return the HTML and the list of facilities).
Started GET "/admin/facilities" for ::1 at 2015-05-10 16:12:47 +0800
Processing by Admin::FacilitiesController#index as HTML
Facility Load (0.4ms) SELECT "facilities".* FROM "facilities"
Rendered admin/facilities/index.html.erb within layouts/application (2.5ms)
Completed 200 OK in 91ms (Views: 90.4ms | ActiveRecord: 0.4ms)
But when I call http://localhost:3000/api/v1/facilities from browser, which supposed to return JSON. I got an error
NoMethodError in Api::V1::FacilitiesController#index
undefined method `new' for nil:NilClass
Extracted source (around line #8):
6 def index
7 #facilities = Facility.all
8 render json: #facilities
9 end
10
11
The error from console
Started GET "/api/v1/facilities" for ::1 at 2015-05-10 16:38:26 +0800
Processing by Api::V1::FacilitiesController#index as HTML
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" IS NULL ORDER BY "users"."id" ASC LIMIT 1
Facility Load (0.5ms) SELECT "facilities".* FROM "facilities"
Completed 500 Internal Server Error in 6ms (ActiveRecord: 1.1ms)
NoMethodError (undefined method `new' for nil:NilClass):
app/controllers/api/v1/facilities_controller.rb:8:in `index'
Rendered /Users/abrahamks/.rvm/gems/ruby-2.2.1/gems/actionpack-4.2.1/lib/action_dispatch/middleware/templates/rescues/_source.erb (7.1ms)
Rendered /Users/abrahamks/.rvm/gems/ruby-2.2.1/gems/actionpack-4.2.1/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (2.7ms)
. . . .
. . . .
and so on
I check from rails c and call Facility.all and looks like the command line return correct values, but I don't understand why it can't render / return json.
Loading development environment (Rails 4.2.1)
2.2.1 :001 > Facility.all
Facility Load (0.5ms) SELECT "facilities".* FROM "facilities"
=> #<ActiveRecord::Relation [#<Facility id: 1, name: "Kitchen", created_at: "2015-05-09 10:54:00", updated_at: "2015-05-09 16:08:48">, #<Facility id: 2, name: "Washer", created_at: "2015-05-09 11:20:40", updated_at: "2015-05-09 16:09:32">, #<Facility id: 3, name: "Swimming Pool", created_at: "2015-05-09 11:22:19", updated_at: "2015-05-09 16:09:41">, #<Facility id: 4, name: "Internet", created_at: "2015-05-09 11:24:02", updated_at: "2015-05-09 16:12:31">, #<Facility id: 5, name: "Dryer", created_at: "2015-05-09 15:55:36", updated_at: "2015-05-09 16:12:54">]>
What's wrong with my code? Is there any configuration that I missed?
Thank you.
More Details if Needed
# GET /facilities/1
facilities has many-to-many relationship with properties, I generate a join table
class CreateJoinTablePropertiesFacilities < ActiveRecord::Migration
def change
create_join_table :properties, :facilities do |t|
t.index [:property_id, :facility_id]
t.index [:facility_id, :property_id]
end
end
end
Here is my facility.rb
class Facility < ActiveRecord::Base
has_and_belongs_to_many :property, join_table: :facilites_properties
end
Here is my routes.rb
Rails.application.routes.draw do
namespace :admin do
resources :facilities
end
namespace :api do
namespace :v1 do
resources :properties
resources :facilities, only: [:index, :show]
resources :users do
member do
post 'list', :to => "users#list_property"
end
end
Here is my app/controllers/api/v1/facilities_controller
class Api::V1::FacilitiesController < ApplicationController
before_action :set_facility, only: [:show, :edit, :update, :destroy]
# before_action :authenticate
# GET /facilities
# GET /facilities.json
def index
#facilities = Facility.all
render json: #facilities
end
# GET /facilities/1
# GET /facilities/1.json
def show
render json: #facility
end
private
# Use callbacks to share common setup or constraints between actions.
def set_facility
#facility = Facility.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def facility_params
params.require(:facility).permit(:name)
end
end
And this is app/controllers/admin/facilities_controller
class Admin::FacilitiesController < ApplicationController
before_action :set_facility, only: [:show, :edit, :update, :destroy]
# before_action :authenticate
# GET /facilities
# GET /facilities.json
def index
#facilities = Facility.all
end
# GET /facilities/1
# GET /facilities/1.json
def show
end
# GET /facilities/new
def new
#facility = Facility.new
end
# GET /facilities/1/edit
def edit
end
# POST /facilities
# POST /facilities.json
def create
#facility = Facility.new(facility_params)
respond_to do |format|
if #facility.save
format.html { redirect_to admin_facilities_path, notice: 'Facility was successfully created.' }
format.json { render :show, status: :created, location: #facility }
else
format.html { render :new }
format.json { render json: #facility.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /facilities/1
# PATCH/PUT /facilities/1.json
def update
respond_to do |format|
if #facility.update(facility_params)
format.html { redirect_to admin_facilities_path, notice: 'Facility was successfully updated.' }
format.json { render :show, status: :ok, location: #facility }
else
format.html { render :edit }
format.json { render json: #facility.errors, status: :unprocessable_entity }
end
end
end
# DELETE /facilities/1
# DELETE /facilities/1.json
def destroy
#facility.destroy
respond_to do |format|
format.html { redirect_to facilities_url, notice: 'Facility was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_facility
#facility = Facility.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def facility_params
params.require(:facility).permit(:name)
end
end
The stack trace is showing the request was processed as HTML.
Processing by Admin::FacilitiesController#index as HTML
As you are trying to render JSON, you can either specify the controller to respond to json
module Api
module V1
class FacilitiesController < ApplicationController
respond_to :json
end
end
end
Or you can specify json as a default response within your routes.rb file
namespace :api, defaults: { format: 'json' } do
# your api json routes...
end
Hope either one of these help.
I just realised I forgot to generate the serializer. Since I use gem Active Model Serializers, this is what I did to generate the serializer.
rails g serializer facility

Sortable Table Row with Nested Resource

In my rails app, a Timesheet has_many Entries and an Entry belongs_to a Timesheet.
class Timesheet < ActiveRecord::Base
has_many :entries, order: 'position', dependent: :destroy
end
class Entry < ActiveRecord::Base
belongs_to :timesheet
end
I'm following Railscast 147 for sortable lists (the updated version). In the development log I notice that my params hash correctly updates the sort order, but on reload it doesn't save the positions correctly. Furthermore, the request is being processed by the create action instead of my custom sort action. Here's my controller.
class EntriesController < ApplicationController
before_filter :signed_in_user
before_filter :find_timesheet
def index
#entries = #timesheet.entries.order("position")
#entry = #timesheet.entries.build
end
def create
#entry = #timesheet.entries.build(params[:entry])
#entry.position = #timesheet.entries.count + 1
if #entry.save
#flash[:notice] = "Entry created"
#redirect_to timesheet_entries_path
respond_to do |format|
format.html { redirect_to timesheet_entries_path }
format.js
end
else
flash[:alert] = "Entry could not be added"
render 'new'
end
end
def destroy
#entry = #timesheet.entries.find(params[:id])
#entry.destroy
respond_to do |format|
format.html { redirect_to timesheet_entries_path, flash[:notice] = "Entry destroyed" }
format.js
end
end
def sort
params[:entry].each_with_index do |id, index|
#timesheet.entries.update_all({position: index+1}, {id: id})
end
render nothing: true
end
private
def find_timesheet
#timesheet = Timesheet.find(params[:timesheet_id])
end
end
and my routes.rb file.
Sledsheet::Application.routes.draw do
resources :timesheets do
resources :entries, only: [:index, :create, :destroy] do
collection { post :sort }
end
end
end
The entries.js.coffee
jQuery ->
$("#entries tbody").sortable(
helper: fixHelper
update: ->
$.post($(this).data('update-url'), $(this).sortable('serialize'))
).disableSelection()
The output from the development log
Started POST "/timesheets/8/entries" for 127.0.0.1 at 2012-06-04 20:14:18 -0400
Processing by EntriesController#create as */*
Parameters: {"entry"=>["60", "59", "61"], "timesheet_id"=>"8"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."remember_token" = 'qDs53hgOWfRMbNN9JKau3w' LIMIT 1
Timesheet Load (0.1ms) SELECT "timesheets".* FROM "timesheets" WHERE "timesheets"."id" = ? ORDER BY date DESC LIMIT 1 [["id", "8"]]
Completed 500 Internal Server Error in 2ms
NoMethodError (undefined method `stringify_keys' for "60":String):
app/controllers/entries_controller.rb:11:in `create'
I googled the error about the undefined method, but I'm confused why the create action would be called in this case anyway? I do have a new_entry form on the page, that creates a new entry via Ajax. Perhaps this is interfering with the sort? Any help would be appreciated!
The reason why there's no 'stringify_keys' method is because you're passing an array to the create action and not the sort action.
What do you have for data-update-url in your erb.html file?
Should be sort_entries_path.

Resources