Search code examples
ruby-on-railsrelationships

rails relationships, 3 levels at least


How can i authentically use rails relationships in my case?

I'm making a nightlife website, just for you to know the context. It has three models, i want to join on one page: Places, Albums, Photos.

So, photos in albums work great, i use there a custom-coded sql with joins. But when i click on a place i want to see info from place model and a list of albums with a sample photo (first for example)

Now i have the following:

class Place < ActiveRecord::Base
  has_many :albums
end

class Album < ActiveRecord::Base
  has_many :photos
  has_one :place
end

class Photo < ActiveRecord::Base
  belongs_to :album
end

And there how i get it in my controller:

@place = Place.find( params[:id], :include => :albums )

and i get @place.albums as an object with albums data. But i dont know how to dig even deeper to reach thephotosmodel. And anywhay i can:include => :albumsbecause i have no direct relations betweenplaceandalbum, but i have them inalbum > photo` so sql join is needed?

That's a complicated question, but i just don`t get it fully.

Thank you for any help, maybe a good link to read!


Solution

  • First of all, the association between Place and Album isn't correct. The way you have it setup, it looks like neither would have a foreign_key. In other words, it should be Album belongs_to :place, with place_id in the albums table.

    Second of all, to get the first photo for each album:

    <% @place.albums.each do |album| %>
      Sample Photo: <%= image_tag(album.photos.first.url) %>
    <% end %>
    

    If you really wanted to, you could get the first photo from the first album of a place in one line:

    <%= image_tag(@place.albums.first.photos.first.url) %>
    

    First note that this is prone to nil errors if you don't add in conditionals, so I don't actually recommend this method. But, if you were to use it, I would just add a method to the Place model:

    def first_photo
      albums.first.photos.first
    end
    

    And in your view:

    <%= image_tag(@place.first_photo.url) %>
    

    You'll want to join this stuff together as well so you're not performing too many queries. Wizard of Ogz answer covers that.