Ignore a column when using `.changed?` in rails - ruby-on-rails

I want to use the .changed? method to check if a record has changed. The problem is that one of the fields will always be different. I would like to ignore the field. Something like:
record.changed?.except(:field_to_ignore)
How can I solve this?

ActiveModel::Dirty gives you a list of all the attributes that have changed via the changed method. So you could do something like
record.changed.reject { |attr| attr == 'field_to_ignore' }.size > 0
Read more about changed method here

EDITED
A simple solution to this is to use the same changed? functionality from ActiveModel::Dirty, so let's say that the attribute you don't want to take into account is x, with that said you can do something like this:
atttibutes_changed = record.changed_attributes.keys
atttibutes_changed.size > 1 || !atttibutes_changed.include?('x')
The above condition means: if more than one attribute changed or in case one changed need to be different from x. changed_attributes returns a hash with all the attributes that changed and his values (before change).

Related

Fake a change for ActiveModel dirty or mimic 'touching' a column?

I can't think of a better way to title this Sorry!
Ultimately I have a callback that 99% of the time I only want to run when a particular list of attributes get changed. But in a couple of cases I'd love to be able to by pass my return unless previous_changes & watched_attributes.
Is there any way to mock a change to a particular attribute? Somehow set model.attribute_changed? to true?
I've been using model.touch but updated_at is a column I deliberately want to ignore.
Yes, you can check whether your attribute is changed or not by using following command
#object.column_changed? #=> true
You can get an array of changed attributes by using changed method
#object.changed #=> ['column_name']
You can try something like the following:
object.attribute_name_will_change!
object.changed << :attribute_name
puts object.attribute_name_changed?
puts object.changed?
resulting output is:
true
true
attribute_name is to be replaced with the name of your attribute.

postgres update the value of hstore with old partial value, in rails

I've been trying to update the wrong migrated values of the hash store,
"area_unit"=>NULL, "building_type"=>"{:building_type=>\"apartment\"}",
to
"area_unit"=>NULL, "building_type"=>"apartment"}",
the value should stay the same, I don't want to use regular expression. is there an easy way for doing that ? I'm working with ruby.
I was able to do it like the following, not a generic solution like I wanted, but it works.
SELECT id, properties::hstore ->'building_type' FROM stops WHERE (properties->'building_type' like '{:building_type=>\"apartment\"}');
UPDATE stops SET properties = properties || '"building_type"=>"apartment"'::hstore
WHERE (properties->'building_type' like '{:building_type=>\"apartment\"}');

Finding records where one attribute is greater than another

I want to find any product that has a higher ip_solid than ip_liquid.
I am trying to do the following:
Product.where("ip_solid > ?", :ip_liquid).count
However, it seems that :ip_liquid is not being read out from each object, and is probably evaluating to 0 or nil. Is something like this even possible?
Product.where("ip_solid > ip_liquid").count should do it as long as ip_liquid is a field in the database and not a method on your model

Fill in unfilled properties with other model

I have an ActiveRecord model #new_profile that has some, but not all of its properties filled in. I have another model #default_profile that has a bunch of values I want to copy over, but only if the properties from the first are not filled in. Is there a built in way to do this besides a block like...
#new_profile.name ||= #default_profile.name
#new_profile.address ||= #default_profile.address
# etc.
This might work
#new_profile.update_attributes!(#default_profile.attributes.merge(#new_profile.attributes))
The problem with this, is that if the attribute is in #new_profile, but it is nil, the merge might leave the value set as nil. You might need to do the following.
new_profile_attrs = #new_profile.attributes.reject{ |key,value| !value }
#new_profile.update_attributes!(#default_profile.attributes.merge(new_profile_attrs))
#new_profile.update_attributes(#default_profile.attributes.merge(#new_profile.attributes))
You could try something like
#new_profile.attributes = #new_profile.attributes.reverse_merge #default_profile.attributes
If you need to copy ALL the attributes (except id of course):
#new_profile.attributes.each{|k,v| #new_profile[k] ||= #default_profile[k] if k != 'id'}
Things like update_attributes won't allow you to copy attr_protected-attributes. This thing should.

Track changes when updating a record

How do I check if the data is changed when I edit a record?
So before update
game.player=1
after update / edit
game.player=2
for example
how to track changes (check if changed) and do something in ruby on rails, when the data is changed.
Have a look at ActiveModel::Dirty
You can check if a model has been changed by doing:
game.changed?
Or an individual field like:
game.player_changed?
Both return a boolean value.
All changes are also kept in a hash. This comes in handy if you want to use the values.
game.changes #=> {:player => [1,2]}

Resources