has_many :through with a foreign key?

Shpigford picture Shpigford · Apr 25, 2013 · Viewed 21.2k times · Source

I've read multiple questions about this, but have yet to find an answer that works for my situation.

I have 3 models: Apps, AppsGenres and Genres

Here are the pertinent fields from each of those:

Apps
application_id

AppsGenres
genre_id
application_id

Genres
genre_id

The key here is that I'm not using the id field from those models.

I need to associate the tables based on those application_id and genre_id fields.

Here's what I've currently got, but it's not getting me the query I need:

class Genre < ActiveRecord::Base
  has_many :apps_genres, :primary_key => :application_id, :foreign_key => :application_id
  has_many :apps, :through => :apps_genres
end

class AppsGenre < ActiveRecord::Base
  belongs_to :app, :foreign_key => :application_id
  belongs_to :genre, :foreign_key => :application_id, :primary_key => :application_id
end

class App < ActiveRecord::Base
  has_many :apps_genres, :foreign_key => :application_id, :primary_key => :application_id
  has_many :genres, :through => :apps_genres
end

For reference, here is the query I ultimately need:

@apps = Genre.find_by_genre_id(6000).apps

SELECT "apps".* FROM "apps" 
   INNER JOIN "apps_genres" 
      ON "apps"."application_id" = "apps_genres"."application_id" 
   WHERE "apps_genres"."genre_id" = 6000

Answer

Anton Grigoryev picture Anton Grigoryev · Apr 25, 2013

UPDATED Try this:

class App < ActiveRecord::Base
  has_many :apps_genres, :foreign_key => :application_id
  has_many :genres, :through => :apps_genres
end

class AppsGenre < ActiveRecord::Base
  belongs_to :genre, :foreign_key => :genre_id, :primary_key => :genre_id
  belongs_to :app, :foreign_key => :application_id, :primary_key => :application_id
end

class Genre < ActiveRecord::Base
  has_many :apps_genres, :foreign_key => :genre_id
  has_many :apps, :through => :apps_genres
end

With query:

App.find(1).genres

It generates:

SELECT `genres`.* FROM `genres` INNER JOIN `apps_genres` ON `genres`.`genre_id` = `apps_genres`.`genre_id` WHERE `apps_genres`.`application_id` = 1

And query:

Genre.find(1).apps

generates:

SELECT `apps`.* FROM `apps` INNER JOIN `apps_genres` ON `apps`.`application_id` = `apps_genres`.`application_id` WHERE `apps_genres`.`genre_id` = 1