Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting up a polymorphic has_many :through relationship

rails g model Article name:string rails g model Category name:string rails g model Tag name:string taggable_id:integer taggable_type:string category_id:integer 

I have created my models as shown in the preceding code. Articles will be one of many models which can have tags. The category model will contain all categories which may be assigned. The tag model will be a polymorphic join-table which represents tagged relationships.

class Article < ActiveRecord::Base   has_many :tags, :as => :taggable   has_many :categories, :through => :taggable end  class Category < ActiveRecord::Base   has_many :tags, :as => :taggable   has_many :articles, :through => :taggable end  class Tag < ActiveRecord::Base   belongs_to :taggable, :polymorphic => true   belongs_to :category end 

I can't seem to get this to work, I can do it non polymorphic, but I must have something wrong with the polymorphic part. Any ideas?

Edit: Still not getting this right:

class Article < ActiveRecord::Base     has_many :taggables, :as => :tag     has_many :categories, :through => :taggables, :source => :tag, :source_type => "Article" end class Category < ActiveRecord::Base     has_many :taggables, :as => :tag     has_many :articles, :through => :taggables, :source => :tag, :source_type => "Article" end class Tag < ActiveRecord::Base   belongs_to :taggable, :polymorphic => true   belongs_to :category end 
like image 440
Serodis Avatar asked May 04 '11 16:05

Serodis


People also ask

What has and belongs to many or has many through?

Stories can belong to many categories. Categories can have many stories. has_many :through gives you a third model which can be used to store various other pieces of information which don't belong to either of the original models. Person can subscribe to many magazines.

What is a polymorphic relationship Rails?

Polymorphic relationship in Rails refers to a type of Active Record association. This concept is used to attach a model to another model that can be of a different type by only having to define one association.

How would you choose between Belongs_to and Has_one?

They essentially do the same thing, the only difference is what side of the relationship you are on. If a User has a Profile , then in the User class you'd have has_one :profile and in the Profile class you'd have belongs_to :user . To determine who "has" the other object, look at where the foreign key is.

How is polymorphic association set up in Rails?

In Ruby on Rails, a polymorphic association is an Active Record association that can connect a model to multiple other models. For example, we can use a single association to connect the Review model with the Event and Restaurant models, allowing us to connect a review with either an event or a restaurant.


1 Answers

To create a polymorphic has_many :through, you must first create your models. We will use'Article,' 'Category,' and 'Tag' where 'Tag' is the join-model and Article is one of many objects which can be "tagged" with a category.

First you create your 'Article' and 'Category' models. These are basic models which do not need any special attention, just yet:

rails g model Article name:string rails g model Category name:string 

Now, we will create our polymorphic join-table:

rails g model Tag taggable_id:integer taggable_type:string category_id:integer 

The join-table joins together two tables, or in our case one table to many others via polymorphic behavior. It does this by storing the ID from two separate tables. This creates a link. Our 'Category' table will always be a 'Category' so we include 'category_id.' The tables it links to vary, so we add an item 'taggable_id' which holds the id of any taggable item. Then, we use 'taggable_type' to complete the link allowing the link to know what it is linked to, such as an article.

Now, we need to set up our models:

class Article < ActiveRecord::Base   has_many :tags, :as => :taggable, :dependent => :destroy   has_many :categories, :through => :tags end class Category < ActiveRecord::Base   has_many :tags, :dependent => :destroy   has_many :articles, :through => :tags, :source => :taggable, :source_type => 'Article' end class Tag < ActiveRecord::Base   belongs_to :taggable, :polymorphic => true   belongs_to :category end 

After this, setup your database using:

rake db:migrate 

That's it! Now, you can setup your database with real data:

Category.create :name => "Food" Article.create :name => "Picking the right restaurant." Article.create :name => "The perfect cherry pie!" Article.create :name => "Foods to avoid when in a hurry!" Category.create :name => "Kitchen" Article.create :name => "The buyers guide to great refrigeration units." Article.create :name => "The best stove for your money." Category.create :name => "Beverages" Article.create :name => "How to: Make your own soda." Article.create :name => "How to: Fermenting fruit." 

Now you have a few categories and various articles. They are not categorized using tags, however. So, we will need to do that:

a = Tag.new a.taggable = Article.find_by_name("Picking the right restaurant.") a.category = Category.find_by_name("Food") a.save 

You could then repeat this for each, this will link your categories and articles. After doing this you will be able to access each article's categories and each categorie's articles:

Article.first.categories Category.first.articles 

Notes:

1)Whenever you want to delete an item that is linked by a link-model make sure to use "destroy." When you destroy a linked object, it will also destroy the link. This ensures that there are no bad or dead links. This is why we use ':dependent => :destroy'

2)When setting up our 'Article' model, which is one our 'taggable' models, it must be linked using :as. Since in the preceeding example we used 'taggable_type' and 'taggable_id' we use :as => :taggable. This helps rails know how to store the values in the database.

3)When linking categories to articles, we use: has_many :articles, :through => :tags, :source => :taggable, :source_type => 'Article' This tells the category model that it should have many :articles through :tags. The source is :taggable, for the same reason as above. The source-type is "Article" because a model will automatically set taggable_type to its own name.

like image 165
Serodis Avatar answered Sep 24 '22 12:09

Serodis