Understanding Rails Model Associations

81 views Asked by At

I'm relatively new to Ruby on Rails and I'm trying to understand the way how active record associations work. So far, I thought I figured it out, but not sure anymore.

Anyway, I'm building my very own CMS and apart from all, I'll focus on my main problem. I'm having a table pages and pictures:

class CreatePages < ActiveRecord::Migration
  def change
    create_table :pages do |t|
      t.string :name
      t.integer :headline_image_id
      t.timestamps
    end

    create_table :pictures do |t|
      t.string   :name
      t.string   :description
      t.string   :image
      t.timestamps
    end
  end
end

With this I have my models:

class Page < ActiveRecord::Base
  validates :name, presence: true
  validates :headline_image_id, presence: true

  belongs_to :headline_image, class_name: Picture, foreign_key: :headline_image_id
end

class Picture < ActiveRecord::Base
  mount_uploader :image, ImageUploader
end

And that's it. Now after I create a picture and a page which has the id of a picture in the headline_image_id attribute, I can fetch that headline_image with @target_page.headline_image. Perfect, but the thing that is bothering me is the readability of the code. Wouldn't it make much more sense if I associated the two models in the Page model like this:

class Page < ActiveRecord::Base
  validates :name, presence: true
  validates :headline_image_id, presence: true

  has_one :headline_image, class_name: Picture, foreign_key: :headline_image_id
end

If I do it like this and run @target_page.headline_image I get a SQL Constraint exception that tells me there is no headline_image_id in the pictures table.

I read all the Active Record Association tutorial on Ruby on Rails Guides and watched all the codeschool Rails courses, and I was pretty sure that everything was going to work with a has_one association...but it didn't.

Can someone please explain? Thanks!

1

There are 1 answers

3
Bart Jedrocha On BEST ANSWER

Rails Guides provides an explanation as to why you're experiencing the problem. Essentially, when you declare a belongs_to relationship, the foreign key appears on the table for the class declaring it. When you declare a has_one relationship, the foreign key is on the table for the class in the declaration.

Example

In this scenario, the pictures table would require a page_id foreign key.

class Page < ActiveRecord::Base
  has_one :picture
end

class Picture < ActiveRecord::Base
  belongs_to :page 
end

In this scenario, the pages table would require a picture_id foreign key.

class Page < ActiveRecord::Base
  belongs_to :picture
end

class Picture < ActiveRecord::Base
  has_one :page
end

If you wanted to use a has_one association, just remove the headline_image_id column from your pages table and add a page_id column to your pictures table. You can do this in one migration. After you run the migration, change your model definitions as per my above example. Hope this helps.