Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rails polymorphic association (legacy database)

I am using a legacy database, so i do not have any control over the datamodel. They use a lot of polymorphic link/join-tables, like this

create table person(per_ident, name, ...)

create table person_links(per_ident, obj_name, obj_r_ident)

create table report(rep_ident, name, ...)

where obj_name is the table-name, and obj_r_ident is the identifier. So linked reports would be inserted as follows:

insert into person(1, ...)
insert into report(1, ...)
insert into report(2, ...)

insert into person_links(1, 'REPORT', 1)
insert into person_links(1, 'REPORT', 2)

And then person 1 would have 2 linked reports, 1 and 2.

I can understand possible benefits having a datamodel like this, but i mostly see one big shortcoming: using constraints is not possible to ensure data integrity. But alas, i cannot change this anymore.

But to use this in Rails, i was looking at polymorphic associations but did not find a nice way to solve this (since i cannot change the columns-names, and did not readily find a way to do that).

I did come up with a solution though. Please provide suggestions.

class Person < ActiveRecord::Base

  set_primary_key "per_ident"
  set_table_name "person"
  has_and_belongs_to_many :reports,
                         :join_table => "person_links",
                         :foreign_key => "per_ident",
                         :association_foreign_key => "obj_r_ident",
                         :conditions => "OBJ_NAME='REPORT'"
end

class Report < ActiveRecord::Base

  set_primary_key "rep_ident"
  set_table_name "report"
  has_and_belongs_to_many :persons,
                     :join_table => "person_links",
                     :foreign_key => "obj_r_ident",
                     :association_foreign_key => "per_ident",
                     :conditions => "OBJ_NAME='REPORT'"
end

This works, but i wonder if there would be a better solution, using polymorphic associations.

like image 829
nathanvda Avatar asked Dec 30 '09 13:12

nathanvda


People also ask

What is a polymorphic association in Rails?

Polymorphic relationship in Rails refers to a type of Active Record association. This concept is used to attach a model to another model that can be of a different type by only having to define one association.

How is polymorphic association set up in Rails?

The basic structure of a polymorphic association (PA)sets up 2 columns in the comment table. (This is different from a typical one-to-many association, where we'd only need one column that references the id's of the model it belongs to). For a PA, the first column we need to create is for the selected model.

What is ActiveRecord in Ruby on Rails?

1 What is Active Record? Active Record is the M in MVC - the model - which is the layer of the system responsible for representing business data and logic. Active Record facilitates the creation and use of business objects whose data requires persistent storage to a database.

What is polymorphic association Ruby?

2.9 Polymorphic Associations A slightly more advanced twist on associations is the polymorphic association. With polymorphic associations, a model can belong to more than one other model, on a single association. For example, you might have a picture model that belongs to either an employee model or a product model.


2 Answers

At least as of Rails 4.2.1, you can pass foreign_type to a belongs_to declaration to specify the name of the column to be used for the 'type' of the polymorphic association

http://apidock.com/rails/v4.2.1/ActiveRecord/Associations/ClassMethods/belongs_to

like image 177
Wei-Liang Chew Avatar answered Sep 19 '22 16:09

Wei-Liang Chew


You can override the column names, sure, but a quick scan of the Rails API didn't show me anywhere to override the polymorphic 'type' column. So, you wouldn't be able to set that to 'obj_name'.

It's ugly, but I think you'll need a HABTM for each type of object in your table.

You might be able to do something like this:

{:report => 'REPORT'}.each do |sym, text|
  has_and_belongs_to_many sym,
    :join_table => "person_links",
    :foreign_key => "obj_r_ident",
    :association_foreign_key => "per_ident",
    :conditions => "OBJ_NAME='#{text}'"
end

At least that way all the common stuff stays DRY and you can easily add more relationships.

like image 23
wesgarrison Avatar answered Sep 21 '22 16:09

wesgarrison