Rails 4: Undefined method `total_price 'for nil: NilClass, Order Controller

I have problems with order. I posted an error below. I think the problem is with the create method in OrderController.rb, I already have the total_price method defined, but ... other than that, I'm not sure how to fix this problem. Any help would be greatly appreciated. Thanks.

enter image description here

class OrderTransaction
  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

  private

  attr_reader :order, :nonce
end

class Order < ActiveRecord::Base
  belongs_to :user
  has_many :order_items

  def total_price
    order_items.inject(0) { |sum, item| sum + item.total_price }
  end
end

class OrdersController < ApplicationController
  before_filter :initialize_cart

  def index
    @orders = Order.order(created_at: :desc).all
  end

  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 root_path, notice: "Thank you for placing the order."
      else
        flash[:warning] = <<EOF
Your order ID is #{@order_form.order.id}.
<br/>
Something went wrong.
EOF
        redirect_to new_payment_order_path(@order_form.order)
      end
    else
      render "carts/checkout"
    end
  end

  def update
    @order = Order.find params[:id]
    @previous_state = @order.state

    if @order.update state_order_params
      notify_user_about_state
      redirect_to orders_path, notice: "Order was updated."
    end
  end


  def new_payment
    @order = Order.find params[:id]
    @client_token = Braintree::ClientToken.generate
  end

  def pay
    @order = Order.find params[:id]
    transaction = OrderTransaction.new @order, params[:payment_method_nonce]
    transaction.execute
    if transaction.ok?
      redirect_to root_path, notice: "Thank you for placing the order."
    else
      render "orders/new_payment"
    end
  end

  private

  def notify_user
    @order_form.user.send_reset_password_instructions
    OrderMailer.order_confirmation(@order_form.order).deliver
  end

  def notify_user_about_state
    OrderMailer.state_changed(@order, @previous_state).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

  def state_order_params
    params.require(:order).permit(:state)
  end
end

class OrderItem < ActiveRecord::Base
  belongs_to :order
  belongs_to :product

  def total_price
    self.quantity * self.product.price
  end
end

  class OrderForm
  include ActiveModel::Model

  attr_accessor :user, :order # credit_card
  attr_writer :cart

  def save
    set_password_for_user

    if valid?
      persist
      true
    else
      false
    end
  end

  def has_errors?
    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 = Digest::SHA1.hexdigest(user.email + Time.now.to_s)[0..8]
  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

class OrderItem < ActiveRecord::Base
  belongs_to :order
  belongs_to :product

  def total_price
    self.quantity * self.product.price
  end
end

+4
source share
2 answers

As a standard note, any error NilClassbasically means that you did not define the variable that you are trying to manipulate.

The key to solving the problem is to find out why the variable is not defined and populate it.


def execute
    @result = Braintree::Transaction.sale(
      amount: order.total_price,
      payment_method_nonce: nonce
    )
end

Rails , .

, , , ...

, , @order. order, . , :

transaction = OrderTransaction.new @order, params[:payment_method_nonce]

, @order .

, .

:

def create
    @order_form = OrderForm.new(
      user: User.new(order_params[:user]),
      cart: @cart
    )

    if @order_form.save
      notify_user
      @order = @order_form.order #-> not efficient but should create @order
      if charge_user
        redirect_to root_path, notice: "Thank you for placing the order."
      else
        flash[:warning] = <<EOF
Your order ID is #{@order_form.order.id}.
<br/>
Something went wrong.
EOF
        redirect_to new_payment_order_path(@order_form.order)
      end
    else
      render "carts/checkout"
    end
end

, :

  • OrderForm @order_form.order
  • , .
  • , OrderForm

:

#app/controllers/orders_controller.rb
class OrdersController < ApplicationController
   def new 
      @order = current_user.order.new
   end
   def create
      @order = current_user.order.new order_params
      if @order.save 
         @order.charge
      end
   end

   private

   def order_params
      params.require(:order).permit(:x, :y, :z, order_products_attributes: [:product, :qty])
   end
end

:

#app/models/order.rb
class Order < ActiveRecord::Base
   belongs_to :user
   has_many :order_products
   has_many :products, through: :order_products, extend ProductQty
   has_many :payments, inverse_of: :order

   scope :cart, -> { order_products }

   def total_price
      products.pluck(:price, :qty) #-> need to work out
   end

   def charge
       payment = payments.create
       payment.execute ? payment.success : payment.error #-> something conditional
   end
end

#app/models/order_product.rb
class OrderProduct < ActiveRecord::Base
   #columns id | order_id | product_id | qty | created_at | updated_at
   belongs_to :order
   belongs_to :product

end

#app/models/payment.rb
class Payment < ActiveRecord::Base
   belongs_to :order, inverse_of: :payments

   def execute
      Braintree::Transaction.sale(amount: order.total_price)
   end
end

#app/models/product.rb
class Product < ActiveRecord::Base
   has_many :order_products
   has_many :orders, through: :order_products
end

#app/models/concerns/product_qty.rb
module ProductQty

    #Load
    def load
       products.each do |qty|
          proxy_association.target << qty
       end
    end

    #Private
    private

    #Products
    def products
       return_array = []
       through_collection.each_with_index do |through,i|
           associate = through.send(reflection_name)
           associate.assign_attributes({qty: items[i]})
           return_array.concat Array.new(1).fill( associate )
       end
       return_array
    end

    #######################
    #      Variables      #
    #######################

    #Association
    def reflection_name
            proxy_association.source_reflection.name
    end

    #Foreign Key
    def through_source_key
            proxy_association.reflection.source_reflection.foreign_key
    end

    #Primary Key
    def through_primary_key
            proxy_association.reflection.through_reflection.active_record_primary_key
    end

    #Through Name
    def through_name
       proxy_association.reflection.through_reflection.name
    end

    #Through
    def through_collection
       proxy_association.owner.send through_name
    end

    #Captions
    def items
       through_collection.map(&:qty)
    end

    #Target
    def target_collection
       proxy_association.target
    end

end

-, .

:

@order = current_user.orders.find params[:id]
@order.products.each do |product|
   product.qty #-> 5

@order.total_price #-> prices * qtys

-

, , , , . IE , .

, :

@order = current_users.orders.find params[:id]
if @order.payments.any?
   @payment = @order.payment.first
   @payment.success?
end
+2

charge_user OrdersController, :

transaction = OrderTransaction.new @order, params[:payment_method_nonce]

@order , .. @order nil, , : undefined method total_price for nil:NilClass

@order charge_user, , @order NOT nil:

transaction = OrderTransaction.new @order, params[:payment_method_nonce]

charge_user order :

def charge_user(order)
  transaction = OrderTransaction.new order, params[:payment_method_nonce]
  transaction.execute
  transaction.ok?
end

create :

if charge_user(@order_form.order)
  redirect_to root_path, notice: "Thank you for placing the order."
else
  # rest of the code
end

.

+2

Source: https://habr.com/ru/post/1609058/


All Articles