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