views:

63

answers:

1

I'm trying to find all topics in a one particular category, but I'm not sure if this is the most efficient way to do it:

Topic.all.select { |topic| topic.categories.include?(category) }

The above works for me but it seems that it takes MySQL a long time to find the records. Is there anything more efficient?

+7  A: 

It sounds like right now you have a has_many relationship between topics and categories, when you need a many-to-many relationship. Restructure your models like this:

# app/models/category.rb
class Category < ActiveRecord::Base
  has_and_belongs_to_many :topics
end

# app/models/topic.rb
class Topic < ActiveRecord::Base
  has_and_belongs_to_many :categories
end

Then create a join table without a primary key. Create the new migration like so:

script/generate migration AddCategoriesTopicsJoinTable

And add these contents:

class AddCategoriesTopicsJoinTable < ActiveRecord::Migration
  def self.up
    create_table :categories_topics, :id => false do |t|
      t.integer :category_id
      t.integer :topic_id
    end
  end

  def self.down
    drop_table :categories_topics
  end
end

Notice the join table is named by combining the two table names, in alphabetical order. That's how Rails will know how to find it automatically.

Now you can call @category.topics and get an array of the topics, and you can call @topic.categories and get the categories. It works in both directions.

UPDATE: questions about many-to-many relationships in Rails have come up often enough that I wrote an article called basic many-to-many associations to explain how to use habtm vs has_many :through, and the differences between them.

Jaime Bellmyer
This is great Jaime. Thank you so much!
andy
You're welcome, I'm glad it helped :)
Jaime Bellmyer