Rails Transaction error when placing order - ruby-on-rails

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

Related

I am having this error: "You cannot call create unless the parent is saved",

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

Nested resources, simple_form_for

I am trying to create an app where I have Events and each event would have many sales. When a new sale is created it automatically gets an event ID it belongs to. Could somebody please review this and tell me if I am doing something wrong, because I think the way am creating simple_form for the nested model(Sale) is a bit incorrect. Also I am not sure if it should be this way or I ve done something wrong, but when I am accessing nested children the url looks like this
.../events/4/sales/1
.../events/3/sales/1
.../events/5/sales/1
but I would expect it to be like this ?!
.../events/4/sales/1
.../events/4/sales/2
.../events/4/sales/3
Here is my controller and model for Events
class Event < ApplicationRecord
has_many :sales, dependent: :destroy
end
.
class EventsController < ApplicationController
def index
#events = Event.all
end
def new
#event = Event.new
end
def create
#event = Event.new(event_params)
if #event.save
redirect_to #event
else
redirect_to events_path
end
end
def show
#event = Event.find(params[:id])
#sales = #event.sales
end
private
def event_params
params.require(:event).permit(:name, :comment, :event_disscount)
end
end
.
Here is my controller and model for Sales
class Sale < ApplicationRecord
belongs_to :event
has_many :sale_items
accepts_nested_attributes_for :sale_items, allow_destroy: true
end
.
class SalesController < ApplicationController
def new
#sale = Sale.new(event_id: params[:event_id])
#event = Event.find_by(id: params[:event_id])
end
def create
#event = Event.find(params[:event_id])
#sale = #event.sales.create(params[:sale].permit(:receipt_email))
if #sale.save
redirect_to #event
else
redirect_to new
end
end
end
routes.rb
Rails.application.routes.draw do
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
resources :events do
resources :sales
end
root 'events#index'
end
And this is how I use simple_form for sale(new)
<%= simple_form_for([#event, #sale]) do |f| %>
My main concern is the 'new' action in Sales controller, whats the best way to create a nested resource with the id of its parent, and then passing this object to the simple_form?!
Thank you in advance
Your question is too broad. Basically you're doing it all right, however, with some improvements on the code it will be easier to find possible problems.
is it correct the way I am creating new sale?
Some improvements over your SalesController:
Create private method sale_params which will sanitize input params from your form. You did it for events already - why not to do it here too?
Since that controller works in the scope of event, params[:event_id] is set for every action. So create a before_action filter which will set your #event variable.
Method create saves the model to the database, so calling save after it makes no sense.
In case of failure on saving #sale to the db redirecting to new is not reasonable. In that case everything user typed in the form will be lost, validation error won't be shown and it will look like a glitch of your app. Render new template instead with the same #sale.
This is how I would rewrite your controller:
class SalesController < ApplicationController
before_action: :set_event
def new
#sale = #event.sales.build
end
def create
#sale = #event.sales.build(sale_params)
if #sale.save
redirect_to #event
else
render action: :new
end
end
private
def sale_params
params.require(:sale).permit(:receipt_email, sale_items_attributes: [])
end
def set_event
#event = Event.find(params[:event_id])
end
end

Strange error in rails while sending notification email

I am trying to send a notification email to the email provided by the user when he clicks the place order button but i get this error
TypeError: no implicit conversion of Symbol into Integer
and the error is in order_controller.rb file here it is
class OrdersController < ApplicationController
def create
#order_form=OrderForm.new(user: User.new(order_params[:user]),cart: #cart)
if #order_form.save
notify_user
redirect_to root_path,notice:"Thank You for placing the order sir."
else
render "carts/checkout"
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
end
and this is the order_form.rb model
class OrderForm
include ActiveModel::Model
attr_accessor :user,:order
attr_writer :cart
def save
set_password_for_user
if valid?
persist
true
else
false
end
end
def has_error?
user.errors.any?
end
private
def valid?
user.valid?
end
def persist
user.save
#order=Order.create!(user:user)
build_order_items
end
def set_password_for_user
user.password="examplepassword"
end
def build_order_items
#cart.items.each do |item|
#order.order_items.create! product_id: item.product_id, quantity: item.quantity
end
end
end
and finally my order_mailer.rb mailer
class OrderMailer < ActionMailer::Base
default from: "bobbyverma946#yahoo.in"
def order_confirmation order
#order=order
mail to: order.user.email, subject: "Your order (##{order.id})"
end
end
can someone please tell me whats wrong with the code because i am really confused

forbidden attribute error rails 4 Carrierwave

Have a issue with a controller file which i have narrowed down to a method
Controller
def create
#gallery = Gallery.new(params[:gallery])
if #gallery.save
flash[:notice] = "Successfully created gallery."
redirect_to #gallery
else
render :action => 'new'
end
end
private
def gallery_params
params.require(:gallery).permit(:name, :gallery, :gamepic)
end
end
the problem is that there is no attr_accessible in the controller or the model
model
class Gallery < ActiveRecord::Base
has_many :gamepics
private
def gallery_params
params.require(:gallery).permit(:name, :gallery, :gamepic)
end
end
Try passing the strong parameters method into Gallery.new instead of params[:gallery].
My understanding of this is that, the hash returned from that method is what should be used anyways. So you'd have:
#gallery = Gallery.new(gallery_params)
If you only need certain params from your :permit call, just make a new strong params method and use that one.

Keep Receiving an "Unknown attribute=user_id" error

First time poster, long time lurker here. I have a Users model and controller for a little video game application for Rails that I'm currently making. So I've read a couple of answers on here regarding this issue, but none of the answers really seem to have helped me. People have suggested adding a "user_id" column to my Users table, but my point of contention is, I thought the "user_id" was automatically made in Rails? Even if I use a user.inspect, I still see a user_id=7show up on the page. However, I still get the unknown attribute error when attempting to create a game and assign to the current user. Any help would be most appreciated in pinpointing the cause and solution to this. Thanks!
app/controllers/users_controller.rb:
class UsersController < ApplicationController
skip_before_filter :require_authentication, only: [:new, :create]
def index
#users = User.all
end
def show
end
def new
#user = User.new
end
def edit
#user = current_user
end
def create
#user = User.create!(user_params)
session[:user_id] = #user.id
redirect_to users_path, notice: "Hi #{#user.username}! Welcome to DuckGoose!"
end
def update
current_user.update_attributes!(user_params)
redirect_to users_path, notice: "Successfully updated profile."
end
def destroy
#user = User.find(params[:id])
#user.destroy
redirect_to users_url, notice: 'User was successfully destroyed.'
end
private
def user_params
params.require(:user).permit(:username, :firstname, :lastname, :email, :password, :password_confirmation)
end
end
app/config/routes.rb:
NkuProject::Application.routes.draw do
resources :users do
resources :games
end
resources :sessions
resources :games
get "sign_out", to: "sessions#destroy"
get "profile", to: "users#edit"
root to: "sessions#new"
end
app/controllers/games_controller.rb
class GamesController < ApplicationController
def new
#game = Game.new
end
def index
#games = Game.all
end
def destroy
#game = Game.find(params[:id])
#game.destroy
redirect_to games_url, notice: 'Game was successfully deleted.'
end
def create
#game = current_user.games.build(game_params)
if #game.save
redirect_to #game, notice: "Game successfully added"
else
render :new
end
end
def show
#game = Game.find(params[:id])
end
private
def game_params
params.require(:game).permit!
end
end
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :require_authentication
def current_user
#current_user ||= User.find_by(id: session[:user_id]) if session[:user_id].present?
end
helper_method :current_user
def require_authentication
if current_user
true
else
redirect_to new_session_path
end
end
end
I'm sure I'm missing some code to put in for reference, but if I need anything else please let me know.
Looking at the way your controller actions are defined, I can safely say that User and Game have a 1-M relationship, i.e.,
class User < ActiveRecord::Base
has_many :games
end
class Game < ActiveRecord::Base
belongs_to :user
end
Now, based on that games table must have a field named user_id. Rails is not going to create it for you unless you specify it. You need to add field user_id in games table by creating a migration for the same. Right now, it doesn't seem like you have user_id foreign_key field in games table. Hence, the error while saving games record.

Resources