Question

I have a model class page.rb:

class Page < ActiveRecord::Base

    def paypal_url(return_url)
      values = {
        :business => 'seller_1229899173_biz@railscasts.com',
        :cmd => '_cart',
        :upload => 1,
        :return => return_url,
        :invoice => id
      }
      line_items.each_with_index do |item, index|
        values.merge!({
          "amount_#{index+1}" => item.unit_price,
          "item_name_#{index+1}" => item.product.name,
          "item_number_#{index+1}" => item.id,
          "quantity_#{index+1}" => item.quantity
        })
      end
     "https://www.sandbox.paypal.com/cgi-bin/webscr?" + values.to_query
    end

end

And in my controller:

def order_form
    if params[:commit] == "Proceed to Checkout"
        redirect_to(@cart.paypal_url("/pages/order_online"))
end

but when I click on "Proceed to Checkout", it gives me an error:

undefined method `paypal_url' for nil:NilClass

Any idea if I'm missing anything or doing anything wrong?

Thanks!

Était-ce utile?

La solution

The simple answer is your @cart variable is not being populated with any data

The way to fix this is to create a @cart variable in your order_form controller, like so:

def order_form
    @cart = Cart.new cart_params #-> how to define your cart var?
    redirect_to @cart.paypal_url "/pages/order_online"
end

I looked at the Railscast you've been using, and it seems he's continuing on from another episode, where he explains how to create the cart object using standard ActiveRecord


A longer answer is that I believe your system is flawed, in that you're calling PayPal methods in your Page model (why?)

We've set up our own cart in Rails before (you can see here):

  1. Cart session model #-> stores product id's in a cart model
  2. Product model stores the products & links with cart id's
  3. Order controller sends data to Paypal & handles returns

Here's some code for you:

#config/routes.rb
get 'cart' => 'cart#index', :as => 'cart_index'
post 'cart/add/:id' => 'cart#add', :as => 'cart_add'
delete 'cart/remove(/:id(/:all))' => 'cart#delete', :as => 'cart_delete'

get 'checkout/paypal' => 'orders#paypal_express', :as => 'checkout'
get 'checkout/paypal/go' => 'orders#create_payment', :as => 'go_paypal'
get 'checkout/stripe' => 'orders#stripe', :as => 'stripe'

#app/models/cart_session.rb #-> "session based model"
class CartSession

    #Initalize Cart Session
    def initialize(session)
        @session = session
        @session[:cart] ||= {}
    end

    #Cart Count
    def cart_count
        if (@session[:cart][:products] && @session[:cart][:products] != {})
            @session[:cart][:products].count
        else
            0
        end
    end

    #Cart Contents
    def cart_contents
        products = @session[:cart][:products]

        if (products && products != {})

            #Determine Quantities
            quantities = Hash[products.uniq.map {|i| [i, products.count(i)]}]

            #Get products from DB
            products_array = Product.find(products.uniq)

            #Create Qty Array
            products_new = {}
            products_array.each{
                |a| products_new[a] = {"qty" => quantities[a.id.to_s]}
            }

            #Output appended
            return products_new

        end

    end

    #Qty & Price Count
    def subtotal
        products = cart_contents

        #Get subtotal of the cart items
        subtotal = 0
        unless products.blank?
            products.each do |a|
                subtotal += (a[0]["price"].to_f * a[1]["qty"].to_f)
            end
        end

        return subtotal

    end

    #Build Hash For ActiveMerchant
    def build_order

        #Take cart objects & add them to items hash
        products = cart_contents

        @order = []
        products.each do |product|
            @order << {name: product[0].name, quantity: product[1]["qty"], amount: (product[0].price * 100).to_i }
        end

        return @order
    end

    #Build JSON Requests
    def build_json
        session = @session[:cart][:products]
        json = {:subtotal => self.subtotal.to_f.round(2), :qty => self.cart_count, :items => Hash[session.uniq.map {|i| [i, session.count(i)]}]}
        return json
    end


end

#app/controllers/cart_controller.rb
# shows cart & allows you to click through to "buy"
class CartController < ApplicationController
include ApplicationHelper

#Index
def index
    @items = cart_session.cart_contents
    @shipping = Shipping.all
end

#Add
def add
    session[:cart] ||={}
    products = session[:cart][:products]

    #If exists, add new, else create new variable
    if (products && products != {})
        session[:cart][:products] << params[:id]
    else
        session[:cart][:products] = Array(params[:id])
    end

    #Handle the request
    respond_to do |format|
        format.json { render json: cart_session.build_json }
        format.html { redirect_to cart_index_path }
    end
end

#Delete
def delete
    session[:cart] ||={}
    products = session[:cart][:products]
    id = params[:id]
    all = params[:all]

    #Is ID present?
    unless id.blank?
        unless all.blank?
            products.delete(params['id'])
        else
            products.delete_at(products.index(id) || products.length)
        end
    else
        products.delete
    end

    #Handle the request
    respond_to do |format|
        format.json { render json: cart_session.build_json }
        format.html { redirect_to cart_index_path }
    end
end

 end

 #app/controllers/orders_controller.rb
 #Paypal Express
def paypal_express
    response = EXPRESS_GATEWAY.setup_purchase(total,
      :items => cart_session.build_order,
      :subtotal => subtotal,
      :shipping => 50,
      :handling => 0,
      :tax => 0,
      :return_url => url_for(:action => 'create_payment'),
      :cancel_return_url => url_for(:controller => 'cart', :action => 'index')
    )
    redirect_to EXPRESS_GATEWAY.redirect_url_for(response.token)
end

#Create Paypal Payment
def create_payment
    response = express_purchase
    #transactions.create!(:action => "purchase", :amount => ((cart_session.subtotal * 100) + 50).to_i, :response => response)
    #cart.update_attribute(:purchased_at, Time.now) if response.success?
    response.success?
    redirect_to cart_index_path
end

#Stripe
def stripe
    credit_card = ActiveMerchant::Billing::CreditCard.new(
        :number             => "4242424242424242",
        :month              => "12",
        :year               => "2020",
        :verification_value => "411"
    )

    purchaseOptions = {
        :billing_address => {
            :name     => "Buyer Name",
            :address1 => "Buyer Address Line 1",
            :city     => "Buyer City",
            :state    => "Buyer State",
            :zip      => "Buyer Zip Code"
        }
    }

    response = STRIPE_GATEWAY.purchase(total, credit_card, purchaseOptions)
    Rails.logger.debug response.inspect

    @responder = response
    render cart_index_path
end


private
def subtotal
    (cart_session.subtotal * 100).to_i
end

def total
    ((cart_session.subtotal * 100) + 50).to_i
end

def express_purchase
    EXPRESS_GATEWAY.purchase(total, express_purchase_options)
end

def express_purchase_options
    {
      :token => params[:token],
      :payer_id => params[:PayerID]
    }
end

def express_token=(token)
    self[:express_token] = token
    if new_record? && !token.blank?
        details = EXPRESS_GATEWAY.details_for(token)
        self.express_payer_id = details.payer_id
        self.first_name = details.params["first_name"]
        self.last_name = details.params["last_name"]
    end
end

 end
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top