Home > Back-end >  Creating the reverse of an association within a concern
Creating the reverse of an association within a concern

Time:09-26

I have a concern that creates an association:

# concerns/product.rb
module Product
  extend ActiveSupport::Concern

  included do
    has_many :products, class_name: "Product", foreign_key: :owner_id
  end
end

And an example model:

# models/user.rb
class User < ApplicationRecord
  include Product
end

If I do: User.products.last it works fine. I also want to be able to do Product.last.owner but it won't work without the association being defined. I can't define it in the Product model since I have no clue to what models will include the concern that creates the association.

I have tried creating the association using inverse_of:

class Product < ApplicationRecord
  belongs_to :owner, inverse_of: :products
end

... but it won't work, apparently it needs a class name.

I've also tried reflecting on which classes the concern gets included within but it raises some strange errors when the concern gets included into several different models.

How do I create the inverse of an association from within the concern?

CodePudding user response:

As pointed out by @engineersmnky you can't actually setup an association that points to a bunch of different classes without using polymorphism*:

# you can't have a class and a module with the same name in Ruby
# reopening the class/module will cause a TypeError
module ProductOwner
  extend ActiveSupport::Concern
  included do
    has_many :products, as: :owner
  end
end
class Product < ApplicationRecord
  belongs_to :owner, 
    inverse_of: :products,
    polymorphic: true
end
class User < ApplicationRecord
  include ProductOwner
end

The information about what you're actually joining has to be stored somewhere on the products table. If you don't use polymorphism you just have an integer (or UUID) which will always refer to a single table.

  • Related