I’m writing a Rails application against a legacy database. One of the
tables
in this legacy database has a column named object_id. Unfortunately
object_id is also an attribute of every object in Ruby, so when
ActiveRecord
is trying to use these objects to formulate a query it is using the Ruby
defined object_id, rather than the value that is in the database.
The legacy application is immense at well over a million lines of code,
so
simply changing the name of the column in the database would be an
option of
last resort.
Questions:
- Is there any way to make ActiveRecord/Rails use an alias or synonym
for
this column? (i.e. such that in my app I can access the value using the
alias, but when AR generates SQL it uses the actual column name)
- Is there any way in Ruby to make the object_id method behave
differently,
depending on who is calling it? (i.e. use database object_id when being
called by activerecord, otherwise return ruby object_id)
- Can I simply override the behavior of the object_id method in my
model (I
assume this is a terrible idea, but had to ask)
Any suggestions are greatly appreciated.
On Dec 3, 2010, at 12:22 PM, Mike B wrote:
I’m writing a Rails application against a legacy database. One of the tables in
this legacy database has a column named object_id. Unfortunately object_id is also
an attribute of every object in Ruby, so when ActiveRecord is trying to use these
objects to formulate a query it is using the Ruby defined object_id, rather than
the value that is in the database.
The legacy application is immense at well over a million lines of code, so
simply changing the name of the column in the database would be an option of last
resort.
Questions:
- Is there any way to make ActiveRecord/Rails use an alias or synonym for this
column? (i.e. such that in my app I can access the value using the alias, but when
AR generates SQL it uses the actual column name)
- Is there any way in Ruby to make the object_id method behave differently,
depending on who is calling it? (i.e. use database object_id when being called by
activerecord, otherwise return ruby object_id)
- Can I simply override the behavior of the object_id method in my model (I
assume this is a terrible idea, but had to ask)
Any suggestions are greatly appreciated.
Ouch. I don’t have a definitive answer, but you maybe able to get away
defining the following methods in your model…
def newobjid
read_attribute(:object_id)
end
def newobjid=(val)
write_atrribute(:object_id, val)
end
There may even be a short cut to the above… definitely take a look at
the source of read_attribute/write_attribute to see what they are doing
and figure out where the short comings in the above are…
-philip
Hi Mike,
Having a db table column named object_id is going to be a problem for
any ruby-based app, given object_id’s significance as an object
attribute in ruby (http://www.ruby-doc.org/core/classes/
Object.html#M000339).
If your rails app only needs to read from (and not write to) that
legacy table, … I’d create a view in the db which includes all the
columns in that table but with that object_id column renamed to
something like ob_id, and then read from that view instead of the
table in your rails app.
If your rails app needs to write to that table, and your rails app and
the legacy app are the only two apps that use that legacy db, and you
are able to modify that legacy app, … I’d change that column name
in the db to something like ob_id, then I’d search for ($ grep -Erni
“object_id” /path/to/proj/root ) and replace all specific references
to that specific column in the legacy code.
Jeff
Thanks for all the replies.
Let me ask you this:
If I do set up a view to rename the columns, can I override the create
and update method in ActiveRecord::Base to make it insert into the
original table (rather than the view)? Having looked at
ActiveRecord::Base a little bit it would seem that I can do this
without any ill effects.
Thanks,
Mike
On Dec 5, 8:26am, Mike B [email protected] wrote:
Let me ask you this:
If I do set up a view to rename the columns, can I override the create
and update method in ActiveRecord::Base to make it insert into the
original table (rather than the view)? Having looked at
ActiveRecord::Base a little bit it would seem that I can do this
without any ill effects.
Why can’t you just insert/update the view? As long as the view isn’t
joining any other tables, you can treat it as a regular table (AFAIK
in MySQL, SQL Server, PostgreSQL).
I would like to be able to support mssql, postgres, oracle, and
sqlite3. My understanding is that updateable views wouldn’t work for
sqlite3, but I’ll have to do a bit more research.
Thanks for your suggestion.
Marnen Laibow-Koser wrote in post #966357:
Mike B wrote in post #966322:
I would like to be able to support mssql, postgres, oracle, and
sqlite3. My understanding is that updateable views wouldn’t work for
sqlite3, but I’ll have to do a bit more research.
Unless I’m badly mistaken, you should just need to use alias_attribute.
No DB view is necessary.
…or not. I looked at the source of alias_attribute, and I’m not sure
if it will work. But do try it before messing with DB views.
Thanks for your suggestion.
Best,
Marnen Laibow-Koser
http://www.marnen.org
[email protected]
Sent from my iPhone
Mike B wrote in post #966322:
I would like to be able to support mssql, postgres, oracle, and
sqlite3. My understanding is that updateable views wouldn’t work for
sqlite3, but I’ll have to do a bit more research.
Unless I’m badly mistaken, you should just need to use alias_attribute.
No DB view is necessary.
Thanks for your suggestion.
Best,
Marnen Laibow-Koser
http://www.marnen.org
[email protected]
Sent from my iPhone
Mike B wrote in post #966542:
Thanks for the suggestion.
Please quote when replying – I have no idea whom you’re thanking for
what suggestion.
Gave it a try but it appears that support
for aliased columns does not run very deep in ActiveRecord.
For example, if you alias obj_id to object_id and then try to do:
Object.find_by_obj_id(3) it complains that the method is unknown.
But find_by_object_id should work.
I did a bit of digging on sqlite3 updateable views and it appears that
this can be accomplished by writing some triggers. Same applies for
postgres and others as well.
Barring an absolutely brilliant suggestion I’m going to pursue this
solution.
Please don’t do that yet. Spend some more time with aliased attributes
– you shouldn’t need to write a view for something this simple. If it
were my DB, I’d either use alias_attribute or something like Philip’s
solution. There should be no need for views here.
Actually, I’d probably change the name of the field. The legacy
application shouldn’t be a concern: no two applications should directly
touch the same DB anyway IMHO. Another good idea might be to have the
legacy application expose a REST service (with any field names you
like!) that the Rails application can interact with by using
ActiveResource (this is sort of what we’ve done here at my job).
If you do need DB views, try the rails_sql_views plugin.
Thanks to all,
Mike
Best,
Marnen Laibow-Koser
http://www.marnen.org
[email protected]
On Dec 3, 3:22pm, Mike B [email protected] wrote:
Questions:
- Is there any way to make ActiveRecord/Rails use an alias or synonym for
this column? (i.e. such that in my app I can access the value using the
alias, but when AR generates SQL it uses the actual column name)
- Is there any way in Ruby to make the object_id method behave differently,
depending on who is calling it? (i.e. use database object_id when being
called by activerecord, otherwise return ruby object_id)
- Can I simply override the behavior of the object_id method in my model (I
assume this is a terrible idea, but had to ask)
Any suggestions are greatly appreciated.
If you are using ActiveRecord 3, try using safe_attributes gem I
released recently. It will probably resolve your issue. If not, let
me know.
https://rubygems.org/gems/safe_attributes
Brian
Thanks for the suggestion. Gave it a try but it appears that support
for aliased columns does not run very deep in ActiveRecord.
For example, if you alias obj_id to object_id and then try to do:
Object.find_by_obj_id(3) it complains that the method is unknown.
I did a bit of digging on sqlite3 updateable views and it appears that
this can be accomplished by writing some triggers. Same applies for
postgres and others as well.
Barring an absolutely brilliant suggestion I’m going to pursue this
solution.
Thanks to all,
Mike