image/svg+xml

Gaurav Koley Internet Lurker, Poet, Creator of Gratia, Actively and Pdfvuer

Multiple Associations Between 2 models in Rails

I have been working on a project as a part of Web Science Lab @ IIIT-B which is essentially an online marketplace of content. I am building this marketplace using Ruby on Rails 5 for backend and VueJS for a rich frontend.

The marketplace has Resources and Users. There are other models in the platform as well but for the sake of this post, Resources and Users are the models of interest.

Users can create some resources and consume some other resources. This entails that Users may be either Creators or Consumers or both. Likewise, the Resource can be termed as Creation or Consumable respectively. This presents a somewhat rare situation. There, now exist, 2 associations between the same 2 models.

A Resource might have multiple creators and a Creator might create multiple resources. Also, it might be obvious to notice that a Resource will have multiple Consumers and a Consumers will consumer multiple resources. This can be depicted as in this image:

User Resource Association

To achieve this, what I did was have a join model Association generated using:

→ rails g scaffold association user:belongs_to resource:belongs_to association_type:string

Here association_type helps us achieve the multiple associations. In the application, we restrict it to have only one of the two specified values: consumer or creator. This is done by:

# app/models/association.rb

class Association < ApplicationRecord
  belongs_to :user
  belongs_to :resource

  validates :association_type, presence: true, inclusion: { in: %w(consumer creator),
    message: "Association %{value} is not one of the types available."
  }
end

Now, we setup the User and Resource Models as following:

# app/models/user.rb

class User < ApplicationRecord

  has_many :associations
  has_many :creation_associations, -> {where 'association_type = "creator"'}, class_name: "Association"
  has_many :consumable_associations, -> {where 'association_type = "consumer"'}, class_name: "Association"

  has_many :creations, through: :creation_associations, source: :resource
  has_many :consumables, through: :consumable_associations, source: :resource
end
# app/models/resource.rb
class Resource < ApplicationRecord
  has_many :associations
  has_many :creators, -> {where 'association_type = "creator"'}, class_name: "User", through: :associations
  has_many :consumers, -> {where 'association_type = "consumer"'}, class_name: "User", through: :associations

end

Now, a Creator(User) can access their creations as: user.creations and a Consumer can access their consumables through user.consumables. Likewise, resources have handles:

resource.creators # For list of creators of this resource

resource.consumers # For a list of Consumers

With this setup, multiple types of associations between 2 models might be established. This setup is extendable to include other kinds of associations (maybe, maintainer or licencer etc).

Hope this helped. For any queries, ping me at my email: gaurav__at__koley__dot__in