How to create a Spree Commerce extension

How to create a Spree Commerce extension

Hi everybody! Last week I showed you the extension Spree It is a present I created for Be Bellón and I promised you that this week I would tell you how to create these extensions. A promise is a promise, so taking this extension as an example, techie post is coming 😉


In order to create the extension Spree It is a present I based myself on  Spree’s guide to create extensions. As you can imagine, albeit this guide is very complete and very well written, it cannot cover every detail, so for the things I did not find in the guides I took a look to other already existing Spree extensions, and in order that you have everything in a single place, I will describe here the whole process to you. Let’s go!


The first thing you need to do is to make sure you have the spree gem installed so that you can use its extension’s generator. Assuming you already have ruby installed on your machine, on a terminal run:

gem install spree

This command should install spree and all necessary dependencies.


Spree gem includes an extension generator that gives you almost everything ready to start coding. It creates the structure of your extension, includes an open-source BSD 3 license, which allows everyone to use your software exonerating you from all liability in case it creates any sort of damage, and adds a very decent README file, you should only need to adjust a few things in the Gemspec file and start programming!

To use the generator simply execute the following command indicating the name you want to give to your extension. In spree_it_is a present‘s case it was:

spree extension it_is_a_present

The result should be something similar to this:

As you can see, the generator creates a directory with the name you indicated, prefixed with spree_. In our case spree_it_is_a_present. Change to that directory and open your favorite editor:

cd spree_it_is_a_present

And install your extension dependencies:

bundle install


If your extension needs to persist some data you will need to add a migration.

Spree’s official extension guide shows how to add a field to an already existing model.

In our case we needed to add a completely new model ,which we named Spree::PresentNote. You should add a migration as you would do in other Rails’ project, in our case, by just executing the following command:

bundle exec rails g migration CreateSpreePresentNotes recipient_name dedication

Once the migration file has been generated, we change it to match our needs:

Pay attention to the following details here. First see how spree_present_notes references an already existing Spree’s model (Spree::Order), which although here it is reference as :order, later you will see what do we need to add to the model so that Rails knows which model should this be related to. And second, in your other Rails projects your migrations will typically inherit from ActiveRecord::Migration. Here, instead of that, add require 'spree_extension/migration' and make them inherit from SpreeExtensionMigration. This will make your extensions compatible with Rails versions earlier than 5.x, (See SpreeExtension::Migration).

This migrations will be copied into the applications that consume our extension when they install it, let’s see how it is done.


The earlier you start using your extension, the earlier you will know how it behaves. On top of that it is really cool to see how it gets real!

Let’s add your newborn extension to your Spree application. In your Gemfile, add your extension indicating the path where it is located in your machine (Adjust this path to your needs)

gem ‘spree_it_is_a_present’, path: ‘../path/spree_it_is_a_present’ # Use the path where your gem is located in your computer

Run bundle install

bundle install

Once ready, run this command to install your extension. If prompted to run your migrations, enter Yes:

bundle exec rails g spree_it_is_a_present:install


This part is pretty straight forward since the only thing you need to do is add the code for your new model. In this case we create the model Spree::PresentNote (app/models/spree/present_note.rb).

As a detail that does not come in the official guides and might be relevant to you, take a look at how I relate Spree::PresentNote with the already existing Spree::Order model.

At this point you might want to add factories or fixtures for your tests, if you would like to know how did I add them here is the link to that exact commit.


Once we have created Spree::PresentNote we need to associated it with Spree::Order from the latter so that we can navigate through objects. As Spree::Order already exists, we need to extend it, to do that we create a decorator for Spree::Order using ActiveSupport::Concern in app/models/spree_it_is_a_present/spree/order_decorator.rb 

As you can see, on top of adding a relations, we also indicate that from now on Spree::Order will accept nested attributes for :present_note. This is important so that we can persist this in formation within the checkout’s form later.

At this point it would be convenient to add some tests. I used RSpec and FactoryBot, but you can also use other frameworks.

What we would like to be sure is that Spree::Order is able to also persist data about its related Spree::PresentNote.

On top of that, it would also be interesting to know if our new model works as expected, and although these tests could not be necessary in other projects, I think they are useful here to avoid future regressions since I hope this gem will be shared among many people.


The first thing you need to show something is to have something to show. For that, we will create a partial that contains our form and we will display it using Deface. The partial would be like this:

Modifying views with Deface is very easy because Spree Commerce’s most relevant HTML elements provide IDs for this purpose. To be honest I do not know if using Deface will be also the way to go in the future since Spree’s core team decided to stop including this dependency, but for the time being the main gems in spree-contrib continue using it. As the upgrading guide says, if you use this kind of extensions you need to add Deface to your Gemfile.

Here you can see how I added the form partial to the checkout form:


Great, we already have the models (step  5 ) and we also have the views, What else do we need? Exactly, the glue, the controller.

Spree’s default checkout controller responsible of persisting Spree::Order instances has no idea about how to persist Spree::PresentNote records. In step 5 we told Spree::Order it should accept nested attributes for Spree::PresentNote, but at some place we should provide these. That place will be Spree::CheckoutController, which is where Spree gets all parameters related to orders and persists them. To do that, we will rely again on the Decorator pattern.


The last steps would be to add a form and a controller for the backend side. But as this is analogous to what we already saw in steps 6 and 7, I will not further extend this post with that. If you would like to take a look at it here you have the link to the Spree It is a commerce’s link in which I added it. After this you just need to polish the gem a little bit and share it with the world.

If you have worked with me in the past you already know I like to have a commit history as clean as possible, so if you are interested on knowing step by step how I added things to the gem you can check commit by commit here.

And this is the end of this week’s post! I hope you enjoyed it and… see you next week! Adiós!

No Comments

Post A Comment