Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails - How to use has_and_belongs_to_many association with Composite Primary Keys

I am using Dr.Nic's Composite Primary Keys for rails (http://compositekeys.rubyforge.org/)

In the examples he has has_many and belongs_to relation, but not has_and_belongs_to_many

My association works good going from books to genres (books has a composite primery key of title and author), but genre to books tries to query the column book_id which doesn't exist in the join table, and raises an error.

class Book < ActiveRecord::Base
  self.primary_keys = :title, :author
  has_and_belongs_to_many :genres, foreign_key: [:title, :author]
end

class Genre < ActiveRecord::Base
  has_and_belongs_to_many :books, foreign_key: [:title, :author]
end

Edit: I also got it to work using :association_foreign_key option on the Genre model

class Genre < ActiveRecord::Base
  has_and_belongs_to_many :books, association_foreign_key: [:title, :author]
end
like image 418
Vall3y Avatar asked Nov 30 '12 17:11

Vall3y


1 Answers

According to the Ruby on Rails Style Guide :

Prefer has_many :through to has_and_belongs_to_many. Using has_many :through allows additional attributes and validations on the join model.

This would solve your problem: You would have only has_many and belongs_to relations, no HABTM ;)

In your case:

class Book < ActiveRecord::Base
  self.primary_keys = :title, :author
  has_many :book_genre_relations
  has_many :genres, through: :book_genre_relations
end

class Genre < ActiveRecord::Base
  has_many :book_genre_relations
  has_many :books, through: :book_genre_relations
end

class BookGenreRelation < ActiveRecord::Base # Sorry but couldn't find a better name...
  belongs_to :book
  belongs_to :genre
end

You may have to change the typo for the foreign_key, I'm not familiar with Composite Primary Keys.

like image 146
MrYoshiji Avatar answered Sep 19 '22 10:09

MrYoshiji