I need to compare some Rails (2.3.11) model attribute values before and after a database update, so I start by finding my record and saving the existing attribute values in a hash, as follows:
id = params[:id]
work_effort = WorkEffort.find(id)
ancestor_rollup_fields = {
:scheduled_completion_date => work_effort.scheduled_completion_date
}
work_effort.update_attributes(params.except(:controller, :action))
#etcetera
Note I am adhering to the “best practice” of using a symbol for a hash key.
Then I have a method that takes the model and the hash to determine possible additional steps to take if the values from the hash and the model attributes don’t match. To determine this I tried to get at the model attribute value in an each loop but I was getting nil at first:
def rollup_ancestor_updates(work_effort, ancestor_rollup_fields)
ancestor_rollup_fields.each do |key, value|
model_val = work_effort.attributes[key] #nil
#etcetera
In debugging the above I noticed that hard-coding a string as a key:
work_effort.attribute['scheduled_completion_date']
Returned the desired value. So then in my each block I tried the following and it worked:
model_val = work_effort.attributes[key.to_s]
Is there a different way to do this? To me, with just 3 months Ruby/Rails experience, it’s confusing to use symbols as hash keys as is the prescribed best practice, but then have to call .to_s on the symbol to get at a model attribute. Has anybody else experienced this, worked around this, been confused by this too? Thanks in advance
The Hash returned when you call
#attributeson a AR instance has string keys, which is why a symbol as an index into the hash doesn’t work in your case. There is a subclass ofHashcalledHashWithIndifferentAccesswhich automatically converts symbol indexes into strings.Quite often in Rails you’ll encounter
HashWithIndifferentAccessinstances. A perfect example is the params variable you access in your controller and view code.Try using
work_effort.attributes.with_indifferent_access[key]Really it is just doing the same thing that you are, but it does it behind the scenes.