Ben Morgan I/O

Web Development

Do you like my blog?

I'm a programmer who rants and raves about SEO, social media, web programming, and maybe some physics. If you are in the same field as me, read! I have tutorials.

Imagine developing an application where you need to grab shipping data in real time, send products, inventory, and order information over at least ten different APIs including Amazon and eBay. When I first heard that I had to do this, there could only be one answer: “Challenge accepted”.

If you’re reading this, then you probably know what Ninefold does and why you would use Spree, but let me introduce you to Wombat: the operating system for ecommerce applications.

Now, Wombat has an enormous amount of documentation on how to use their app, but to be frank: they don’t have a lot yet when it comes to hooking Wombat up to Spree.

In this blog post, we’re going to go from start to finish on building a Wombat application and then deploying it onto Ninefold.

Getting Started with Wombat

Lets first install spree with these commands:

$ rails new wombat_app --database postgresql
$ cd wombat_app
$ spree install -A

Now that your store is set up, lets get Wombat installed. Simply add Wombat to your Gemfile:

gem 'spree_wombat', github: 'spree/spree_wombat', branch: '2-3-stable'

And when you’re ready:

$ bundle
$ bundle exec rails g spree_wombat:install

Once that is finished, head over to Wombat and sign up for a two week trial. When you’re set up, update config/initializers/wombat.rb to include your connection token and ID.

Wombat Configuration

Inside of the Wombat configuration, you’ll see that there’s a #push_objects method. In here, you will have an array of strings that Wombat can use to identify which object you want to send up to Wombat.

Inside of the #payload_builder this is where you’ll add the JSON to get pushed up to Wombat. The :root is used to tell Wombat exactly what type of JSON you’re giving it. You want this because in Wombat, you call your users “customers”, therefore you would need a way to specify how Wombat should interpret the data vs your application (this is how Wombat is made universal and app-agnostic). Now, to grab the JSON that Wombat will need to send up to cloud, you use a serializer. Wombat comes with some serializers upfront (except a user serializer, but I’ll show you how to make that further on).

Finally, we have #push_url which will push the data to wombat. Leave it to its default unless you customize your Wombat profile; you’ll know if you need to change it.

Pushing Data Manually to Wombat

If you set up Spree and Wombat correctly, then you should be able to send two Spree example orders up to Wombat. To do this, lets enter the rails console (with rails c):

> Spree::Wombat::Client.push_batches("Spree::Order")

If you check out your Wombat page, you should see that those orders have been pushed up. If you want to send all of the objects that you have defined in Wombat (and there are times that you will want to do this), then you would use Wombat’s built in rake task:

$ bundle exec rake wombat:push_it

If you check out Wombat, you should see all of your products up there as well.

Adding a Wombat Serializer

This is all fine and dandy, but you happen to have some shipments you want up on Wombat as well. Thankfully, Wombat already has this shipment serializer predone for you! Lets set this up within our application.

Set your #push_objects to include the "Spree::Shipment" model:

config.push_objects = ["Spree::Order", "Spree::Product", "Spree::Shipment"]

Now, inside of your #payload_builder, you’ll want to make sure you add it as a key ("Spree::Shipment") with a Hash as a value ({ serializer: "Spree::Wombat::ShipmentSerializer", root: "shipments" }). This should give you:

config.payload_builder = {
  "Spree::Order" => { serializer: "Spree::Wombat::OrderSerializer", root: "orders" },
  "Spree::Product" => { serializer: "Spree::Wombat::ProductSerializer", root: "products" },
  "Spree::Shipment" => { serializer: "Spree::Wombat::ShipmentSerializer", root: "shipments" }
}

Now, if you perform Spree::Wombat::Client.push_batches("Spree::Shipment") you should be able to see it in Wombat.

Adding a Custom Serializer

You now have three objects hitting Wombat. Wombat lists four objects it will take by defualt. Let’s give it the final one: customers!

To begin, we will generate the serializer using Wombat’s serializer generator:

bundle exec rails g spree_wombat:serializer Spree::User UserSerializer

Within the app/serializers/user_serializer.rb this is the code that I use:

require 'active_model/serializer'

class UserSerializer < ActiveModel::Serializer
  attributes :id, :firstname, :lastname, :email, :shipping_address, :billing_address

  def id
    object.id
  end

  def firstname
    object.try :first_name
  end

  def lastname
    object.try :last_name
  end

  def email
    object.email
  end

  def shipping_address
    address_hash object.shipping_address
  end

  def billing_address
    address_hash object.billing_address
  end

  private

  def address_hash(address)
    {
      address1: address.address1,
      address2: address.address2,
      zipcode: address.zipcode,
      city: address.city,
      state: address.state.name,
      country: address.country.name,
      phone: address.phone
    }
  end
end

Your #push_objects should now look like:

config.push_objects = ["Spree::Order", "Spree::Product", "Spree::Shipment", "Spree::User"]

And your #payload_builder should be:

config.payload_builder = {
  "Spree::Order" => { serializer: "Spree::Wombat::OrderSerializer", root: "orders" },
  "Spree::Product" => { serializer: "Spree::Wombat::ProductSerializer", root: "products" },
  "Spree::Shipment" => { serializer: "Spree::Wombat::ShipmentSerializer", root: "shipments" },
  "Spree::User" => { serializer: "UserSerializer", root: "customers" }
}

Using After Commits with Wombat

Now that this is all done, you’re probably tired of doing it manually. Using decorators, you can add some after_commits to push the model’s data up to Wombat when an ActiveRecord transaction has finished. Here’s an example using the Spree::Shipment model:

# app/models/spree/shipment_decorator.rb
Spree::Shipment.class_eval do
  after_commit :wombat_push_spree_shipments, on: [:create, :update]

  private

  def wombat_push_spree_shipments
    Spree::Wombat::Client.push_batches("Spree::Shipment")
  end
end

Now, if you create a new shipment (and follow this pattern for your other three models) then you should be able to get your data up to wombat in realtime.

Using Workers with Wombat

There’s an issue with this though. What if the page takes two seconds to load and eight seconds to get updated on Wombat? That means that you’ll have eight seconds of blocking code and the amount of time on the server to render the next page for the user would be ten seconds. To get around this, we’re going to set up a Wombat worker and get it done using Resque.

To begin, we’re going to need to install Redis. To do so, follow Redis Rails installation instructions. When finished, add Resque to your Gemfile:

gem 'resque', '~> 1.25', require: 'resque/server'

After bundling, start up these three servers:

web: rails s
redis: redis-server redis.conf
worker: bundle exec rake resque:work QUEUE=* TERM_CHILD=1

You should be good to go. Now, inside fo your Spree::Shipment model, update it to:

Spree::Shipment.class_eval do
  after_commit :wombat_push_spree_shipments, on: [:create, :update]

  private

  def wombat_push_spree_shipments
    Resque.enqueue(WombatWorker, "Spree::Shipment")
  end
end

The only ine that we’ve changed is line 7 where we state that we’re going to be using Resque. The first argument is WombatWorker which is the class of the worker that will handle anything and everything Wombat. First, in your application.rb add the workers directory to your load path:

# Load application's workers
Dir.glob(File.join(File.dirname(__FILE__), "../app/workers/*_worker.rb")) do |c|
  Rails.configuration.cache_classes ? require(c) : load(c)
end

When finished, restart your web server and make a new file called app/workers/wombat_worker.rb:

# app/workers/wombat_worker.rb
class WombatWorker
  @queue = :wombat_worker_queue

  def self.perform(wombat_payload)
    Spree::Wombat::Client.push_batches(wombat_payload)
  end
end

Using @queue we name the queue using a symbol and then use #perform to execute the worker code. Here, wombat_payload will be whatever our second argument is in the Resque.enqueue method that we added within the spree shipment decorator.

Deploying to Ninefold

Lets get this app onto Ninefold. First, we’ll need a Procfile:

# Procfile
redis: redis-server redis.conf
worker: bundle exec rake resque:work QUEUE=* TERM_CHILD=1

Push up all your code to Github and then head over to Ninefold to sign up as a new user.

When done, sign in and create a new application. Select where you’re storing your code (such as Github) and then you should be on step 2. If not, you’ll be asked to sign into Github through Ninefold. Now, you specify the account, repo, and which branch or release that you would like to deploy to. It will then ensure that you are using PostgreSQL, that you do not have rails_12factor gem, and that your application is a valid Rails app.

On step 3, you get to choose your architecture. You’re going to need a web server, so go ahead and make sure you’re using the 2GB - 1vCPU in whichever region is closest to you. Make sure you have a dedicated PG database server for your app (makes it easy to scale). Yes, you would like a background worker for your app and you will want it dedicated. Also make sure that this is a 1GB - 1vCPU server. Finally, push the “Next” button and you should be on Step 4 deployin gyour application

Wrapping Up

Throughout this blog post, you have discovered how to install Spree and Wombat, send data to Wombat, set up serializers, set up a WombatWorker, and finally deploy it onto production using Ninefold. I hope this blog post was informative and useful. Have fun!

Posted 1 week ago on

Quite often, I find that Foreman and Zeus don’t always go hand in hand, so in this quick write up, I’m going to show you how to get the power of Zeus inside of the great Foreman.

To start, lets assume that this is what our Profile looks like:

web: bundle exec thin start -p $PORT
redis: redis-server redis.conf
worker: bundle exec rake resque:work QUEUE=* TERM_CHILD=1

That’s great, except if we want to run zeus with it, we have to have two tabs open. One tab runs zeus start and the other tab run the Procfile as:

web: zeus s
redis: redis-server redis.conf
worker: bundle exec rake resque:work QUEUE=* TERM_CHILD=1

OK, that’s kinda works, but now we have two tabs. Let’s change that:

zeus: zeus start
web: zeus s
redis: redis-server redis.conf
worker: bundle exec rake resque:work QUEUE=* TERM_CHILD=1

This breaks one in a while since Foreman will start each process randomly giving us the Can't connect to master. Run zeus start first. error.

To get past this, we will update the Procfile to:

zeus: zeus start
web: sleep 2 && zeus s
redis: redis-server redis.conf
worker: bundle exec rake resque:work QUEUE=* TERM_CHILD=1

Now we can have web sleep for 2 seconds, giving it enough time to detect zeus start and therefore stalling until it receives the green light from Zeus.

We’re not done yet. You may notice that the output is not so pretty anymore. Instead, try this:

zeus: zeus start &> /dev/null
web: sleep 2 && zeus s
redis: redis-server redis.conf
worker: bundle exec rake resque:work QUEUE=* TERM_CHILD=1

This is great, but now we don’t know when Zeus is starting. To fix this we’ll add a simple echo:

zeus: echo "Starting Zeus..." && zeus start &> /dev/null
web: sleep 2 && zeus s
redis: redis-server redis.conf
worker: bundle exec rake resque:work QUEUE=* TERM_CHILD=1

And there we go, you now know how to get Zeus and Foreman running together. Have fun!

Posted 3 weeks ago on

In Spree, I run into this error a LOT and it always takes some time to debug, so here, I am not only going to solve it and make a detailed listing of what the possible issues are, but make sure that I don’t spend another two hours going through this head ache.

What happens is that when you are using Spree, you will hit the checkout page and you will submit your address information. On submission you ge this infamous error.

This error is caused because you have either made a product with no shipping information (which is easy to solve) or your tax information is not correct…

to solve the shipping method error, just slip over to the admin product edit page and see if the product you’re trying to but has a shipping method. It usually does and this unlikely the error. Anywho, just select Default in the drop down if you’re on a brand new store.

If, however, this is not the solution (and it probably isn’t), then you need to do some taxes. To start, lets talk about zones. Zones in spree define exactly in what areas of the world some tax information applies to. This a great junction to introduct the problem because (a) you might not have a zone set up for your default tax or (b) the problem now lies in either the countries/states or the tax information.

In the right side bar to the configuration, do you see a “States” button? If you don’t you might want to load up this data into your app:

The Countries.

The States.

The Zones.

And since Spree (as of 2.3.1) does not contain the Canadian states:

canada = Spree::Country.find_by_name('Canada')
Spree::State.create!([
 { "name" => "Yukon", "abbr" => "YT", country: canada },
 { "name" => "Nunavut", "abbr" => "NU", country: canada },
 { "name" => "British Columbia", "abbr" => "BC", country: canada },
 { "name" => "Alberta", "abbr" => "AB", country: canada },
 { "name" => "Saskatchewan", "abbr" => "SK", country: canada },
 { "name" => "Manitoba", "abbr" => "MB", country: canada },
 { "name" => "Ontario", "abbr" => "ON", country: canada },
 { "name" => "Quebec", "abbr" => "QC", country: canada },
 { "name" => "New Brunswick", "abbr" => "NB", country: canada },
 { "name" => "Newfoundland and Labrador", "abbr" => "NL", country: canada },
 { "name" => "Nova Scotia", "abbr" => "NS", country: canada },
 { "name" => "Prince Edward Island", "abbr" => "PE", country: canada },
 { "name" => "Northwest Territories", "abbr" => "NT", country: canada }
])

And now your app works for the geography. Lets hook up the tax information.

There are currently three settings for taxes: Tax Categories, Tax Rates, and Tax Settings.

We’ll go ahead and create a tax category and tax rate for clothing using Spree Sample’s data.

Spree::TaxCategory.create!(:name => "Clothing")
north_america = Spree::Zone.find_by_name!("North America")
clothing = Spree::TaxCategory.find_by_name!("Clothing")
tax_rate = Spree::TaxRate.create(
  :name => "North America",
  :zone => north_america,
  :amount => 0.05,
  :tax_category => clothing)
tax_rate.calculator = Spree::Calculator::DefaultTax.create!
tax_rate.save!

Now, if you head into the admin section and set clothing as the default and the North America zone as your default you should be good to go from the tax/geo section of this error.

But, wait, remember that this was also being caused because of the shipping information?

Well, you can solve this by adding in shipping information, or rather, shipping methods:

begin
  north_america = Spree::Zone.find_by_name!("North America")
rescue ActiveRecord::RecordNotFound
  puts "Couldn't find 'North America' zone. Did you run `rake db:seed` first?"
  puts "That task will set up the countries, states and zones required for Spree."
  exit
end

europe_vat = Spree::Zone.find_by_name!("EU_VAT")
shipping_category = Spree::ShippingCategory.find_or_create_by!(name: 'Default')

Spree::ShippingMethod.create!([
  {
    :name => "UPS Ground (USD)",
    :zones => [north_america],
    :calculator => Spree::Calculator::Shipping::FlatRate.create!,
    :shipping_categories => [shipping_category]
  },
  {
    :name => "UPS Two Day (USD)",
    :zones => [north_america],
    :calculator => Spree::Calculator::Shipping::FlatRate.create!,
    :shipping_categories => [shipping_category]
  },
  {
    :name => "UPS One Day (USD)",
    :zones => [north_america],
    :calculator => Spree::Calculator::Shipping::FlatRate.create!,
    :shipping_categories => [shipping_category]
  },
  {
    :name => "UPS Ground (EU)",
    :zones => [europe_vat],
    :calculator => Spree::Calculator::Shipping::FlatRate.create!,
    :shipping_categories => [shipping_category]
  },
  {
    :name => "UPS Ground (EUR)",
    :zones => [europe_vat],
    :calculator => Spree::Calculator::Shipping::FlatRate.create!,
    :shipping_categories => [shipping_category]
  }
])

{
  "UPS Ground (USD)" => [5, "USD"],
  "UPS Ground (EU)" => [5, "USD"],
  "UPS One Day (USD)" => [15, "USD"],
  "UPS Two Day (USD)" => [10, "USD"],
  "UPS Ground (EUR)" => [8, "EUR"]
}.each do |shipping_method_name, (price, currency)|
  shipping_method = Spree::ShippingMethod.find_by_name!(shipping_method_name)
  shipping_method.calculator.preferences = {
    amount: price,
    currency: currency
  }
  shipping_method.calculator.save!
  shipping_method.save!
end

Hope that works for you! It works for me. Have at it.

Posted 1 month ago on

Spree is an ecommerce framework for Ruby on Rails that is currently at version 2.2.2. I often find that individuals come to spree when Magento or Shopify just can’t serve their needs anymore and they need an even more custom solution.

To get started, we first need to install spree:

$ gem install spree

OK, that was fun, now let’s go ahead and make a new rails project:

$ rails _4.0.5_ new spree_app

Now that you have that done, try this out:

$ spree install spree_app

Or, if you’ve already navigated into spree_app:

$ spree install .

You will get a number of questions:

Would you like to install the default gateways? (Recommended) (yes/no) [yes]
Would you like to install the default authentication system? (yes/no) [yes]
Would you like to run the migrations? (yes/no) [yes]
Would you like to load the seed data? (yes/no) [yes]
Would you like to load the sample data? (yes/no) [yes]

Right now, please answer yes (the default) to all of them. When starting a new spree project, I often do spree install . -A which auto-accepts all parameters.

Now, as its installing, it will stop and ask you to create an Admin user:

Create the admin user (press enter for defaults).
Email [spree@example.com]:
Password [spree123]:

Just push the default options so that we can get going.

Throughout the installation, you might have noticed this warning:

[WARNING] You are not setting Devise.secret_key within your application!
You must set this in config/initializers/devise.rb. Here's an example:

Devise.secret_key = "a0c5e56c8764a93b03fce02083f4aed18aef63ef4d7be33f351accb002d4e2187ac6ba4a78090c341281f51a6abebd4fe499"

Now I’m going to tell you how to solve this. If you open up your Gemfile it should look like this:

source 'https://rubygems.org'

gem 'rails', '4.0.5'
gem 'sqlite3'

gem 'sass-rails', '~> 4.0.2'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.0.0'

gem 'jquery-rails'
gem 'turbolinks'
gem 'jbuilder', '~> 1.2'

group :doc do
  gem 'sdoc', require: false
end

gem 'spree', '2.2.2'
gem 'spree_gateway', github: 'spree/spree_gateway', branch: '2-2-stable'
gem 'spree_auth_devise', github: 'spree/spree_auth_devise', branch: '2-2-stable'

Notice at the bottom there were 3 gems that got installed. spree is the main project and is definately what you wanted to install. There’s also two more: spree_gateway and spree_auth_devise. spree_gateway basically handles active merchant, stripe, checks, stuff that allows you to receive money. spree_auth_devise is used for authenticating users. Its different from devise in that it requires you to be running devise; since bundler detects that you don’t have it in your Gemfile, it does it for you - the magic of Bundler.

Because spree_auth_devise is its own gem, it actually never got installed fully when you ran spree install. Therefore, we have to do another installation for spree_auth_devise. Here’s how you install spree_auth_devise:

$ bundle exec rails g spree:auth:install

you will see the error pop up one more time and then directly after that you get:

create  config/initializers/devise.rb

And there we go, its gone. Alternatively, you could have also created the initializer yourself and copy and pasted the devise secret key. To generate secret keys, you can use rake secret like so:

$ rake secret
9ba50700679fc17712ce1a1538bb9dd05c31038e12d1155cb8d437a9dd69a0a2fc8b7f9425f254c77d5bfa0587c9e50df0931f3803d947eb5fe13c7d1b6cec00

And there you go, now lets start the application:

$ rails s

IF you head over to localhost:3000 you will see the spree skeleton. Awesome! But, you probably don’t like that design, so lets get bootstrap in there! In your Gemfile, add:

gem 'spree_bootstrap_frontend', github: '200Creative/spree_bootstrap_frontend', branch: '2-2-stable'

Now, bundle and then run:

$ rails generate spree_bootstrap_frontend:install

It should now ask you if you would like to overwrite one of your assets. Answer Y.

If everything is working for you right now, just go and type in rails s and watch the design completely change for the better.

You can now change the theme of you spree application with ease!

Posted 2 months ago on