Creating a product file for Merchant Center in Rails
How to create a product file for Google's Merchant Center in Rails, without any additional gems
In this guide we will walk through all the steps needed to generate a product file for Google’s Merchant Center using Ruby on Rails, without the need for any additional gems.
There are a few different ways Google allows you to communicate with the merchant center, you can create a tab-delimited spreadsheet, you can use an API, or, and what we are going through, you can submit an XML file.
Both the tab-delimited spreadsheet and XML are what they call the “product file”. You can think of this file as a source of truth for all the products you want to appear within the Merchant Center.
Why pick XML
We decided to use XML because creating XML files is baked right into Rails, it has support out of the box which makes serving up XML files feel very natural.
If you’ve never seen an XML file before, it sort of looks like HTML, here is a random example, note that the elements are specific to the purpose of the file (this is storing information about a note between two people).
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tina</to>
<from>John</from>
<subject>Reminder</subject>
<body>Don't forget the meeting at 10 AM tomorrow.</body>
</note>
High level actions
Let’s run through some of the things we will be doing;
Find an appropriate controller action
If you are selling products, you hopefully have some sort of product list view, if we assume you have a ProductsController
then the index
action would be the best place for us to put our code.
We need to tell this action to respond to XML requests, as well as HTML (the default) requests.
For this we use respond_to
, which takes a block and a series of things to do based on the format of the request.
class ProductsController < ApplicationController
def index
@products = Product.live
respond_to do |format|
format.html
format.xml { render layout: false }
end
end
end
What we are saying here is “when HTML, act like normal”, and “when XML, render the view, but without any layout around it”.
We do this because for XML, we don’t want our application.html.erb
code to top and tail our code.
It is worth noting that your code might include pagination logic or other filtering which you may need to split out for our XML view (which we don’t need to paginate or limit as much).
Next up, we need to create the view
Create a new controller action
If you don’t have the equivalent of a products#index
, you should make one. You could use the above code and just remove the format.html
section from respond_to
, since we don’t care about showing an HTML version of this feed.
One thing to consider when making a new action, instead of borrowing an existing one, is that you likely have some sort of scope to suggest a product is live
or some other type of filtering. We only want to generate the XML for products we eventually wish to appear in Google’s listing.
Create the view
Using Google’s sample XML as a guide, we need to create something XML-shaped in our view.
We want to create a file called index.xml.builder
inside app/views/products
, or whatever is appropriate for your resource set up.
The end file will look like the below, but don’t worry, we will talk through the main elements of this.
# frozen_string_literal: true
xml.rss 'xmlns:g': 'http://base.google.com/ns/1.0', version: '2.0' do
xml.channel do
xml.title 'Our title'
xml.description 'Our description'
xml.link products_url
@products.each do |product|
xml.item do
xml.g :id, product.id
xml.g :title, product.title
xml.g :description, strip_tags(product.description)
xml.g :link, product_url(product)
xml.g :image_link, product.image.url
xml.g :condition, 'new'
xml.g :availability, 'in_stock'
xml.g :price, "#{product.price} #{product.main_currency}"
end
end
end
end
Chained file names
First up, lets talk about the file name, index.xml.builder
. This will look familiar if you use something like erb
, you might even have a file in the same directory called index.html.erb
.
Rails works from right to left when processing view files, passing the file through different formatters in that order.
In our case, our file will get processed by builder
first, then xml
.
So, what is “builder”?
The Builder gem
Builder is a a gem that is required by ActionView. Builder provides an easy way to build XML documents and fragments.
The structure of the file
We start with a root element;
xml.rss 'xmlns:g': 'http://base.google.com/ns/1.0', version: '2.0'
This tells the file to use the RSS specification version 2.0 and that the namespace to use is “g” which is defined at the URL provided.
If you’re wondering why RSS, it is because this XML document is being treated as a feed of information, which RSS is perfect for.
Next up we need a wrapper for everything, as well as three things common to all RSS type feeds; a title, a description, and a link. The link should be to the HTML version of your shop.
xml.channel do
xml.title 'Our title'
xml.description 'Our description'
xml.link products_url
Now we get into the individual items, so we iterate over our @products
collection and for each one put out their properties.
@products.each do |product|
xml.item do
xml.g :id, product.id
xml.g :title, product.title
xml.g :description, strip_tags(product.description)
xml.g :link, product_url(product)
xml.g :image_link, product.image.url
xml.g :condition, 'new'
xml.g :availability, 'in_stock'
xml.g :price, "#{product.price} #{product.main_currency}"
end
end
Of note here you’ll see xml.g :id
, this will generate an XML element that looks like <g:id>
.
Read the Product data specification guide to learn more about the specific attributes you should include, and the format expected for them.
Hook up any new routes
If you were able to hook the XML view into an existing controller action, then you shouldn’t need a new route. If your products#index
is accessed via mysite.com/shop
, then visiting mysite.com/shop.xml
should work.
If you needed to create a new controller or action, you will need to create the appropriate route.
resources :products only: :index
Submit your feed
This article doesn’t cover testing this feed, because how you test will depend quite a lot on your setup and I don’t want to make assumptions. At the very least you should check that visiting your development environment can generate the file correctly and with the information you’d expect.
All being well, we should now be able to visit /products.xml
, or the route you’ve created, and see a well formatted XML file ready for submission.
Because of how we’ve set this up, any time Google crawls the XML file, it will get the most up to date information.
You can set how frequently this is crawled from within the Merchant Center.