Trying to get has_many :through working with legacy tables

My first significant Rails app needs to integrate with a legacy
database and I'm having trouble getting my has_many :through
relationship working. (I've tried a number of permutations to what I
describe below and I've searched through this group's archives and
Googled for clues, but I haven't figured out what I'm doing wrong.)

The legacy tables don't follow RoR conventions, so I'm specifying table
names, primary keys and sequence names explicitly (running on Oracle)
and turning off pluralization of table names--that part seems to work.
(I can Model#find individual records in the tables.)

Since all of the legacy tables don't pluralize table names, I
sub-classed ActiveRecord::Base like this:

class MyActiveRecord < ActiveRecord::Base
  self.pluralize_table_names = false
end

Each of my models inherit from the MyActiveRecord. Here they are:

class PubPlacement < MyActiveRecord
  set_table_name "pub_placement"
  set_primary_key "placement_id"
  set_sequence_name "pub_placement_seq"

  has_many :pub_placement_assocs
  has_many :pub_presets, :through => :pub_placement_assocs, :source =>
:preset_id
end

class PubPreset < MyActiveRecord
  set_table_name "pub_preset"
  set_primary_key "preset_id"
  set_sequence_name "domain_preset_seq"

  has_many :pub_placement_assocs
  has_many :pub_placements, :through => :pub_placement_assocs, :source
=> :placement_id
end

class PubPlacementAssoc < MyActiveRecord
  set_table_name "pub_placement_assoc"
  set_primary_key "assoc_id"
  set_sequence_name "pub_placement_assoc_seq"

  belongs_to :pub_placement, :foreign_key => "placement_id"
  belongs_to :pub_preset, :foreign_key => "preset_id"
end

In script/console, I can find individual records from each of these
tables successfully. However, when I try something like this (return
values filtered):

p = PubPlacement.find 64

  <legit pub_placement object>

p.pub_presets

I get this result:

ActiveRecord::HasManyThroughSourceAssociationNotFoundError: Could not
find the source association(s) :preset_id in model
PubPlacementAssoc. Try 'has_many :pub_presets, :through =>
:pub_placement_assocs, :source => <name>'. Is it one of :stuck_out_tongue:
ub_placement or :pub_preset?
        from
./script/../config/../config/../vendor/rails/activerecord/lib/active_record/reflection.rb:173:in
`check_val
idity!'
        from
./script/../config/../config/../vendor/rails/activerecord/lib/active_record/associations/has_many_through_a
ssociation.rb:6:in `initialize'
        from
./script/../config/../config/../vendor/rails/activerecord/lib/active_record/associations.rb:920:in
`pub_pre
sets'
        from (irb):2

I've been staring this in the face for a while and don't know what to
try next.

Thanks in advance.

Ed

Hi Ed,

I haven't worked through your exact situation, but my current guess is
that you need some

  :class_name => "PubPreset"

or the like in your associations here and there... (or not, but
probably worth trying.. :slight_smile:

Best,

-r

I poked around a bit more and figured out that I made several mistakes
in my models. Here's a simplification of the has_many :through models
that work (the sequence stuff is irrelevant):

class PubPlacement < MyActiveRecord
  set_table_name "pub_placement"
  set_primary_key "placement_id"

  has_many :pub_placement_assocs, :foreign_key => :placement_id
  has_many :pub_presets, :through => :pub_placement_assocs
end

class PubPreset < MyActiveRecord
  set_table_name "pub_preset"
  set_primary_key "preset_id"

  has_many :pub_placement_assocs, :foreign_key => :preset_id
  has_many :pub_placements, :through => :pub_placement_assocs

class PubPlacementAssoc < MyActiveRecord
  set_table_name "pub_placement_assoc"
  set_primary_key "assoc_id"

  belongs_to :pub_placement, :foreign_key => :placement_id
  belongs_to :pub_preset, :foreign_key => :preset_id
end

I learned:

- belongs_to and has_many require :foreign_key to be specified if Rails
naming conventions for the foreign keys aren't followed
- the :source parameter for has_many :through relationships specifies
the name of an association in the join table (not a foreign key name),
and you don't need it if the association name follows Rails naming
conventions (e.g., "has_many :pub_placements, :through =>
:pub_placement_assocs" doesn't need the :source parameter if the
association in the join table is named ":pub_placement" or
":pub_placements")

Thanks!