1

I have a Topic model that belongs to Category and Level.

Knowing that each Topic belongs to maximum 5-6 Level and 2-3 categories, could the category ids and the level ids of each topic be stored in 2 columns using array:true of Postgresql or is it bad practice to do so?

1 Answer 1

1

Would a has_and_belongs_to_many relationship work for you?

class Topic
  has_and_belongs_to_many :levels
  has_and_belongs_to_many :categories
end

class Category
  has_and_belongs_to_many :topics
end

class Level
  has_and_belongs_to_many :topics
end

create_table :categories_topics do |t|
  t.integer :topic_id
  t.integer :category_id
end

create_table :levels_topics do |t|
  t.integer :level_id
  t.integer :topic_id
end

This would make the structure look like:

|--------|      |--------------|
| Topics | ---> | LevelsTopics |
|--------|      |--------------|
                    ^
|--------|          |
| Levels | ---------|
|--------|


|--------|      |-------------------|
| Topics | ---> | CategoriesTopics  |
|--------|      |-------------------|
                        ^
|------------|          |
| Categories | ---------|
|------------|

This way there is a single row for each Topic, a single row for each Level and a single row for each Category. The relationship logic will be contained in a new table so everything stays DRY.

Read more about has_and_belongs_to_many

Sign up to request clarification or add additional context in comments.

5 Comments

That sounds good but the problem is when you request the topics in an index action, how do fetch the associated levels and categories without doing N+1 queries? Do you have to issue 3 different queries (Category.all, Topic.all and Level.all)?
You can use references and includes: It might look something like Topic.where(id: 1).includes(:levels).references(:levels)
To fetch a single Topic that's the way, but it is not clear not how to proceed with the Topic index method (Topic.all) to display also the categories and levels...
You would just remove the where clause: Topic.includes(:levels).references(:levels)
You actually don't need the references in those queries. Topic.includes will load everything it needs using either the preload or eager_load strategy. blog.arkency.com/2013/12/rails4-preloading

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.