Rails can't render JSON undefined method `new' for nil:NilClass - ruby-on-rails

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

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

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

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).

FriendlyId redirecting to the basket instead or correct links

I have just installed FriendlyID to change the urls of my site.
I have set this up for the categories although the links change as they should do when I click on them the url changes to basket/(correct-product).
It's really bugging and I have been through the code below and removed all the basket references and it still happens.
Can anyone point me in the correct direction?
Category.rb
class Category < ActiveRecord::Base
extend FriendlyId
friendly_id :title, use: [:slugged, :history]
has_many :products
end
This is the code that runs in the console:
Started GET "/categories/log-stores" for 88.97.48.111 at 2017-04-10 13:03:11 +0000
Cannot render console from 88.97.48.111! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by CategoriesController#show as HTML
Parameters: {"id"=>"log-stores"}
Category Load (0.2ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`id` = 0 LIMIT 1
Redirected to https://market2-walsh259.c9users.io/baskets/log-stores
Completed 302 Found in 2ms (ActiveRecord: 0.2ms)
Started GET "/baskets/log-stores" for 88.97.48.111 at 2017-04-10 13:03:11 +0000
Cannot render console from 88.97.48.111! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by BasketsController#show as HTML
Parameters: {"id"=>"log-stores"}
Basket Load (0.2ms) SELECT `baskets`.* FROM `baskets` WHERE `baskets`.`id` = 0 LIMIT 1
Redirected to https://market2-walsh259.c9users.io/baskets/log-stores
Completed 302 Found in 2ms (ActiveRecord: 0.2ms)
Started GET "/baskets/log-stores" for 88.97.48.111 at 2017-04-10 13:03:11 +0000
Cannot render console from 88.97.48.111! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by BasketsController#show as HTML
Parameters: {"id"=>"log-stores"}
Basket Load (0.2ms) SELECT `baskets`.* FROM `baskets` WHERE `baskets`.`id` = 0 LIMIT 1
Redirected to https://market2-walsh259.c9users.io/baskets/log-stores
Completed 302 Found in 2ms (ActiveRecord: 0.2ms)
Started GET "/baskets/log-stores" for 88.97.48.111 at 2017-04-10 13:03:11 +0000
Cannot render console from 88.97.48.111! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by BasketsController#show as HTML
Parameters: {"id"=>"log-stores"}
Basket Load (0.2ms) SELECT `baskets`.* FROM `baskets` WHERE `baskets`.`id` = 0 LIMIT 1
Redirected to https://market2-walsh259.c9users.io/baskets/log-stores
Completed 302 Found in 2ms (ActiveRecord: 0.2ms)
My categories_controller.rb
class CategoriesController < ApplicationController
before_action :set_category, only: [:show, :edit, :update, :destroy]
before_action :set_basket, only: [:show, :destroy]
rescue_from ActiveRecord::RecordNotFound, with: :invalid_basket
# GET /categories
# GET /categories.json
def index
#categories = Category.all
#top_ups = #categories [8]
#log_stores = #categories [6]
#smokeless_coal = #categories [5]
#log_packages = #categories [4]
#seasoned_logs = #categories [3]
#kiln_dried_hardwood_logs = #categories [1]
#logs_for_pizza_ovens = #categories [2]
#logs_for_firepits = #categories [9]
end
# GET /categories/1
# GET /categories/1.json
def show
#products = Product.where(category_id: params[:id])
if request.path != category_path(#category)
redirect_to #category, status: :moved_permanently
end
end
# GET /categories/new
def new
#category = Category.new
end
# GET /categories/1/edit
def edit
end
# POST /categories
# POST /categories.json
def create
#category = Category.new(category_params)
respond_to do |format|
if #category.save
format.html { redirect_to #category, notice: 'Category was successfully created.' }
format.json { render :show, status: :created, location: #category }
else
format.html { render :new }
format.json { render json: #category.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /categories/1
# PATCH/PUT /categories/1.json
def update
respond_to do |format|
if #category.update(category_params)
format.html { redirect_to #category, notice: 'Category was successfully updated.' }
format.json { render :show, status: :ok, location: #category }
else
format.html { render :edit }
format.json { render json: #category.errors, status: :unprocessable_entity }
end
end
end
# DELETE /categories/1
# DELETE /categories/1.json
def destroy
#category.destroy
respond_to do |format|
format.html { redirect_to categories_url, notice: 'Category was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_category
#category = Category.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def category_params
params.require(:category).permit(:title, :description)
end
def set_basket
#basket = Basket.find(params[:id])
end
def basket_params
params[:basket]
end
def invalid_basket
logger_error = 'Your trying to access an invalid basket'
redirect_to basket_url, notice: 'Invalid basket'
end
end
Baskets_controller.rb
class BasketsController < ApplicationController
before_action :set_basket, only: [:show, :destroy]
rescue_from ActiveRecord::RecordNotFound, with: :invalid_basket
def new
#basket = Basket.new
end
def show
#basket = Basket.find(params[:id])
end
def index
#basket = Basket.find(params[:id])
end
def destroy
#basket.destroy if #basket.id == session[:basket_id]
session[:basket_id] = nil
redirect_to home_url, notice: 'Your basket is empty'
end
private
def set_basket
#basket = Basket.find(params[:id])
end
def basket_params
params[:basket]
end
def invalid_basket
logger_error = 'Your trying to access an invalid basket'
redirect_to basket_url, notice: 'Invalid basket'
end
end
Basket.rb
class Basket < ActiveRecord::Base
has_many :product_items, dependent: :destroy
def add_product(product_id)
current_item = product_items.find_by(product_id: product_id)
if current_item
current_item.quantity += 1
else
current_item = product_items.build(product_id: product_id)
end
current_item
end
def total_price
product_items.to_a.sum{|item| item.total_price}
end
end
Application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
before_action :set_basket, only: [:show, :destroy]
protect_from_forgery with: :exception
def set_basket
#basket = Basket.find(params[:id])
end
private
def basket_params
params[:basket]
end
def invalid_basket
logger_error = 'Your trying to access an invalid basket'
redirect_to basket_url, notice: 'Invalid basket'
end
end
The database has the following:
create_table "categories", force: :cascade do |t|
t.string "title", limit: 255
t.text "description", limit: 65535
t.string "slug", limit: 255
end
add_index "categories", ["slug"], name: "index_categories_on_slug", using: :btree
create_table "friendly_id_slugs", force: :cascade do |t|
t.string "slug", limit: 255, null: false
t.integer "sluggable_id", limit: 4, null: false
t.string "sluggable_type", limit: 50
t.string "scope", limit: 255
t.datetime "created_at"
end
add_index "friendly_id_slugs", ["slug", "sluggable_type", "scope"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type_and_scope", unique: true, using: :btree
add_index "friendly_id_slugs", ["slug", "sluggable_type"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type", using: :btree
add_index "friendly_id_slugs", ["sluggable_id"], name: "index_friendly_id_slugs_on_sluggable_id", using: :btree
add_index "friendly_id_slugs", ["sluggable_type"], name: "index_friendly_id_slugs_on_sluggable_type", using: :btree
Routes.rb
Rails.application.routes.draw do
mount Ckeditor::Engine => '/ckeditor'
resources :vans
devise_for :users
# Change get method for user signout
devise_scope :user do
get '/users/sign_out' => 'devise/sessions#destroy'
end
root 'pages#index'
resources :categories
resources :products
resources :drivers
resources :product_items
resources :baskets
resources :orders
resources :customers
match '/areascovered', to: 'pages#areascovered', via: :get
match '/deliveryschedule', to: 'pages#deliveryschedule', via: :get
match '/news', to: 'pages#news', via: :get
match '/faqs', to: 'pages#faqs', via: :get
match '/about', to: 'pages#about', via: :get
match '/contact', to: 'pages#contact', via: :get
get "baskets" => "baskets#show", :as => "current_basket"
end
You need to use the friendly find method in your controllers. For example, instead of
def set_category
#category = Category.find(params[:id])
end
You should use:
def set_category
#category = Category.friendly.find(params[:id])
end
Also, watch out for instances where you are performing a find operation twice. For example, in your BasketsController#show action, you are calling set_basket (which currently calls Basket.find(params[:id]), and which you should change to perform Basket.friendly.find(params[:id]) by means of a before_action, but then you set the same instance variable again in the body of the #show action. Your BasketsController#show action should be just:
def show
end

Unpermitted parameter: format

I don't understand why I'm geting these Unpermitted parameter: format messages, I'm doing a JSON request: POST "/questions/add_options.json" with these parameters Parameters: {"id_question"=>551, "options"=>[{"position"=>10, "label"=>"opc 10", "value"=>"opc 10", "go_page"=>nil}], "question"=>{}} and this is what I get in the terminal...
Started POST "/questions/add_options.json" for 127.0.0.1 at 2016-08-16 23:12:27 -0300
Processing by QuestionsController#add_options as JSON
Parameters: {"id_question"=>551, "options"=>[{"position"=>10, "label"=>"opc 10", "value"=>"opc 10", "go_page"=>nil}], "question"=>{}}
User Load (0.4ms) SELECT "login_aexa".* FROM "login_aexa" WHERE "login_aexa"."usuaex_id" = $1 ORDER BY "login_aexa"."usuaex_id" ASC LIMIT 1 [["usuaex_id", 1]]
Unpermitted parameter: format
Question Load (0.4ms) SELECT "questions".* FROM "questions" WHERE "questions"."id" = $1 LIMIT 1 [["id", 551]]
Unpermitted parameter: format
(0.2ms) BEGIN
(0.4ms) SELECT COUNT(*) FROM "options" WHERE "options"."question_id" = $1 [["question_id", 551]]
In the Rails controller I use params permit to reject parameters that are not allowed, like this:
def question_add_options_params
params.permit(:id_question, options: [:position, :label, :value, :go_page], question: {})
end
In my opinion the format should be fine, anyone know why I'm getting those Unpermitted parameter: format messages?
EDIT:
Here's the code of the controller
class QuestionsController < ApplicationController
before_action :set_question, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
# GET /questions
# GET /questions.json
def index
#questions = Question.all
end
# GET /questions/1
# GET /questions/1.json
def show
end
# GET /questions/new
def new
#question = Question.new
end
# GET /questions/1/edit
def edit
end
# POST /questions
# POST /questions.json
def create
#question = Question.new(question_params)
respond_to do |format|
if #question.save
format.html { redirect_to #question, notice: 'Question was successfully created.' }
format.json { render :show, status: :created, location: #question }
else
format.html { render :new }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /questions/1
# PATCH/PUT /questions/1.json
def update
respond_to do |format|
if #question.update(question_params)
format.html { redirect_to #question, notice: 'Question was successfully updated.' }
format.json { render :show, status: :ok, location: #question }
else
format.html { render :edit }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
def add_options
#question = Question.find(question_add_options_params[:id_question])
question_add_options_params[:options].each do|q_aop|
#question.options.create(q_aop)
end
#options = #question.options
end
# DELETE /questions/1
# DELETE /questions/1.json
def destroy
#question.destroy
respond_to do |format|
format.html { redirect_to questions_url, notice: 'Question was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_question
#question = Question.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def question_params
params[:question]
end
def question_add_options_params
params.permit(:id_question, options: [:position, :label, :value, :go_page])
end
end
params.permit(:id_question, options: [:position, :label, :value, :go_page], question: {})
This line is telling Rails that the only params that are permitted are in the list above.
If you actually look at a real params-hash, it doesn't just contain the params passed in by the form, it also contains things like: :controller => :questions, :action => :create, :format => :json etc... which Rails always inserts based on the URL
Normally we namespace the form by using eg form_for #question which means the params come in like this:
{:controller => :questions, :action => :create,
:format => :json,
:question => {"id_question"=>551, "options"=>[{"position"=>10, "label"=>"opc 10", "value"=>"opc 10", "go_page"=>nil}]}
}
then you can do this in your controller:
params.require(:question).permit(:id_question, options: [:position, :label, :value, :go_page])
which doesn't literally tell rails that you aren't allowed to have the controller/action/format params that are always passed in by rails...
Obviously you'll need to modify the names of these to suit your needs, but this is what you need to do to stop the error.
I was having a similar issue with my JSON and thought this question could use a few more examples.
TL;DR
To avoid the Unpermitted parameter: format with JSON requests be sure to nest your request object for POST and PATCH requests (ex. { question: {name: '', prompt: ''} } and access with params.require(:question).permit(:name, :prompt, ..) in the controller. For GET and DELETE requests, use only params.require(:id) in the controller.
To build on Taryn's reply above, I needed to create a nested object in my front end for POST requests, and fix how I was using require and permit on the back end. Here are examples:
Example: POST /questions
Rails expects a post request to be of the form, { question: { name: '', prompt: '', ..} }. In the front end:
// bad
$http.post('/questions.json', { name: 'Question 1', prompt: 'Bears eat beets?' })
// good
$http.post('/questions.json', { question: { name: 'Question 1', prompt: '...' } })
Backend:
# app/controllers/questions_controller.rb
def question_params
# bad - logs 'Unpermitted parameter: format'
params.permit(:name, :prompt)
# good
params.require(:question).permit(:name, :prompt)
end
Example: GET /questions/:id
My mistake was in the backend again. For example:
# app/controllers/questions_controller.rb
def show
# bad - logs 'Unpermitted parameter: format'
question = Question.where(params.permit(:id)).first
# good
question = Question.find(params.require(:id))
render json: question
end
<%= link_to "Questinons", questions_path(format: "json") %>

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.

Resources