#146
Jan 26, 2009

PayPal Express Checkout

PayPal Express Checkout is easy to add to an existing ordering system. See how in this episode.
Download (29.5 MB, 15:24)
alternative download for iPod & Apple TV (22 MB, 15:24)

Resources

script/generate migration add_express_token_to_orders express_token:string express_payer_id:string
rake db:migrate
# config/environments/development.rb
config.after_initialize do
  ActiveMerchant::Billing::Base.mode = :test
  paypal_options = {
    :login => "seller_1229899173_biz_api1.railscasts.com",
    :password => "FXWU58S7KXFC6HBE",
    :signature => "AGjv6SW.mTiKxtkm6L9DcSUCUgePAUDQ3L-kTdszkPG8mRfjaRZDYtSu"
  }
  ::STANDARD_GATEWAY = ActiveMerchant::Billing::PaypalGateway.new(paypal_options)
  ::EXPRESS_GATEWAY = ActiveMerchant::Billing::PaypalExpressGateway.new(paypal_options)
end

# config/environments/test.rb
config.after_initialize do
  ActiveMerchant::Billing::Base.mode = :test
  ::STANDARD_GATEWAY = ActiveMerchant::Billing::BogusGateway.new
  ::EXPRESS_GATEWAY = ActiveMerchant::Billing::BogusGateway.new
end

# config/environments/production.rb
config.after_initialize do
  ActiveMerchant::Billing::Base.mode = :production
  paypal_options = {
    :login => "seller_1229899173_biz_api1.railscasts.com",
    :password => "FXWU58S7KXFC6HBE",
    :signature => "AGjv6SW.mTiKxtkm6L9DcSUCUgePAUDQ3L-kTdszkPG8mRfjaRZDYtSu"
  }
  ::STANDARD_GATEWAY = ActiveMerchant::Billing::PaypalGateway.new(paypal_options)
  ::EXPRESS_GATEWAY = ActiveMerchant::Billing::PaypalExpressGateway.new(paypal_options)
end

# routes.rb
map.resources :orders, :new => { :express => :get }

# orders_controller.rb
def express
  response = EXPRESS_GATEWAY.setup_purchase(current_cart.build_order.price_in_cents,
    :ip                => request.remote_ip,
    :return_url        => new_order_url,
    :cancel_return_url => products_url
  )
  redirect_to EXPRESS_GATEWAY.redirect_url_for(response.token)
end

def new
  @order = Order.new(:express_token => params[:token])
end

# models/order.rb
def purchase
  response = process_purchase
  transactions.create!(:action => "purchase", :amount => price_in_cents, :response => response)
  cart.update_attribute(:purchased_at, Time.now) if response.success?
  response.success?
end

def express_token=(token)
  write_attribute(: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

private

def process_purchase
  if express_token.blank?
    STANDARD_GATEWAY.purchase(price_in_cents, credit_card, standard_purchase_options)
  else
    EXPRESS_GATEWAY.purchase(price_in_cents, express_purchase_options)
  end
end

def standard_purchase_options
  {
    :ip => ip_address,
    :billing_address => {
      :name     => "Ryan Bates",
      :address1 => "123 Main St.",
      :city     => "New York",
      :state    => "NY",
      :country  => "US",
      :zip      => "10001"
    }
  }
end

def express_purchase_options
  {
    :ip => ip_address,
    :token => express_token,
    :payer_id => express_payer_id
  }
end

def validate_card
  if express_token.blank? && !credit_card.valid?
    credit_card.errors.full_messages.each do |message|
      errors.add_to_base message
    end
  end
end
<!-- carts/show.html.erb -->
<%= link_to image_tag("https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif"), express_new_order_path %>

<!-- orders/new.html.erb -->
<% form_for @order do |f| %>
  <%= f.error_messages %>
  <% if @order.express_token.blank? %>
    ...
  <% else %>
    <%= f.hidden_field :express_token %>
    <p>Name: <%=h @order.first_name %> <%=h @order.last_name %></p>
    <p>TODO Display order confirmation details</p>
  <% end %>
  <p><%= f.submit "Complete Order" %></p>
<% end %>

RSS Feed for Episode Comments 33 comments

1. Bertg Jan 26, 2009 at 01:07

When overriding the express_token= method, you set the express_token "attribute" via the self[] method. This is not the best way.

According to the Rails manuals it is better to use write_attribute when overriding an attribute setter (and read_attribute when overriding the getter)

Great cast otherwise ;)


2. Udo Urbantschitsch Jan 26, 2009 at 05:35

Hi Ryan,

thank you very much for another useful and interesting Railscast!

Keep up the good work.

Greetings from Austria,
Udo


3. Igor Jan 26, 2009 at 05:46

Hi, Ryan

Thanks for your work. Can't wait the end of work day to watch it ;)

However it's 6 screen casts regarding payment gateways. How much more you planning to spend on it, when we will see your screencasts with another rails tips?

Thanks


4. Ryan Bates Jan 26, 2009 at 07:16

@Bertg, thanks for the correction, I'll update the code in the show notes.

@Igor, This is the last cast on e-commerce for a little while. Expect some more regular episodes over the next few weeks.


5. Sam Jan 26, 2009 at 07:54

Hi Ryan,

Thanks again for the screen cast - very useful.

Still new to Ruby and Rails and had a quick question. If the purchase fails it goes to a failure page rather than rendering the new action again. Should this be changed? I'm not sure if this is a bad practice or if it was just to simplify it for the screencast.


6. ron Jan 26, 2009 at 15:10

No screencast on recurring billing? That's too bad. Anyway, love the series. Thanks a lot!


7. Scott Jan 26, 2009 at 18:55

+1 for Recurring Billing!


8. Gustavo Scanferla Jan 26, 2009 at 21:08

@ron and @Scott,
Ryan said that he would that in previous episodes! =D


9. David Trasbo Jan 26, 2009 at 22:58

This episode Ryan said he needed to do some more research on recurring billing before doing an episode on it. In the mean time, we'll get the usual episodes with Rails tips and so on, that we all appreciate. :)


10. jflcooper Jan 27, 2009 at 02:46

AWESOME!!!!!!!

Recurring billing still to come...
awwwwwwww


11. Vincent Jan 27, 2009 at 13:24

It is my understanding that (like mentioned in episode 145) informations (even more so for sensitive ones) should be gathered in HTTPS... I'm not sure if i missed an episode where the process of doing just that is explained but wouldn't it be a good episode subject otherwise ?

Great screencasts, btw ! keep up the great work !


12. Nick Jan 27, 2009 at 17:38

Ryan, Just wanted to thank you for all the recent merchant casts, have been very helpful for setting up my shop. Keep up the good work :)


13. Ray Rogers Jan 28, 2009 at 06:54

I'm missing the boat on something. How do I add the shipping information into my orders table when using the express pay. I have the first and last name just like the screen cast. But when I try and add the shipping address or any of the shipping information, its not updating the orders table.

Ryan. Thanks for the great series on Active Merchant and PayPal.


14. Vinay Jan 29, 2009 at 00:59

You use current_cart.build_order.price_in_cents in the controller to setup your response. And then the request cycle goes to paypal and then returns and then im losing the cart_id for the order.
Could someone check that?

Great series of casts Ryan! VERY helpful!


15. Andrea Jan 31, 2009 at 02:37

Thanks a lot Ryan! But why not ending in great style with a recurring bill episode? :(
Was one of the most important features!

Thanks aniway :)


16. Ben Feb 03, 2009 at 03:11

I found a handy pdf to get you started with credit card processing:
http://jumpstartcc.com/

Most of the things were already mentiond by ryan, but its a nice overview.


17. Justin Feb 18, 2009 at 10:54

There have been a lot of ecommerce related Railscasts lately, but I think that is because it is a complex topic. I'll throw in a +1 for recurring billing.

Thanks for all of your work. Railscasts are one of the best resources for the community and they are free. Thanks again.


18. Raymond Law Feb 20, 2009 at 11:54

I had to do PayPal recurring payment before the Railscast becomes available. So I put together an extention and wrote a blog post about it.

http://rayvinly.com/articles/2009/02/20/paypal-recurring-billing-with-activemerchant-in-ruby-on-rails/

I hope it works out you all who need to do similar things. There are stuff you can configure. ActiveMerchant is real nice.

Feedback will be appreciated.


19. richard Apr 14, 2009 at 05:58

I'm trying to get this code to work from the git repo but its complaining about current_cart in line_items_controller.rb the create on line 4. any ideas?


20. richard May 05, 2009 at 17:47

Any plans for authorize.net processing ryan? I'm trying to get it work but just can't was hoping you might give some insight.


21. bigshiny90 Jun 03, 2009 at 13:28

great screencast, got me most of the way. i still have questions about integrating a list of ordered products on the confirmation page (after going to paypal).

i can't seem to get the cart line items to list on the confirm page. (this is the Orders -> new.html.erb page).

specifically i thought i would be able to access the cart thru @orders.cart.line_items, but i'm obviously missing something. in fact the @orders.cart_id seems nil.

does this get lost in the Express situation?


22. bigshiny90 Jun 03, 2009 at 13:59

second thoughts...

if i'm understanding this correctly, i can get all the order details (and items) thru the returned express_token. (since i'm actually sending PaymentDetailItems in my purchase).

question: can i access the token details directly on my orders new ERB? or is there a better way to do this?


23. bigshiny90 Jun 03, 2009 at 14:29

oh, i just included the current cart as in the new method of the OrderController. silly me...


24. Darren Jul 03, 2009 at 11:04

+ eight gazzilion billon for recurring billing, Ryan this !#*$ is the bomb.


25. Tinu Cleatus Jul 28, 2009 at 07:16

Looking forward to the recurring billing episode. Many thanks for the series on Paypal.


26. Muthhus Aug 27, 2009 at 06:21

I got the following error, when i followed your code, please assist me..
Thanks

 NameError in OrdersController#express

undefined local variable or method `products_url' for #<OrdersController:0xb6933454>

RAILS_ROOT: /home/shanmuga/shapero/shapero
Application Trace | Framework Trace | Full Trace

app/controllers/orders_controller.rb:6:in `express'

Request

Parameters:

None


27. Brett Francis Oct 13, 2009 at 21:47

How can I use Active Merchant to set Express Checkout's taxamt field? I need to set tax on orders shipping to my state.

Thanks!


28. hello Oct 16, 2009 at 01:38

[url=http://www.rs2guru.com/]wedding invitations[/url]
[url=http://www.rs2guru.com/]wedding invitation[/url]
[url=http://www.rs2guru.com/]unique wedding invitations[/url]


29. CalebHC Nov 11, 2009 at 17:55

Thank you so much for this series! It helped me out an incredible amount. This saved me days of researching and learning. Thank you! :)


30. artemave Dec 17, 2009 at 07:11

Before considering PayPal, consider this:

http://blog.apparentsoft.com/business/124/is-paypal-good-for-your-microisv-business-a-short-paypal-horror-story/


31. Bijesh Dec 23, 2009 at 03:33

Hi Ryan,

There is one issue.

When you are redirecting to PayPal sandbox for Payment, you are not showing the amount which User is going to PAY ?

How can we show the AMOUNT on PayPal site which user is going to PAY ?

Thanks,
Bijesh


32. stone Dec 30, 2009 at 00:45

great screencast


33. Mark Richman Jan 26, 2010 at 12:09

+1,210,000,000 for recurring billing. Killer screencast.


34. USB Accessories Feb 03, 2010 at 06:55

Thanks a lot Ryan! But why not ending in great style with a recurring bill episode? :(
Was one of the most important features!

Add your comment:

(SKIP THIS ONE)

(required)

(not shown)


(use pastie or gist for code)

sponsored by:
if you want to help:
required:
Get Quicktime Player
Give Back to Open Source