Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActiveRecord Join table for legacy Database

I have a legacy database that I'm working on getting ActiveRecord to work with. I've run into a problem with join tables. I have the following:

class TvShow < ActiveRecord::Base

  set_table_name "tvshow"
  set_primary_key "idShow"

end

class Episode < ActiveRecord::Base
  set_table_name "episode"
  set_primary_key "idEpisode"
end

And then I have a table called tvshowlinkepisode that has 2 fields: idShow, idEpisode So I have 2 tables and a join between them (so a many to many relationship), however the join uses non-standard foreign keys. My first thought was to create a model called TvShowEpisodeLink but there isn't a primary key. The idea was that since the foreign keys are non-standard I could use the set_foreign_key and have some control. Ultimately I want to say something like TvShow.find(:last).episodes or Episode.find(:last).tv_show. How do I get there?

like image 392
nixterrimus Avatar asked Jul 24 '09 20:07

nixterrimus


2 Answers

I believe you can be slightly more elegant than Alvaro's answer using options to has_and_belongs_to_many, though his answer is perfectly fine and will result in fairly identical functionality for any clients of your class.

class TvShow < ActiveRecord::Base

  set_table_name "tvshow"
  set_primary_key "idShow"
  has_and_belong_to_many :episodes, 
                         :join_table => "tvshowlinkepisode", 
                         :foreign_key => "idShow",
                         :association_foreign_key => "idEpisode"

end

class Episode < ActiveRecord::Base
  set_table_name "episode"
  set_primary_key "idEpisode"
  has_and_belongs_to_many :tv_shows,
                          :join_table => "tvshowlinkepisode",
                          :foreign_key => "idEpisode",
                          :association_foreign_key => "idShow"
end

Note that the :foreign_key option specifies which column is the id for the class on "this side" of the link, while :association_foreign_key specifies the column that is the id for the class on the "other side" of the link.

Contrast this with Alvaro's answer, this pattern should avoid instantiation of any unnecessary objects to represent the link.

like image 109
animal Avatar answered Sep 24 '22 00:09

animal


This work for you...

class TvShow < ActiveRecord::Base
  set_table_name "tvshow"
  set_primary_key "idShow"

  has_many :tv_show_link_episode, :foreign_key => 'idShow'
  has_many :episodes, :through => :tv_show_link_episode
end


class Episode < ActiveRecord::Base
  set_table_name "episode"
  set_primary_key "idEpisode"

  has_many :tv_show_link_episode, :foreign_key => 'idEpisode'
  has_many :tv_shows, :through => :tv_show_link_episode

end

class TvShowLinkEpisode  < ActiveRecord::Base
  set_table_name "tvshowlinkepisode"

    # the foreign key is named by the TvShowLinkEpisode field, 
    # the primary key name is for the primary key of the associated class
    belongs_to :tv_show, :foreign_key => 'idShow'
    belongs_to :episode, :foreign_key => 'idEpisode'
end
like image 42
Alvaro Talavera Avatar answered Sep 23 '22 00:09

Alvaro Talavera