0

I'm porting a php app to rails so I have a set of sql statements that I'm converting to find_by_sql's. I see that it returns a collection of objects of the type that I called on it. What I'd like to do is then iterate through this collection (presumably an array) and add an instance of a specific object like this:

#class is GlobalList
#sql is simplified - really joining across 3 tables
def self.common_items user_ids
    items=find_by_sql(["select gl.global_id, count(gl.global_id) as global_count from main_table gl group by global_id"])

    #each of these items is a GlobalList and want to add a location to the Array            
    items.each_with_index do |value,index|
        tmp_item=Location.find_by_global_id(value['global_id'])
        #not sure if this is possible
        items[index]['location']=tmp_item
    end
    return items
end

controller

#controller  
@common_items=GlobalList.common_items user_ids

view

#view code - the third line doesn't work
<% @common_items.each_with_index do |value,key| %>
        <%=debug(value.location) %> <!-- works -->
        global_id:<%=value.location.global_id %> <!-- ### doesn't work but this is an attribute of this object-->
<% end %>

So I have 3 questions:
1. is items an Array? It says it is via a call to .class but not sure
2. I am able to add location these GlobalList items. However in the view code, I cannot access the attributes of location. How would I access this?
3. I know that this is pretty ugly - is there a better pattern to implement this?

timpone
  • 19,235
  • 36
  • 121
  • 211

1 Answers1

0

I would get any data you need from locations in the sql query, that way you avoid the n+1 problem

   @items=find_by_sql(["select locations.foo       as location_foo, 
                               gl.global_id        as global_id, 
                               count(gl.global_id) as global_count 
                        from main_table gl 
                        inner join locations on locations.global_id = gl.global_id 
                        group by global_id"])

Then in the view:


<% @items.each do |gl| %>
        <%= gl.location_foo %> <-- select any fields you want in controller -->
        <%= gl.global_count %>
        <%= gl.global_id %>
<% end %>

If you want to keep it close to as is, I would:


def self.common_items user_ids
    items=find_by_sql(["select gl.global_id, count(gl.global_id) as global_count 
                        from main_table gl group by global_id"])

    items.map do |value|
        [value, Location.find_by_global_id(value.global_id)]
    end
end

Then in the view:

<% @common_items.each do |value,location| %>
        <%=debug(location) %> 
        global_id:<%=value.global_id %> 
<% end %>
Community
  • 1
  • 1
klochner
  • 8,077
  • 1
  • 33
  • 45
  • I would agree but am hoping that these find_by_sql are an interim sol'n. Also, will be pushing this out to memcache so not that concerned about n+1 problem (there's also a top limit of 10). Is the three deep call in the erb file a deal breaker? thx – timpone Sep 30 '11 at 17:41
  • it's not a deal breaker, but i don't see why you need to write the location back into the returned model. see edits – klochner Sep 30 '11 at 20:14