Question

I've encountered a rather frustrating problem when trying to use has_and_belongs_to_many associations.

The scenario is as follows.

I have a product that has many news items associated and vice versa. News items can be translated to different languages, so in order to keep track of news with same content (but translated to different language) - I've added a news_id to news.

My problem is that the association is between a product and a unique news (the newsitem.news_id) and not on the single news item (newsitem.id).

My models:

class Product < ActiveRecord::Base
     has_and_belongs_to_many :newsitems , :association_foreign_key => :news_id
end

class Newsitem < ActiveRecord::Base 
     has_and_belongs_to_many :products, :foreign_key => :news_id
end

My migrations are as follows:

def change
    create_table :products do |t|
       t.string :name
       t.timestamps
    end
end

def change
   create_table :newsitems do |t|
      t.string :content
      t.integer :news_id
      t.integer :language_id
      t.timestamps
   end
end

def change
    create_table :newsitems_products, :id => false do |t|
      t.integer :news_id
      t.integer :product_id
    end
end

Using this setup I get the following correct sql generated when calling:

news = Newsitem.first
news.products.to_sql

SQL:

"SELECT `products`.* FROM `products` 
INNER JOIN `newsitems_products` 
ON `products`.`id` = newsitems_products`.`product_id` 
WHERE `newsitems_products`.`news_id` = 1"

The troubles begin when I ask for all newsitems associated with product: prod = Products.first prod.newsitems.to_sql SQL:

"SELECT `newsitems`.* FROM `newsitems` 
INNER JOIN `newsitems_products` 
ON `newsitems`.`id` = `newsitems_products`.`news_id` 
WHERE `newsitems_products`.`product_id` = 1"

Eventhough I've declared :association_foreign_key => :news_id on product and :foreign_key => :news_id on newsitem the generate "ON newsitems.id" is wrong and should be:

ON `newsitems`.`news_id` = `newsitems_products`.`news_id`

I hope some of you can crack this nut open.

Thanks in advance - Peter Piper

Was it helpful?

Solution

I had the same problem, I'll write a similar example.

1.First model:

class Label < ActiveRecord::Base
 has_and_belongs_to_many :spaces
end

2.Second model:

class Space < ActiveRecord::Base
 has_and_belongs_to_many :labels
end

3. Migration:

rails g migration createSpacesLabels
  1. Edit the migration:

    class CreateSpacesLabels < ActiveRecord::Migration
     def up
      create_table :spaces_labels, :id => false do |t|
      t.references :space
      t.references :label
     end
     add_index :spaces_labels, [:label_id, :space_id]
     add_index :spaces_labels, [:space_id, :label_id]
    end
    
    def down
     drop_table :spaces_labels
     end
    end
    
  2. Problems:

    I found that rails searches the wrong table, it looks for labelsspaces instead of spaceslabels, I guess it's because the name of the models. I solved it by adding in the models:

    has_and_belongs_to_many :labels,:join_table=>'spaces_labels'
    
    has_and_belongs_to_many :spaces,:join_table=>'spaces_labels'
    

Now, you should be able, to perform queries like @space.labels or @label.spaces. I hope it helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top