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)
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...
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.
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.
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.
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 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.
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.