0

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.

hattenn
  • 4,371
  • 9
  • 41
  • 80
  • Can you include your `Categiorization` model as well? The `source: categorizable` makes me think you're using STI in that table, though your post doesn't mention it. – Lanny Bose Oct 28 '15 at 21:58
  • What you want will require some complex validations (and database constraints if you really want to have reliable data). In my opinion it would be easier to have separate category types (BookCategory and MagazineCategory). This is similar to what my team has done in several cases and we have not regretted it. – Wizard of Ogz Oct 28 '15 at 22:18

1 Answers1

2
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

wesley6j
  • 1,393
  • 9
  • 17
  • Thanks, but I wanted to find out if there was a logical and efficient way to do this using only one table. I'm aware of many to many. – hattenn Oct 29 '15 at 05:43
  • @hattenn This is a one table solution with STI. Create `categories` table with a string cloumn `type`. – wesley6j Oct 29 '15 at 09:48
  • I don't see how I can create the join table using this method (other than creating separate join tables for each type of category). – hattenn Oct 29 '15 at 09:57
  • @hattenn To use a single join table, use [polymorphic join table](http://aaronvb.com/articles/a-polymorphic-join-table.html) – wesley6j Oct 29 '15 at 10:52
  • This seemed to work at first, but there are issues. I'm still choosing this as the answer for the direction it provided. – hattenn Oct 29 '15 at 12:17