views:

340

answers:

2

Right now I am trying to call my model, and spit out its results into json/xml format. My only problem is, my database associations aren't being loaded or queried.

Normally, I can just run this

@campaign = Campaign.find(:all)
Then get the number of hits by calling, @campaign[0].hits through the has_many :hits. But if you debug the output, it only calls the columns on the table. How would you go about having it put it alongside your query?

In example:
  <campaign>
    <category>website</category>
    <created-at type="timestamp">2009-01-24 14:49:02 -0800</created-at>
    <end-at type="date">2009-01-24</end-at>
    <id type="integer">14</id>
    <is-watched type="integer">1</is-watched>
    <name>Lets</name>
    <slug>c5334415da5c89384e42ce6d72609dda</slug>
    <start-at type="date">2009-01-24</start-at>
    <user-id type="integer">5</user-id>
  </campaign>

Then having it instead add another column, but witht he number of hits.

  <campaign>
    <category>website</category>
    <created-at type="timestamp">2009-01-24 14:49:02 -0800</created-at>
    <end-at type="date">2009-01-24</end-at>
    <id type="integer">14</id>
    <is-watched type="integer">1</is-watched>
    <name>Lets</name>
    <slug>c5334415da5c89384e42ce6d72609dda</slug>
    <start-at type="date">2009-01-24</start-at>
    <user-id type="integer">5</user-id>
    <hits type="integer">123412</hits>
  </campaign>
+7  A: 

The ActiveRecord find() family takes an :include option which allows you to eager load your associatons.

So all you need to do is:

@campaign = Campaign.find(:all, :include => :hits)

The above will eager load your database calls so that accessing each index [0]. [1], etc wont issue their own SELECT calls. When you call

@campaign[0].to_json

Then it will NOT include any associations, such as "hits" to do that then you also need to :include it on the to_json call, e.g.

@campaign[0].to_json(:include => :hits)

Cody Caughlan
That does what I asked, but is it possible to not return the rows, but to just count them, and return the integer?
Garrett
Yes. ActiveRecord returns an AssociationProxy (which acts like an Array but has more super-powers). One method that it has is "size()". So you could do @campaign = Campaign.find(:all, :include => :hits)@campaign.each do |cpg| puts "Hits: #{cpg.hits.size}"end
Cody Caughlan
AssocationProxy has "count", "size" and "length", covered here:http://rhnh.net/2007/09/26/counting-activerecord-associations-count-size-or-length
Cody Caughlan
But you wouldn't be able to add the to_json or to_xml right? Since this isn't adding it on as an array.Maybe a better question is, how to do another query and throw that in as a new column. Like a custom method.
Garrett
+1  A: 

You might be able to achieve what you want here by adding a hits_count field to your Campaign model. This will get automatically updated when new associations are added.

Have a look at counter_cache in the ActiveRecord Associations documentation

Steve Weet