Reputation: 645
So, after thinking on this for a while, I have no idea what the proper way to model this is.
I have a website focused on sharing images. In order to make the users happy, I want them to be able to subscribe to many different collections of images.
So far, there's two types of collections. One is a "creator" relationship, which defines people who worked on a specific image. That looks like this:
class Image < ActiveRecord::Base
has_many :creations
has_and_belongs_to_many :locations
has_many :creators, through: :creations
end
class Creator < ActiveRecord::Base
has_many :images, ->{uniq}, through: :creations
has_many :creations
belongs_to :user
end
class Creation < ActiveRecord::Base
belongs_to :image
belongs_to :creator
end
Users may also tag an image with a subjective tag, which is something not objectively present in the image. Typical subjective tags would include "funny" or "sad," that kind of stuff. That's implemented like this:
class SubjectiveTag < ActiveRecord::Base
# Has a "name" field. The reason why the names of tags are a first-class DB model
# is so we can display how many times a given image has been tagged with a specific tag
end
class SubjectiveCollection < ActiveRecord::Base
# Basically, "User X tagged image Y with tag Z"
belongs_to :subjective_tag
belongs_to :user
has_many :images, through: :subjective_collection_member
end
class SubjectiveCollectionMember < ActiveRecord::Base
belongs_to :subjective_collection
belongs_to :image
end
I want users to be able to subscribe to both Creators and SubjectiveTags, and to display all images in those collections, sequentially, on the home page when they log in.
What is the best way to do this? Should I have a bunch of different subscription types - for example, one called SubjectiveTagSubscription
and one called CreatorSubscription
? If I do go this route, what is the most efficient way to retrieve all images in each collection?
Upvotes: 0
Views: 434
Reputation: 1995
What you want to use is a Polymorphic Association.
In your case, it would look like this:
class Subscription < ActiveRecord::Base
belongs_to :user
belongs_to :subscribeable, polymorphic: true
end
The subscriptions
table would need to include the following fields:
user_id
(integer)subscribeable_id
(integer)subscribeable_type
(string)This setup will allow a subscription to refer to an instance of any other model, as ActiveRecord will use the subscribeable_type
field to record the class name of the thing being subscribed to.
To produce a list of images for the currently logged in user, you could do this:
Subscription.where(user_id: current_user.id).map do |subscription|
subscription.subscribeable.images.all
end.flatten
If the performance implications of the above approach are intolerable (one query per subscription), you could collapse your two types of subscribeables into a single table via STI (which doesn't seem like a good idea here, as the two tables aren't very similar) or you could go back to your initial suggestion of having two different types of subscription models/tables, querying each one separately for subscriptions.
Upvotes: 1