How to use Spreedly with Merb

UPDATE: See Using Spreedly with Merb via HTTParty instead.

This article is not yet completed.

Spreedly is great. So clever. Nathaniel Tablott, you are awesome. I really have enjoyed trying it out, but it required me to learn some new skills – namely hooking up to restful web services – I had never done that before. This was also the first time I had ever worked with ‘payment processing’ so to speak – spreedly actually does all the processing.

Signup for Spreedly, create a test site, & add a subscription plan

Watch this video by the creator of Spreedly to see how to do this.

Also, here’s the guide.

Setup app to redirect to spreedly after account/site is created

Your create action is where things happen so let’s redirect the user after they create their account/site. *If you are dealing with multiple plans you should replace the Merb::Config[:spreedly_plan_one_id] with a passed in value of the user’s chosen plan

 1 def create(site, user)
       2   @site = Site.new(site)
       3   @user = @site.users.build(user)
       4   
       5   if @site.save  && @user.valid?
       6     # encodes message for merb's message[:notice] to redisplay.
       7     notice = encoded_notice(:message => {:notice => 'Site was successfully created'})
       8 
       9     redirect "#{Merb::Config[:spreedly_url]}/subscribers/#{@site.id}/subscribe/#{Merb::Config[:spreedly_plan_one_id]}/#{@site.subdomain}?return_url=http://#{@site.subdomain}.#{Merb::Config[:site_url]}?_message=#{notice}"
      10     
      11   else
      12     @site.destroy
      13     message[:error] = "Site failed to be created"
      14     render :new
      15   end
      16 end
      

The rest all happens on spreedly, and then the user gets redirected via the return_url. That’s how easy it is to accept payment.

Also, here’s the encoded notice helper. Put this in your global helpers.

1   def encoded_notice(opts = {})
      2     # from /home/merb/merb-docs/current/gems/gems/merb-core-1.0.8.1/lib/merb-core/controller/mixins/controller.rb, line 132. this is something that could definitely end up needing fixing
      3     default_redirect_options = { :message => nil, :permanent => false }
      4     opts = default_redirect_options.merge(opts)
      5     if opts[:message]
      6       "#{Merb::Parse.escape([Marshal.dump(opts[:message])].pack('m'))}"
      7     end
      8   end
      

1   def encoded_notice(opts = {})
2 # from /home/merb/merb-docs/current/gems/gems/merb-core-1.0.8.1/lib/merb-core/controller/mixins/controller.rb, line 132. this is something that could definitely end up needing fixing
3 default_redirect_options = { :message => nil, :permanent => false }
4 opts = default_redirect_options.merge(opts)
5 if opts[:message]
6 "#{Merb::Parse.escape([Marshal.dump(opts[:message])].pack(m))}"
7 end
8 end

Getting subscriber info from Spreedly

We will use ActiveResource to create a Subscriber model that queries the Spreedly api.

1 $ merb-gen model Subscriber
      
1 # models/subscriber.rb
      2 class Subscriber < ActiveResource::Base
      3   self.site = "https://2fc4873fb65e3652eb36438be7422a424fa810e:X@spreedly.com/api/v4/test-investobot"
      4 end
      

Add active resource to your merb dependencies.rb file.

1 dependency "activeresource", "2.3.0"
      

1 dependency "activeresource", "2.3.0"

Bundle it up.

1 $ thor merb:gem:install
      

1 $ thor merb:gem:install

No you can run commands like this in merb -i

1 merb -i
      2 > Subscriber.create(:customer_id => "1", :screen_name => 'mottemen')
      3 > Subscriber.find(:all)
      4 # see https://spreedly.com/manual/integration-reference/api-access-using-rails/ for more details
      

1 merb -i
2 > Subscriber.create(:customer_id => "1", :screen_name => ‘mottemen’)
3 > Subscriber.find(:all)
4 # see https://spreedly.com/manual/integration-reference/api-access-using-rails/ for more details

You can now use your model to pull down subscriber info and post it on the user’s account page. Cool, huh.

Instead of storing all this information in the user, account, or sites table we are letting Spreedly store it, and using our Subscriber model as a go between to display it for us in our views. *You’ll probably want to cache this Subscriber info – otherwise, you will slow your application down by waiting on Spreedly.

Example:

1         @subscriber = Subscriber.find(:first)
      2         <p>Active: <%= @subscriber.active # returns true or false %></p>
      3         <p>Full Name: <%= @subscriber.billing_first_name %> <%= @subscriber.billing_last_name %></p>
      

1         @subscriber = Subscriber.find(:first)
2 <p>Active: <%= @subscriber.active # returns true or false ></p>
3 <p>Full Name: <
= @subscriber.billing_first_name > <= @subscriber.billing_last_name %></p>

Listen for changes from Spreedly

Since Spreedly is keeping track of everything, we need to listen for changes whenever they happen. For example in our app, we might have a before filter that checks if the current site is active.

In sites.rb for datamapper you property schema would have the following along with the rest of your schema like subdomain, domain, folder, timestamps, etc.

1         property :active, Boolean, :default => false
      2   property :spreedly_token, String
      

1         property :active, Boolean, :default => false
2 property :spreedly_token, String

Then in application.rb we could do something like:

 1         class Application < Merb::Controller
       2 
       3           before :get_site
       4           def get_site
       5             if request.first_subdomain != nil
       6               @current_site = Site.first(:subdomain => request.first_subdomain)
       7                                 if @current_site.active == false
       8                                         # redirect somewhere or raise an exception
       9                                 end
      10             end
      11           end
      12 
      13         end
      

 1         class Application < Merb::Controller
2
3 before :get_site
4 def get_site
5 if request.first_subdomain != nil
6 current_site</span> = <span class="co">Site</span>.first(<span class="sy">:subdomain</span> =&gt; request.first_subdomain) <span class="no"> 7</span> <span class="r">if</span> <span class="iv">current_site.active == false
8 # redirect somewhere or raise an exception
9 end
10 end
11 end
12
13 end

But what happens if a subscriber on Spreedly stops paying for their site? We need a way to keep track of that. We could use Subscriber.find(subscriber_id).active. This will now be equal to false, but we don’t want to have to manually check these all the time. We could run a cron job to check spreedly, but Spreedly makes it easier than that.

Each time one of your subscribers change Spreedly sends a restful post to the url of your choosing one minute later. All we need to do is create this restful post route and then tell Spreedly about it in the settings. Let’s do it.

This is gleaned from here.

1  # router.rb
      2  resources :sites, :collection => { :changed_on_spreedly => :post }
      
 1  # sites.rb controller
       2  class Sites < Application
       3   # provides :xml, :yaml, :js
       4 
       5   def changed_on_spreedly(subscriber_ids)
       6     subscriber_ids = subscriber_ids.split(",")
       7     subscriber_ids.each do | subscriber_id |
       8       site = Site.get(subscriber_id)
       9       site.refresh_from_spreedly if site
      10     end
      11   end
      12 
      13         ..
      

As you can see it takes the subscriber_ids that spreedly sends us, parses them up, and then refreshes the site from spreedly with parameters we specify in refresh_from_spreedly. Let’s check that method out.

 1         # site.rb model
       2         ..
       3 
       4         # Spreedly method from https://spreedly.com/manual/integration-guide/expose-a-change-subscription-link/
       5         # also here http://github.com/duff/crew/commit/e839084b49f8d18feccfb2457e9d0984e1c93a3c
       6         def refresh_from_spreedly
       7           # Subscriber is using activeresource
       8           subscriber = Subscriber.find(self.id)
       9           self.update_attributes(:active => subscriber.active, :spreedly_token => subscriber.token)
      10         rescue NotFound
      11           self.update_attribute(:active, false)
      12         end
      

Don’t forget to change your Subscribers Changed Notification URL on Spreedly.com to the one we specified as /sites/changed_on_spreedly


That is as much as I have so far from my forays into Spreedly yesterday evening. I also tried using HTTParty and rest-client, but with no luck so I stuck with activeresource.


Notes:

Picture of Scott Motte

delicious facebook rss twitter

Spitfire Sky | github | archives | resume