Tag Archives: respond_to

Using rails and respond_to to include nested data

I want to display data from a nested table in my XML output using respond_to. I searched google a bit and it seems :include was the way to go. However I had some problems getting this to work properly.

I have two models (customer and user) that are linked together. When I fetch the data for a single user, I want my xml output to include the customer data.

The Customer model:

class Customer < ActiveRecord::Base
  has_many :users
end

The User model:

class User < ActiveRecord::Base
  belongs_to :customer
end

In my UserController I use the respond_to method to respond to html and xml data.
The show action is as follows:

# Shows the seleted user
def show
  @user = User.find(params[:id])
  
  respond_to do |format|
    format.html
    format.xml { render :xml => @user) }
  end
end

Calling the show action on the user controller as xml should yield something like:

<user>
  ...
  <customer>
    ...
  </customer>
</user>

But the customer data is not included.
This puzzled me a bit.

Searching a bit on google got me the following answer:

# Shows the seleted user
def show
  @user = User.find(params[:id])
  
  respond_to do |format|
    format.html
    format.xml { render :xml => @user.to_xml(:include => @user.customer) }
  end
end

source: http://rubydoc.info/docs/rails/3.0.0/ActionController/MimeResponds

(I also tried fetching the customer out separately, that didn't work either)

This gave me the following error:

undefined method `macro' for nil:NilClass

The solution

After a lot more searching I found out, that you shouldn't pass an object, but a symbol. The name of the symbol is the data block you want to show, so in my case it was :customer

The code to fix it was:

# Shows the seleted user
def show
  @user = User.find(params[:id])
  
  respond_to do |format|
    format.html
    format.xml { render :xml => @user.to_xml(:include => :customer) }
  end
end

The data for the customer now returned as well.

Need more data?

If you need data from several tables, just use an array of symbols instead.

# Shows the seleted user
def show
  @user = User.find(params[:id])
  
  respond_to do |format|
    format.html
    format.xml { render :xml => @user.to_xml(:include => [:customer, :table2, :table3]) }
  end
end

Hope you can use this tip.