I just realized one of my models has object_id as a column, and that's going to cause prolems.
Any suggestions on possible alternatives for the name object_id?
What is this column supposed to be mapping to? Is it a foreign key to an objects table?
Figure out what you're really trying to represent. It's probably not just any generic thing in the whole world. (If it is, maybe things is a better name.)
If you're working under constraints and you absolutely must have that object_id column, you could still refer to it directly with attributes[:object_id] and bypass Rails's magic methods.
As a last resort, you could overwrite the method with your own #object_id method that simply returns that attribute from your database (this is what Rails did with the #id method). I can't think of anything that would definitely break off the top of my head, but it's probably not a great idea. The object ID is used for a lot of miscellaneous things, so you may get strange behavior if you do object comparisons, use your object as a hash key, etc.
You don't need to use object_id at in your model. And there should be no column named object_id in the database.
object_id is just a default methods that all (except BasicObject in Ruby 1.9) objects have (see docs).
Returns an integer identifier for obj.
The same number will be returned on
all calls to id for a given object,
and no two active objects will share
an id.
Replaces the deprecated Object#id.
2.object_id # 5 or anything, but the same
2.id # NoMethodError: undefined method `id' for 2:Fixnum
2.object_id # 5
"anything has object_id".object_id # 22522080
"anything has object_id".object_id # 22447200 - string has different object_id because it's a new instance everytime
So, just use id to access database identifier of ActiveRecord classes. That is the one created by Ruby On Rails for model objects.
OR if you do need to have the column in the database called object_id then you can create a method on the ActiveRecord model like this:
def general_id
read_attribute(:object_id)
end
I'm kind of surprised that Rails doesn't create __object_id__ as a reference to the original form of object_id, like send has a Ruby variant called __send__.
Edit: The Ruby method __id__ appears to be the __send__ equivalent for object_id. It may be safe to use object_id as a method for your foreign key, or it may not. I don't actually use Rails in my current job.
Related
With Active Record, we can access a value like
method access
user = User.find(1)
user.name #=> 'John'
or
hash access
user[:name] #=> 'John'
I just wonder when to use which, or is there any best practice out there?
Personally I'd prefer method access because I feel that is more like ruby way. However when I see code by others, I face the hash access.
Rails convention is to use ActiveRecord::AttributeMethods::Read#read_attribute (dot notation), rather than its alias ActiveRecord::AttributeMethods#[], which:
Returns the value of the attribute identified by attr_name after it
has been typecast (for example, “2004-12-12” in a date column is cast
to a date object, like Date.new(2004, 12, 12)). It raises
ActiveModel::MissingAttributeError if the identified attribute is
missing.
I would strongly advise against using bracket notation as it breaks the inheritance hierarchy of method calls and makes refactoring harder.
If my model has an attribute name, and I decide I want to enhance the name every time someone reads it, a very idiomatic way to do that would be:
def name
"Awesome #{super}!"
end
Any place in my app that uses the method version would work fine, any place that uses the [] notation would return raw database data. I could overwrite the [] but then I would need special conditions checking for specific attributes. The whole thing would be a nightmare.
Another scenario, let's say I had an attribute that used to be stored in the database, but after a while decide that it should be computed on the fly, and end up dropping the database column. With the method version all I would need to do is add methods to my model. With the [] notation the process would be much much harder.
Also [] provides an insignificant performance improvement so though it looks like it's "closer" to the raw data it really isn't.
Within an RoR ActiveRecord class what are the pros and cons of using self[:attribute]=value as opposed to write_attribute( :attribute => value ). Is it simply a matter of style? Or is there some deeper reason to prefer one over the other?
If you look at the source on github, you can see that internally it uses the private method write_attribute_with_type_cast:
https://github.com/rails/rails/blob/8fdd4bf761b280126e52a212eed187391bdedbb3/activerecord/lib/active_record/attribute_methods/write.rb#L55
This gives you one advantage over just calling self[:attribute]=value yourself in that if you're setting id, or what you think should be id, the method will handle finding the correct attribute name of the primary key for your model.
Finally, through write_from_user, rails actually calls self[:attribute] = value for you, albeit with different names for things:
https://github.com/rails/rails/blob/8fdd4bf761b280126e52a212eed187391bdedbb3/activerecord/lib/active_record/attribute_set.rb#L38
Beyond the auto-correction of :id to :custom_primary_key if your model isn't using the standard id column as its primary key, there is no functional advantage to using write_attribute over self[:attribute]=value.
I am using Ruby on Rails 3 and I followed the Tableless models in Rails istructions in order to apply that to a my model Account.
All works, but if I do
#test = account.id
a debug of #test results in a nil value and seems not accessible at all.
In a comment of this question #Wukerplank said:
You are right. I suppose id has a special status in ActiveRecord. I think it would only be set after the record is persisted in some database.
How can I retrive\access the id attribute value?
UPDATED
Trying and re-trying I discovered that a possible solution is to make all attributes 'attr_accessible' (if I make just the 'id', I get all other value 'nil'), but I think it is a very dangerous solution.
Another solution is to create a new class attribute that acts as the id, but why I have to do that if I have already the id?!
Why don't you use ActiveModel instead? Check this screencast.
I'm confused why column values for a record cannot be accessed using #column_name. Why are they not instance variables? How is activerecord holding their value? Why is it necessary to prefix the column name with 'self.' for assignment?
Thank you for clarifying this mystery for me!
because if you mistype #f00 its a pain to figure out why your code isn't working when you meant #foo or #Foo. This way there will be a "no method error" on a typo instead of making a new variable you didn't want
Edit
I misread the question. I thought you meant about inside the ActiveRecord source when they do that. The real reason is because ActiveRecord is implemented almost entirely through reflection. It checks the database for column_names and then dynamically makes setters and getters for those fields via method_missing. If I recall correctly after you use the self.field it sets #field. This might be hidden somewhere like in #attributes[:field].
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:
1. Is there any way to make ActiveRecord/Rails use an alias or synonym for this column?
2. Is there any way in Ruby to make the object_id method behave differently, depending on who is calling it?
3. 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.
I'm just kind of spitballing here, but you might try something like this:
class Legacy < ActiveRecord::Base
#... all the other stuff
#give yourself a way to access the DB version of object_id
def oid
attributes[:object_id]
end
def oid=(val)
attributes[:object_id]=val
end
#restore ruby's default #object_id implementation
def object_id
super
end
end
Check out alias_attribute http://www.railstips.org/blog/archives/2008/06/20/alias-attribute/ I believe that it does what you are looking for.