ruby-on-railspolymorphic-associationssurrogate-key

Avoiding Polymorphic Associations in Rails


(sorry for any bad English)

Let's suppose I have models A, B, C. Each model have one address.

In the book "SQL Antipatterns: Avoiding the Pitfalls of Database Programming" (chapter 7 - Polymorphic Associations) there is a recipe to avoid such associations through the use of a "common super table" (also called base table or ancestor table).

Polymorphically, it would be:

table addresses:
    id: integer
    parent_type:string  # 'A', 'B' or 'C'
    parent_id: integer

I know you can use intersection tables, but the following solution looks more polished:

Instead of polymorphically associating A, B, C with Address, the recipe suggests to create a super table (Addressing) that have only a id field (surrogate key or pseudo key). Then, the other tables references Addressing. That way, says the author, "you can rely on the enforcement of your database’s data integrity by foreign keys". So, it would be:

table addressing
    id: integer
table addresses
    id: integer
    addressing_id: integer  (foreign_key)
    zip: string
table a
    id: integer
    addressing_id: integer  (foreign_key)
    name: string
table b
    id: integer
    addressing_id: integer  (foreign_key)
    name: string
table c
    id: integer
    addressing_id: integer  (foreign_key)
    name: string

The SQL query would be like this:

SELECT * from a
  JOIN address USING addressing_id
  WHERE a.addressing_id = 1243 

The QUESTION is: how to code such scenario in Rails ? I've tried in several ways without success.


Solution

  • Do objects A, B and C each have a single address? Or many addresses? From your comment below it looks like each object has one address.

    If every object has just one address you can simply put a foreign key in the A/B/C objects with the address ID. Let the House or Office objects have one address:

    class House < ActiveRecord::Base
      belongs_to :address
    end
    
    class Office < ActiveRecord::Base
      belongs_to :address
    end
    

    Your offices and houses DB tables need to have a foreign key address_id. This way you can access an object's address with something like house.address or office.address.

    If these objects could have many addresses, the solution depends on the A/B/C objects. If they are related you could use Single Table Inheritance - Rails supports this pattern well - but without more information it's difficult to say which is the best approach.