Jim Jones
Jim Jones

Reputation: 2837

How to model multi-blog site?

I've got these tables:

**Sites**
:has_many :blogs
:has_many :pages

**Blogs**
:belongs_to :site

**Pages**
:belongs_to :site
:belongs_to :blog

Basically, I want to be able to create Pages that are either related to a Site OR related to a Blog with routes like this:

/blogs/1/pages/1
/sites/1/pages/2 

With my current setup, my Pages table has a foreign_key for blog_id AND site_id - and I was just thinking of doing this:

Then if I want a list of Site pages: I can just query the Pages table for all NULL blog_ids, and if I want Blog pages, I'll get them through the relationship with Blog already.

UPDATE: I accepted the answer below which suggested using "polymorphic associations", but could this also be done using Single Table Inheritance? If so, which method is better?

Thanks.

Upvotes: 2

Views: 427

Answers (2)

Matt Darby
Matt Darby

Reputation: 6324

You should look into Polymorphic assocations: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

Basically, you're on the right track, but there is an existing pattern for what you're trying to do.

Upvotes: 1

molf
molf

Reputation: 75025

You can use polymorphic associations.

Add a foreign key and a type column to your pages table. Find an adjective that describes the common property of the classes that your pages can belong to. I came up with pageable (which gives me a pageable_id and pageable_type column). If you use migrations, add the following your Page migration:

# Adds "pageable_id" integer column and "pageable_type" string column.
t.references(:pageable, :polymorphic => true)

In your models, specify the polymorphic relationship when using has_many/belongs_to:

class Site < ActiveRecord::Base
  has_many :pages, :as => :pageable
end

class Blog < ActiveRecord::Base
  has_many :pages, :as => :pageable
end

class Page < ActiveRecord::Base
  belongs_to :pageable, :polymorphic => true
end

And behold:

# Return all pages belonging to Site with ID 12, that is, return all pages
# with pageable_id 12 and pageable_type "site".
Site.find(12).pages

# Return all pages belonging to Blog with ID 3, that is, return all pages
# with pageable_id 3 and pageable_type "blog".
Blog.find(3).pages

# Returns the owner (Blog or Site) of Page with ID 27.
Page.find(27).pageable

I hope this helps.

Upvotes: 5

Related Questions