ActiveRecord aliases 'id' to primary key

I have a legacy table with three fields: NAME, VALUE, ID. Naturally, the primary key is NAME and not ID. The problem is that ActiveRecord updates the NAME primary key when I try to set ID: object.id=1 will update the NAME attribute and not the ID attribute. I can only update the ID attribute via WRITE_ATTRIBUTE (see IRB example below).

I can work around this issue, but it breaks FactoryGirl (and presumably others). Any thoughts on workarounds or if I'm doing something wrong? Thanks!

Pete

Can you create a view in the legacy database to remap the field names? If so, then your ActiveRecord model can just point to the view and save you a lot of headaches.

Can you change the field names in the table or do you have a legacy app to go with the legacy table that needs to keep working?

Colin

Its a good suggestion but sadly the answer is no. There is another app that also accesses this data and so I *probably* can't change it.

Is this behavior expected or not? It was a bit of a surprise to me.

E. Litwin wrote in post #967734:

Pete Campbell wrote in post #967747:

Its a good suggestion but sadly the answer is no. There is another app that also accesses this data and so I *probably* can't change it.

Is this behavior expected or not? It was a bit of a surprise to me.

A little unexpected... but the source makes it obvious what is happening.

module ActiveRecord   module AttributeMethods     module Write

      blah blah blah

      def write_attribute(attr_name, value)         attr_name = attr_name.to_s         attr_name = self.class.primary_key if attr_name == 'id'

Seems like it ought to check and see if   set_primary_key = something other than "id" is set in the model and behave accordingly (if "id" is not the model's primary key, then don't remap attr_name to self.class.primary_key).

Of course, I've just looked at this one small snippet of code, and there may be other places in the AR code base that use 'id' as a name alias for the primary key (whatever it is), so removing that bit of redirection might totally hose up AR.

Just a very kludgy though on this Friday afternoon, but could you use 'iD' as your attribute?

The database adapter probably isn't too kind, but you might just have to define your own:

def iD    read_attribute('iD') end

def iD=(value)    write_attribute('iD', value) end

-Rob

(Hey, I said that it was a kludge! Oh, and it's also completely untested.)

Rob Biedenharn Rob@AgileConsultingLLC.com http://AgileConsultingLLC.com/ rab@GaslightSoftware.com http://GaslightSoftware.com/

[Please post responses below, not above, i.e. no top posting]

My suggestion to create a view would not affect other applications. The whole point of the view is to create an abstraction for your application without a side effect. So I will ask again, can you create a view in your legacy database?

Ar Chron wrote in post #967748:

module ActiveRecord   module AttributeMethods     module Write

      blah blah blah

      def write_attribute(attr_name, value)         attr_name = attr_name.to_s         attr_name = self.class.primary_key if attr_name == 'id'

Thanks for the dope-slap that I should have looked in the code itself. I should also have mentioned that this is using Rails 2.3.5. Turns out that object.id is always going to point to the primary key.

module ActiveRecord   class Base       # Sets the primary ID.       def id=(value)         write_attribute(self.class.primary_key, value)       end

(not sure if I showed the hierarchy to the function correctly)

E. Litwin wrote in post #967757:

My suggestion to create a view would not affect other applications. The whole point of the view is to create an abstraction for your application without a side effect. So I will ask again, can you create a view in your legacy database?

Thanks for clarifying, I didn't realize the distinction when I read your message the first time. I don't know the answer but it certainly seems like it should work.

Thanks to everyone for your help, very good ideas and very informative. Much appreciated!

Pete