I have recently changed my database from sqlite3 to Postgres so I could launch it to Heroku. Thus I made all the changes to my database and Gemfile, and lauched. The Heroku app is working well, but when I go back to my local branch I am triggering this error.
ActiveRecord::RecordNotFound in Devise::SessionsController#new
Couldn't find Order with 'id'=2
def current_order
if !session[:order_id].nil?
Order.find(session[:order_id])
else
Order.new
end
Which has me confused because a) Again the Heroku app is working well. and b) Because the conditional clearly states that if order id is nil it should just Make a new order. Why would it freak out if it can't find the id?
As you can see, I am using devise. Here are my cart-relevant models:
class CartsController < ApplicationController
def show
#order_items = current_order.order_items
end
end
class OrderItemsController < ApplicationController
def create
#order = current_order
#order_item = #order.order_items.new(order_item_params)
#order.save
session[:order_id] = #order.id
end
def update
#order = current_order
#order_item = #order.order_items.find(params[:id])
#order_item.update_attributes(order_item_params)
#order_items = #order.order_items
end
def destroy
#order = current_order
#order_item = #order.order_items.find(params[:id])
#order_item.destroy
#order_items = #order.order_items
end
private
def order_item_params
params.require(:order_item).permit(:quantity, :subproduct_id)
end
end
And the models:
class Order < ActiveRecord::Base
belongs_to :order_status
has_many :order_items
before_create :set_order_status
before_save :update_subtotal
def subtotal
order_items.collect { |oi| oi.valid? ? (oi.quantity * oi.unit_price) : 0 }.sum
end
private
# Sets order status of 1, in progress.
def set_order_status
self.order_status_id = 1
end
def update_subtotal
self[:subtotal] = subtotal
end
end
class OrderItem < ActiveRecord::Base
belongs_to :subproduct
belongs_to :order
validates :quantity, presence: true, numericality: { only_integer: true, greater_than: 0 }
validate :subproduct_present
validate :order_present
before_save :finalize
# Will use the associated subproduct's price if the order item is not persisted
def unit_price
if persisted?
self[:unit_price]
else
subproduct.price
end
end
def total_price
unit_price * quantity
end
private
def subproduct_present
if subproduct.nil?
errors.add(:subproduct, "is not valid or is not active.")
end
end
def order_present
if order.nil?
errors.add(:order, "is not a valid order.")
end
end
def finalize
self[:unit_price] = unit_price
self[:total_price] = quantity * self[:unit_price]
end
end
class OrderStatus < ActiveRecord::Base
has_many :orders
end
Thank you in advance.
Locally, your session still has the order_id key set to 2. That's why your code passes the if-check and gets to the Order.find call. The reason why it blows up is because the default behavior of find is now to raise ActiveRecord::RecordNotFound if it can't find a matching record.
Now, that's probably also the correct behavior for your website. If somehow a session is tied to an order that doesn't exist, you'd be in an inconsistent state! I think you're seeing this now because you rebuilt your database, wiping the order record that your session was tied to, but haven't cleared your session. If you do so (e.g. by deleting all cookies for your localhost domain, or by closing your browser fully and re-opening it), the error will go away.
Couldn't find Order with 'id'=2
The error is because there is no Order record with id = 2 in your local DB and there could be a child record in your order_items table with order_id = 2. So the session[:order_id] won't be nil and it finds the Order record with id = 2 which didn't exist.
The reason could be because the Order record with id = 2 may be accidentally deleted. For a quick fix, try clearing all the cookies or try deleting the order_items record with order_id = 2 and make sure every order_items record have a correct order_id that corresponding to existing order record.
Clear the cookies, as you've been told, that would cause a possible problem. You could also do this. What it does is check if the order found in the cookie is still available, if not, it will reset it then create a new one without throwing an error
def current_order
if !session[:order_id].nil?
#find_order = Order.find(session[:order_id]) rescue nil
if !#find_order
session[:order_id] = nil
current_order
elsif #find_order.order_status_id != 1
session[:order_id] = nil
current_order
else
Order.find(session[:order_id])
end
else
Order.new
end
end
Related
I have seen this error, I understand the problem or so I hope I do, the problem being my order_items are saving before an Order Id has been created. The problem of being a nube is having a clue about the problem but not idea about how to implement the solution, your patience is appreciated.
The error I am getting.
ActiveRecord::RecordNotSaved (You cannot call create unless the parent is saved):
app/models/shopping_bag.rb:22:in add_item'
app/controllers/order_items_controller.rb:10:increate'
My OrderItems controller
class OrderItemsController < ApplicationController
def index
#items = current_bag.order.items
end
def create
current_bag.add_item(
book_id: params[:book_id],
quantity: params[:quantity]
)
redirect_to bag_path
end
def destroy
current_bag.remove_item(id: params[:id])
redirect_to bag_path
end
end
My Orders controller
class OrdersController < ApplicationController
before_action :authenticate_user!, except:[:index, :show]
def index
#order = Order.all
end
def new
#order = current_bag.order
end
def create
#order = current_bag.order
if #order.update_attributes(order_params.merge(status: 'open'))
session[:bag_token] = nil
redirect_to root_path
else
render new
end
end
private
def order_params
params.require(:order).permit(:sub_total, :status, :user_id)
end
end
My shopping bag Model
class ShoppingBag
delegate :sub_total, to: :order
def initialize(token:)
#token = token
end
def order
#order ||= Order.find_or_create_by(token: #token, status: 'bag') do | order|
order.sub_total = 0
end
end
def items_count
order.items.sum(:quantity)
end
def add_item(book_id:, quantity: 1)
book = Book.find(book_id)
order_item = order.items.find_or_create_by(
book_id: book_id
)
order_item.price = book.price
order_item.quantity = quantity
ActiveRecord::Base.transaction do
order_item.save
update_sub_total!
end
end
def remove_item(id:)
ActiveRecord::Base.transaction do
order.items.destroy(id)
update_sub_total!
end
end
private
def update_sub_total!
order.sub_total = order.items.sum('quantity * price')
order.save
end
end
Thank you, your time is appreciated.
From docs about find_or_create_by:
This method always returns a record, but if creation was attempted and failed due to validation errors it won’t be persisted, you get what create returns in such situation.
Probably this is the situation - the record was not persisted in a database, but only created in memory. Looking at your code, I think you want to use a bang-version of the method (find_or_create_by!), which will raise an error in such situation.
To use parent attributes in child when using nested_attributes you can use inverse_of. Here is the documentation which may help you understand why parents need to be created first.
UPDATED with example: This will create forums first and then posts.
class Forum < ActiveRecord::Base
has_many :posts, :inverse_of => :forum
end
class Post < ActiveRecord::Base
belongs_to :forum, :inverse_of => :posts
end
On my online shop I would like that a user could start shopping without an account, he could select items and add them to his cart.
He would create his account just before the payment process, if he doesn't have any account yet.
Also I would like that order belongs_to user
In my order.rb I added,
belongs_to :user, optional: true
So I can create the order without user_id.
I update the order with the user_id in the payment create method.
I need this association because I want to retrieve users' orders.
In my application_controller.rb I have a method that set a cart
before_action :current_cart
def current_cart
#current_cart ||= ShoppingCart.new(token: cart_token)
end
helper_method :current_cart
private
def cart_token
return #cart_token unless #cart_token.nil?
session[:cart_token] ||= SecureRandom.hex(8)
#cart_token = session[:cart_token]
end
Once my user have paid, his order is recorded.
Also I found out that as I don't force the association with the user and the order, an empty order is created because of the current_cart in the application_controller...
here is the shopping_cart.rb model
class ShoppingCart
delegate :sub_total, to: :order
def initialize(token:)
#token = token
end
def order
#order ||= Order.find_or_create_by(token: #token, status: 0) do |order|
order.sub_total = 0
end
end
def items_count
order.items.sum(:quantity)
end
def add_item(product_id:, quantity:1 , size_id:)
#product = Product.find(product_id)
#size = Size.find_by(id: size_id)
#order_item = if order.items.where(product_id: product_id).where(size_id: size_id).any?
order.items.find_by(product_id: product_id, size_id: size_id)
else
order.items.new(product_id: product_id, size_id: size_id)
end
#order_item.price = #product.price_cents
#order_item.quantity = quantity.to_i
ActiveRecord::Base.transaction do
#order_item.save
update_sub_total!
end
CartCleanupJob.set(wait: 1.minutes).perform_later(order.id)
end
def change_qty(id:, quantity:1, product_id:, size_id:)
#size = Size.find_by(id: size_id)
#order_item = order.items.find_by(product_id: product_id, size_id: size_id)
#order_item.quantity = quantity.to_i
#order_item.save
update_sub_total!
end
def remove_item(id:)
ActiveRecord::Base.transaction do
order.items.destroy(id)
update_sub_total!
end
end
private
def update_sub_total!
order.sub_total = order.items.sum('quantity * price')
order.save
end
end
What should I do in order that my user can create his account right before the payment, and not to have an empty order created...?
In the order method of your ShoppingCart class, you use find_or_create_by which as the name implies, call the create method of the Order class . If you switch to find_or_initialize_by instead the new method will be called giving you an Order object, but not created in the database.
def order
#order ||= Order.find_or_initialize_by(token: #token, status: 0) do |order|
order.sub_total = 0
end
end
I'm trying to place an order with braintree payment gem and everything is working fine execept one little thing
i get this error while placing the order
undefined method `total_price' for nil:NilClass
in the order_transaction.rb file which is located in app/views/services/
this is the file
class OrderTransaction
attr_reader :order,:nonce
def initialize order, nonce
#order=order
#nonce=nonce
end
def execute
#result = Braintree::Transaction.sale(
amount: #order.total_price,
payment_method_nonce: #nonce)
end
def ok?
#result.success?
end
end
and this is the method in orders_controller.rb which is creating the transaction
def charge_user
transaction=OrderTransaction.new #order,params[:payment_method_nonce]
transaction.execute
transaction.ok?
end
i dont get whats happening i have the method total_price in order model which is this
class Order < ApplicationRecord
belongs_to :user
has_many :order_items
def total_price
order_items.inject(0){|sum, item| sum +item.total_price }
end
end
i have also used attr_reader to read the order and the nonce in order_transaction.rb file so why is it showing undefined method for nil class i'm really confused can someone help me out
this is the orders controller in controller folder
class OrdersController < ApplicationController
before_filter :initialize_cart
def create
#order_form=OrderForm.new(user: User.new(order_params[:user]),cart: #cart)
if #order_form.save
notify_user
if charge_user
redirect_to products_path,notice:"Thank You for placing the order sir."
end
else
render "carts/checkout",notice:"Something went wrong please try again."
end
end
def custom
#order_form=OrderForm.new(user: current_user,cart: #cart)
if #order_form.save
notify_user
if charge_user
redirect_to products_path,notice:"Thank You for placing the order sir."
end
else
render "carts/checkout",notice:"Something went wrong please try again sir."
end
end
private
def notify_user
OrderMailer.order_confirmation(#order_form.order).deliver
end
def order_params
params.require(:order_form).permit(
user:[:name,:phone,:address,:city,:country,:postal_code,:email])
end
def charge_user
transaction=OrderTransaction.new #order,params[:payment_method_nonce]
transaction.execute
transaction.ok?
end
end
Rails noob here.
I'm building a basic shopping cart and it was working perfectly before. Without changing any code (I git reset --hard to my prev commit where it was working) it broke. (?!?) Here's the breakdown:
Github Repo: https://github.com/christinecha/michaka
Creates a product. ✓
Adds Product ID to a new Order Item. ✓
Adds Order Item to an Order. ✓
--
Possible Issues
! - New Orders keep being created as you create Order Items = cart is always empty.
! - Cart is not connecting to the right Order ID
! - New sessions are being triggered = new Orders = problem
--
ORDER ITEMS CONTROLLER
class OrderItemsController < ApplicationController
def create
#order = current_order
#order_item = #order.order_items.new(order_item_params)
#order.save
session[:order_id] = #order.id
end
def update
#order = current_order
#order_item = #order.order_items.find(params[:id])
#order_item.update_attributes(order_item_params)
#order_items = #order.order_items
end
def destroy
#order = current_order
#order_item = #order.order_items.find(params[:id])
#order_item.destroy
#order_items = #order.order_items
end
private
def order_item_params
params.require(:order_item).permit(:quantity, :product_id)
end
end
SESSION_STORE.RB
Rails.application.config.session_store :cookie_store, key: '_bead-project_session'
ORDER MODEL
class Order < ActiveRecord::Base
belongs_to :order_status
has_many :order_items
before_create :set_order_status
before_save :update_subtotal
def subtotal
order_items.collect { |oi| oi.valid? ? (oi.quantity * oi.unit_price) : 0 }.sum
end
def subtotal_cents
subtotal * 100
end
private
def set_order_status
self.order_status_id = 1
end
def update_subtotal
self[:subtotal] = subtotal
end
end
APPLICATION CONTROLLER
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
helper_method :current_order
def current_order
if !session[:order_id].nil?
Order.find(session[:order_id])
else
Order.new
end
end
end
It looks like ProductsController#create is called twice, once with format html and once as json.
I think you're submitting some of your data via ajax but still doing a post request from the form. However your controller, in it's format.html response is redirecting before all of the javascript actions have completed.
Since you only save #order and set the session from OrderItemsController#create which is called by js after your initial ajax().success, it is incomplete when the redirect is received.
What I think happens on click:
ajax post request AND regular form post
ajax success -> submit #order_item_product_id form
redirected by original form post response
I would suggest either redesigning the submit process to submit through regular form post or entirely through js. For example you could disable post from the form and change OrderItemsController#create to finally redirect (via js) render :js => "window.location.href = '/cart';"
I'm adding a csv upload feature to my site. I want to be able to add startups to categories that I've created.
I'm getting this error:
Startup_policy.rb file
class StartupPolicy < CategoryPolicy
def create?
user.present?
end
def import?
user.present?
end
end
Startup_controller.rb
class StartupsController < ApplicationController
before_action :authenticate_user!
def create
#startup = #startupable.startups.new startup_params
#startup.user = current_user
#startup.save
redirect_to #startupable, notice: "Your startup was added succesfully."
authorize #startup
end
def import
count = Startup.import params[:file]
redirect_to category_startups_path, notice: "Imported #{count} startups"
authorize #startups
end
private
def set_category
#startup = Startup.find(params[:id])
authorize #startup
end
def startup_params
params.require(:startup).permit(:company, :url)
end
end
Startup.rb
class Startup < ActiveRecord::Base
belongs_to :startupable, polymorphic: true
belongs_to :user
def self.import(file)
counter = 0
CSV.foreach(file.path, headers: true, header_converters: :symbol) do |row|
startup = Startup.assign_from_row(row)
if startup.save
counter += 1
else
puts "#{startup.company} - #{startup.errors.full_messages.join(",")}"
end
end
counter
end
def self.assign_from_row(row)
startup = Startup.where(company: row[:company]).first_or_initialize
startup.assign_attributes row.to_hash.slice(:url)
startup
end
end
EDIT: added Category_policy.rb
class CategoryPolicy < ApplicationPolicy
def index?
true
end
def create?
user.present?
end
def update?
return true if user.present? && (user.admin? || category.user)
end
def show?
true
end
def destroy?
user.present? && user.admin?
end
private
def category
record
end
end
What am I missing here? Pundit is pretty easy to use but for some reason I'm stumped on this one.
I don't see that you've set #startups anywhere. So it's nil, which explains the error message. I assume you meant to set it to the resulting list you get after importing the CSV. Or, since all you are checking in the policy is whether you have a user, you could just authorize :startup which will get you to the right policy, and not care which startups you have.