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
Related
When I add the validates before my case it works normal, but add the validates after give me a error
Started POST "/users" for 106.37.100.61 at 2018-08-20 07:19:33 +0000
Cannot render console from 106.37.100.61! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
(0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
Processing by UsersController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"UrrKnE8xR9phK4WEdyrgxgJSItgopSno2ZfyTHC1AIKG3WEs4iE17gDzp5xGzxXSrLG0cqOPP1cht7AvOSQMqQ==", "user"=>{"name"=>"", "email"=>""}, "commit"=>"Create User"}
(0.1ms) begin transaction
(0.1ms) rollback transaction
Completed 500 Internal Server Error in 25ms (ActiveRecord: 0.8ms)
NoMethodError (undefined method `User' for #):
app/controllers/users_controller.rb:31:in 'block in create'
app/controllers/users_controller.rb:30:in 'create'
This is my model:
class User < ApplicationRecord
has_many :microposts
validates :name, presence: true
validates :email, presence: true
end
My controller:
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
before_action :set_user_micropost, only: [:show, :edit, :update, :destroy]
# 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
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
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
def set_user_micropost
#microposts = #user.microposts
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:name, :email)
end
end
I know what happen for this
validates :name, presence: true
validates :email, presence: true
I change the model in user.rb file
It works
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.
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).
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") %>
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.