i'm having trouble having order go through. have posted error bellow. think issue has create method in ordercontroller.rb, have total_price method defined but.. other i'm not sure how fix issue. appreciated. thank you.
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 placing order." else flash[:warning] = <<eof order id #{@order_form.order.id}. <br/> 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 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 placing 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 |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
as standard note, nilclass
error means haven't defined variable you're trying manipulate.
the key solving problem therefore find why variable isn't defined, , populate it.
def execute @result = braintree::transaction.sale( amount: order.total_price, payment_method_nonce: nonce ) end
this rails says variable not populated.
however, many problems in programming, cause of issue may not defined...
i thought problem weren't calling @order
. however, class initializes order
, shouldn't problem. have @ how you're invoking class:
transaction = ordertransaction.new @order, params[:payment_method_nonce]
this surmises @order
defined.
i surmise isn't.
here's i'd do:
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 should create @order if charge_user redirect_to root_path, notice: "thank placing order." else flash[:warning] = <<eof order id #{@order_form.order.id}. <br/> went wrong. eof redirect_to new_payment_order_path(@order_form.order) end else render "carts/checkout" end end
personally, think highlights deeper problem code structure:
- you're creating
orderform
object , yet processing@order_form.order
- your controller full of tiny methods bloat big time
- your controller orders, yet builds
orderform
objects
i'd best make controller thin possible:
#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
i'd have more modular model structure:
#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 work out end def charge payment = payments.create payment.execute ? payment.success : payment.error #-> 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 |qty| proxy_association.target << qty end end #private private #products def products return_array = [] through_collection.each_with_index |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
i wanted include cart somewhere, i'll have time.
for now, you'd able following:
@order = current_user.orders.find params[:id] @order.products.each |product| product.qty #-> 5 @order.total_price #-> prices * qtys
--
this not complete or tested, hope shows how improve code structure dramatically, making modular. ie keep many methods tied objects possible.
in short, should able following:
@order = current_users.orders.find params[:id] if @order.payments.any? @payment = @order.payment.first @payment.success? end
Comments
Post a Comment