Search code examples
ruby-on-railsrails-activerecordjoinsingle-table-inheritance

Has_and_belongs_to_many and Single Table Inheritance


I need some help. I feel very silly trying to get this to work but really I can't figure it out so.

I need to make a join table between a submodel and another model.

1) I got a User Model that can be subclassed to follow my permissions scheme:

class User < ActiveRecord::Base

  # so we can use Single Table inheritance with each role for the platform
  self.inheritance_column = :role

end

2) I got an Rp submodel that subclasses User with role = "Rp" and I relate this to the Venue model:

class Rp < User
  has_and_belongs_to_many :venues
end

3) I got a Venue model, and I relate this to the Rp model:

class Venue < ActiveRecord::Base
  has_and_belongs_to_many :rps
end

4) I got the join table in order and migrated:

class CreateJoinTableVenueRp < ActiveRecord::Migration
  def change
    create_join_table :Venues, :Rps do |t|
      t.index [:venue_id, :rp_id]
      t.index [:rp_id, :venue_id]
    end
  end
end

This gives me an Rps_Venues join table in the database. All is good:

enter image description here

However, I'd expect to be able to do

Venue.first.rps

and

Rp.first.venues

But when I do this, somehow Active Records goes bananers and doesn't grab the proper join table, instead trying to match venues to the Rp superclass, User:

Loading development environment (Rails 4.2.5.1)
[1] pry(main)> Venue.first.rps
  Venue Load (0.9ms)  SELECT  "venues".* FROM "venues"  ORDER BY "venues"."id" ASC LIMIT 1
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR:  **relation "users_venues" does not exist**
LINE 5:                WHERE a.attrelid = '"users_venues"'::regclass
                                          ^
:               SELECT a.attname, format_type(a.atttypid, a.atttypmod),
                     pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
                FROM pg_attribute a LEFT JOIN pg_attrdef d
                  ON a.attrelid = d.adrelid AND a.attnum = d.adnum
               WHERE a.attrelid = '"users_venues"'::regclass
                 AND a.attnum > 0 AND NOT a.attisdropped
               ORDER BY a.attnum
from /home/null/.rvm/gems/ruby-2.2.3/gems/activerecord-4.2.5.1/lib/active_record/connection_adapters/postgresql_adapter.rb:592:in `async_exec'
[2] pry(main)> Rp.first.venues
  Rp Load (1.4ms)  SELECT  "users".* FROM "users" WHERE "users"."role" IN ('Rp')  ORDER BY "users"."id" ASC LIMIT 1
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR:  **relation "users_venues" does not exist**
LINE 5:                WHERE a.attrelid = '"users_venues"'::regclass
                                          ^
:               SELECT a.attname, format_type(a.atttypid, a.atttypmod),
                     pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
                FROM pg_attribute a LEFT JOIN pg_attrdef d
                  ON a.attrelid = d.adrelid AND a.attnum = d.adnum
               WHERE a.attrelid = '"users_venues"'::regclass
                 AND a.attnum > 0 AND NOT a.attisdropped
               ORDER BY a.attnum
from /home/null/.rvm/gems/ruby-2.2.3/gems/activerecord-4.2.5.1/lib/active_record/connection_adapters/postgresql_adapter.rb:592:in `async_exec'

Can anyone help out a bit?


Solution

  • Aaaaaand here we go, I knew I was close:

    Just specify a :join_table like this:

    class Rp < User
      has_and_belongs_to_many :venues, join_table: "Rps_Venues"
    end
    
    class Venue < ActiveRecord::Base
      has_and_belongs_to_many :rps, join_table: "Rps_Venues"
    end
    

    Everything works now.