I have a tags model that I'd like to be polymorphic, but I don't want five records for a tag of "video" for example, I want to create the tag once and be able to use it on a variety of models. I've ready some of the questions here about doing that, but I'm not quite getting how to make it work.
So I've got:
class Tag < ActiveRecord::Base
belongs_to :tagable, :polymorphic => true
end
and
class Post < ActiveRecord::Base
has_many :tags, :through => :tag_assignments
end
and
class TagAssignment < ActiveRecord::Base
has_many :tags, :as => :taggable
end
Seems to me that should work, but... reading all the questions here I know I need a :source => option in there somewhere to tie it all together, but I'm just not following exactly how to do it. Can anyone help?
You have to redo your models as follows:
class Tag < ActiveRecord::Base
has_many :tag_assignments
end
class TagAssignment < ActiveRecord::Base
belongs_to :tagable, :polymorphic => true
belongs_to :tag
end
class Post < ActiveRecord::Base
has_many :tag_assignments, :as => :tagable
has_many :tags, :through => :tag_assignments
end
Now given a post you can get its tags as follows:
post.tags
Note
You should consider using the acts-as-taggable-on gem for your use case.
Related
I have the following models:
class Article < ActiveRecord::Base
has_many :comments, :as => :subject, :dependent => :destroy
has_many :deleted_comments, :as => :subject, :dependent => :destroy
end
class DeletedComment < ActiveRecord::Base
belongs_to :subject, :polymorphic => true
end
class Comment < ActiveRecord::Base
belongs_to :subject, :polymorphic => true
before_destroy :create_deleted_comment
def create_deleted_comment
DeletedComment.create!(....)
end
end
In my database, I have quite a few DeletedComment objects where the subject is nil. The DeletedComment (and Comment) model stores :article_id, and for the ones where the subject is nil, Article.find(deleted_comment.article_id) raises an ActiveRecord::RecordNotFound error.
Are there any cases where the :dependent => :destroy would destroy the parent record but leave the dependencies untouched?
Is it possible that in some cases when I delete an Article the deleted_comments are destroyed before comments? and when the comments are destroyed, deleted_comments are created and not destroyed (because ActiveRecord has already checked the dependent deleted_comment and tried to destroy any dependencies)?
According to official documentation:
Using polymorphic associations in combination with single table inheritance (STI) is a little tricky. In order for the associations to work as expected, ensure that you store the base model for the STI models in the type column of the polymorphic association. To continue with the asset example above, suppose there are guest posts and member posts that use the posts table for STI. In this case, there must be a type column in the posts table.
class Asset < ActiveRecord::Base
belongs_to :attachable, polymorphic: true
def attachable_type=(sType)
super(sType.to_s.classify.constantize.base_class.to_s)
end
end
class Post < ActiveRecord::Base
# because we store "Post" in attachable_type now dependent: :destroy will work
has_many :assets, as: :attachable, dependent: :destroy
end
class GuestPost < Post
end
class MemberPost < Post
end
I guess you could use examle and do something like:
class Article < ActiveRecord::Base
# for deletion only
has_many :abstract_comments, :as => :subject, :dependent => :destroy
# for 'manual' access/edition
has_many :comments, :as => :subject
has_many :deleted_comments, :as => :subject
end
class AbstractComment < ActiveRecord::Base
belongs_to :subject, :polymorphic => true
def attachable_type=(sType)
super(sType.to_s.classify.constantize.base_class.to_s)
end
end
class DeletedComment < AbstractComment
end
class Comment < AbstractComment
before_destroy :create_deleted_comment
def create_deleted_comment
DeletedComment.create!(....)
end
end
I've got a Person who can be linked to many Structures (structure is polymorphic)
I've got a Venue, who can have many People, as a structure.
I've got a Journal, who can have many People, as a structure.
Here is my modelization :
class Venue < ActiveRecord::Base
has_many :structure_people, :as => :structure
has_many :people, :through => :structure_people
end
class Journal < ActiveRecord::Base
has_many :structure_people, :as => :structure
has_many :people, :through => :structure_people
end
class Person < ActiveRecord::Base
has_many :structure_people
has_many :structures, :through => :structure_people
end
class StructurePerson < ActiveRecord::Base
belongs_to :structure, polymorphic: true
belongs_to :person
end
My problem :
when i try to get people on a Venue or on a Journal, it works. Cool :)
BUT
when i try to get structures on a person, i've got an error :
ActiveRecord::HasManyThroughAssociationPolymorphicSourceError: Cannot have a has_many :through association 'Person#structures' on the polymorphic object 'Structure#structure'.
Anyone could help me to solve this ?
Thanks a lot.
Christophe
I think it's a restriction of Rails, because has_many association will guess a class_name automatically. But polymorphic association may returns multiple class_name. Do you mind use this:
class Person < ActiveRecord::Base
has_many :structure_people
has_many :venues, :through => :structure_people
#Journal is the same.
end
class StructurePerson < ActiveRecord::Base
belongs_to :structure, polymorphic: true
belongs_to :venue, :foreign_key => 'structure_id', :conditions => {:structure_type => 'Venue'}
belongs_to :person
end
Although it is an ugly solution...
I think you can choose an alternative way.
class Person < ActiveRecord::Base
has_many :structure_people
def structures
structure_people.map(&:structure)
end
end
You can't get chaining function of has_many, but you can get polymorphic structures :)
I have a polymorphic association like so (adapted from guides.rubyonrails.com):
class Picture < ActiveRecord::Base
belongs_to :imageable, :polymorphic => true
end
class Employee < ActiveRecord::Base
has_many :pictures, :as => :imageable
end
class Product < ActiveRecord::Base
has_many :pictures, :as => :imageable
has_many :employees
end
Is there a way to get all of the possible :imageable_types only given the Picture model?
For example to get the class of has_many :quotes in the Product model, you would do:
Product.reflect_on_association(:employees).klass
to get: # => Employee
Now I want to do something similar:
Picture.reflect_on_association(:imageable).klass
This obviously throws an exception, but I want to get something like: # => [Employee, Product]
Is there a way to do this? (Without trying out all models to see if they contain has_many :pictures)
I couldn't find a way to do this without looking at all the models, so I just adapted this solution: https://stackoverflow.com/a/2315469/1440599
Models:
class Thread < ActiveRecord::Base
has_many :threaded, :through => :threaded, :foreign_key => :thread_id
class ThreadFeed < ActiveRecord::Base
belongs_to :threaded, :polymorphic => true
Model Fields
Thread (id)
ThreadFeed (id, thread_id, threaded_id, threaded_type)
Problem is with:
#thread.threaded
Rails is using (threaded_id, threaded_type) as the foreign key and I want thread_id to be the foreign key.
Take a look into this Railscast, Polymorphism
It will give you a better insight into how Polymorphism works.
First issue I notice is that it should be through :threadfeed, not :threaded
class Thread < ActiveRecord::Base
has_many :threadfeeds, :as => :threaded
In the Railscast, he has:
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => true
end
class Article < ActiveRecord::Base
has_many :comments, :as => :commentable
end
class Photo < ActiveRecord::Base
has_many :comments, :as => :commentable
#...
end
class Event < ActiveRecord::Base
has_many :comments, :as => :commentable
end
The first problem is that Thread doesn't know what feed is:
class Thread < ActiveRecord::Base
has_many :feeds, :through => :thread_feeds, :as => :feeded
has_many :thread_feeds
class ThreadFeed < ActiveRecord::Base
belongs_to :feeded, :polymorphic => true
The second problem is the complexity of polymorphic. Here's a great article on it: http://blog.hasmanythrough.com/2006/4/3/polymorphic-through
Right now I have a rich many-to-many association with VideoVote as the independent record.
class VideoVote < ActiveRecord::Base
belongs_to :user
belongs_to :video
end
class User < ActiveRecord::Base
has_many :video_votes
has_many :voted_videos,
:through => :video_votes,
:source => :video
end
class Video < ActiveRecord::Base
has_many :video_votes
has_many :voted_users,
:through => :video_votes,
:source => :user
end
However, I want to trasform this into a polymorphic association where comments can also have many VideoVotes (I realize this is confusing, so I should probably change it to Votes). (also, a video will have many comments.) How should I do this?
You first want to add voteable_id:integer and voteable_type:string to your video_votes table.
Then your models will look like:
class VideoVote < ActiveRecord::Base
belongs_to :voteable, :polymorphic => true
end
class Comment < ActiveRecord::Base
has_many :video_votes, :as => :voteable
#code
end
class Video < ActiveRecord::Base
has_many :video_votes, :as => :voteable
#code
end
Then you can access them just like any other has_many:
#video.video_votes
#comment.video_votes
#etc.