Search code examples
ruby-on-railspolymorphic-associationssingle-table-inheritance

Many to many between categories and other models


Let's say we have two classes like so:

class Book < ActiveRecord::Base
end

class Magazine < ActiveRecord::Base
end

These entities can have many categories, and each category can have many books or many magazines, but not both books and magazines.

One way to deal with this is to create two separate category models, namely BookCategory and MagazineCategory, and then create a many to many relation.

I was wondering if there is a way to do this through one Category model only.

I thought about polymorphism, but it doesn't really work with many to many.

I tried STI like below, but couldn't crack it:

class Book < ActiveRecord::Base
  has_many :categorizations
  has_many :book_categories, through: :categorizations
end

class Category < ActiveRecord::Base
end

class BookCategory < Category
  has_many :categorizations
  has_many :books, through: :categorizations, source: :categorizable, source_type: "Book"
end

But this produces the following SQL, which is not correct:

SELECT "books".* FROM "books" INNER JOIN "categorizations"
ON "books"."id" = "categorizations"."categorizable_id"
WHERE "categorizations"."book_category_id" = ?
AND "categorizations"."categorizable_type" = ?  [[nil, 1], ["categorizable_type", "Book"]]

Should I just give up and do this using two separate category tables, or is there a way to do this using STI or polymorphism? And even if there is a way, would it be logical to use it?

P.S. I know there are kind of similar posts on SO, and I tried reading and understanding them. None of them really helped.


Solution

  • class Book < ActiveRecord::Base
      has_and_belongs_to_many :book_categories, join_table: :books_categories
    end
    
    class Category < ActiveRecord::Base
    end
    
    class BookCategory < Category
      has_and_belongs_to_many: books, join_table: :books_categories
    end
    

    Set the table according to has_and_belongs_to_many association