# Dynamic association generation in ActiveRecord

I'm developing a Rails-based web interface/API for a large, vendor-supplied, legacy Oracle database. One of the constraints is that I can't change the schema other than adding views, because it still has to support the vendor's application.

The table for customer data has a limited number of columns, and extended attributes are stored in customer_def_field_value. These attributes are defined in customer_def_field_def.

so I end up with the classes:

class FieldDef < ActiveRecord::Base

set_table_name 'customer_def_field_def'
set_primary_key :customer_def_field_def_id
set_sequence_name 's_customer_def_field_def'

alias_attribute :field_def_id, :customer_def_field_def_id

has_many :field_values

def symbol
self.title.parameterize('_').to_sym
end
end

class FieldValue < ActiveRecord::Base

set_table_name 'customer_def_field_value'
set_primary_keys :cust_id, :customer_def_field_def_id
set_sequence_name :autogenerated

alias_attribute :field_def_id, :customer_def_field_def_id

belongs_to :customer, :foreign_key => :cust_id
belongs_to :field_def, :foreign_key => :customer_def_field_def_id
end


In order to get associations on Customer for each of the 'custom fields', I have this code in the Customer class:

FieldDef.find_each do |field|
has_one field.symbol, :class_name => 'FieldValue', :foreign_key => :cust_id, :conditions => proc{ "customer_def_field_def_id = #{field.id}"}
accepts_nested_attributes_for field.symbol
delegate :field_value, :to => field.symbol, :prefix => true
delegate :field_value=, :to => field.symbol, :prefix => true
attr_accessor ('set_' + field.symbol.to_s).to_sym
end


This works like a charm, but it queries the DB every time a Customer is instantiated in order to generate the method definitions.

It hasn't been a performance issue... yet.

New custom field types aren't added very often, so I think I might be able to do this in an initializer rather than in my model, and just restart the application if new fields have to be added... but I wanted to get some feedback. Thanks!

-

config.log_level = :debug

Thanks... I'll give this a try. I especially like the idea of using the after_save callback to avoid server restarts. – Jason Lewis Jan 16 '12 at 5:48
You're absolutely right. The query to generate the associations is only run the first time, when the class is cached. Sadly, the after_save callback won't save me from restarting periodically, as new custom fields are usually added from the vendor's application. Thanks! – Jason Lewis Jan 17 '12 at 14:16