Sometimes we need to provide an xml data feed in our Ruby on Rails applications. This article will show you how.

First, we will need a model and some sample data. In this sample project we will have 2 models. A book model, and a review model, which will be associated with books. Lets generate these 2 models now. Run the commands below to create the models and migrate the database.

Terminal Commands:

rails g model Book name author price:decimal{12,2} active:boolean
rails g model Review book:references user rating:integer body:text
rake db:migrate

Now lets add some seed data. Copy and paste the following seed data into your seeds.rb file.

db/seeds.rb:

Book.delete_all
Review.delete_all

Book.create!([
  {id: 1, name: "The Goldfinch", author: "Donna Tartt", price: 29.95, active: true},
  {id: 2, name: "Humans of New York", author: "Brandon Stanton", price: 19.95, active: true},
  {id: 3, name: "Thank You for Your Service", author: "David Finkel", price: 18.95, active: true},
  {id: 4, name: "The Night Guest:  A Novel", author: "Fiona McFarlane", price: 16.95, active: true},
])

Review.create!([
  {id: 1, book_id: 1, user: "Jenn", rating: 3, body: "Excellent Book!"},
  {id: 2, book_id: 1, user: "Joe", rating: 4, body: "Boring!"},
  {id: 3, book_id: 2, user: "Rick", rating: 5, body: "Amazing."},
  {id: 4, book_id: 2, user: "Earl", rating: 5, body: "I Love it!"},
  {id: 5, book_id: 3, user: "Tina", rating: 4, body: "A must read!"},
  {id: 6, book_id: 4, user: "Charlie", rating: 1, body: "I recommend everyone buy this!"},
  {id: 7, book_id: 4, user: "Mike", rating: 4, body: "Wow.  Just.  Wow."}
])

Next, run the seed command to populate your database.

Terminal Commands:

rake db:seed

Excellent, we now have a database populated with books and reviews. Next we will need to set up the our associations First, open up the Book model and modify it so that it looks like the code listed below.

app/models/book.rb:

class Book < ActiveRecord::Base
  has_many :reviews
end

Great, now lets add the reverse association. Open up your Review model and verify that it looks like the code listed below. Rails should auto populate this, but double check just to be sure.

app/models/reviews.rb:

class Review < ActiveRecord::Base
  belongs_to :book
end

With the database model created, our data populated, and our associations set up, now it's time to create a controller. Run the command below to create books controller.

Terminal Commands:

rails g controller books index

Now, lets make a change to our routes.rb file so that our controller becomes a resourceful controller. Replace the line that says get "books/index" with the code listed below.

config/routes.rb:

# get "books/index"
resources :books, only: [:index]

This sets up the books controller as a resourceful controller. Now, in order to create an xml feed, we must create a builder view. Create a new file in app/views/books called books.xml.builder and add the code listed below.

app/views/books/index.xml.builder:

xml.instruct!
xml.books do
end

Excellent. Now if you navigate to http://localhost:3000/books.xml You will see an empty xml data feed. Now, lets add some content to that data feed. Now, open up the books controller and modify it so that it looks like the code listed below.

app/controllers/books_controller.rb:

class BooksController < ApplicationController
  def index
    @books = Book.all
  end
end

Next, Open the xml builder file again and modify it so that it looks like the code listed below.

app/views/books/index.xml.builder:

xml.instruct!
xml.books do
  @books.each do |book|
    xml.book do
      xml.name book.name
      xml.author book.author
      xml.price number_to_currency book.price
      xml.active book.active
    end
  end
  
end

Now if we refresh the page we will see a listing of books in xml format. Now lets add the reviews. Modify your code so that it looks like the code listed below.

app/views/books/index.xml.builder:

xml.instruct!
xml.books do
  @books.each do |book|
    xml.book do
      xml.name book.name
      xml.author book.author
      xml.price number_to_currency book.price
      xml.active book.active
      xml.reviews do
        book.reviews.each do |review|
          xml.review do
              xml.user review.user
              xml.rating review.rating
              xml.body review.body
          end
        end
      end
    end
  end
end

Excellent! Now if we refresh the page we'll see the review listing for each book. That's it folks! That's all there is to creating an xml data feed. Thanks for reading!