Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails, Globalize3 check if translated attributes changed?

In Rails we can check if a model attribute is changed, using obj.field_changed?.

Say I have a model that uses Globalize3.

It has translates :name

How can I check if the name attribute got changed?

Something like obj.name_changed?

like image 292
Muntasim Avatar asked Feb 09 '23 20:02

Muntasim


1 Answers

I am not sure that the proposed answer would really give you the expected results.

Say you have

class Post < ActiveRecord::Base
  translates :name
end

If you instantiate a post:

p = Post.last

check its name:

p.name
=> "My old name"

and change the name:

p.name = "My new name"

If you do:

p.name_changed?

you will get a no method error.

If, as you propose, you call the Translation class from within the model:

class Post < ActiveRecord::Base
  translates :name
  .......
  # Open the Translation class
  class Translation
    after_save do #you may define a private method as callback method
      if name_changed?
      #accomplish your tasks...
      end
    end
  end
end

You will only be able to know if your attribute has changed after you have saved your main translatable record. This might not be what you want (imagine for example that you want to generate a new slug, based on the new name of the post each time it changes, you would then have to save your post a second time).

Instead of calling the class from within the method, you could also try (before saving your post) a:

p.translation.name_changed?
=> false

The result will be a false. This can be explained. If, after having changed the name with a:

p.name = "My new name"
=> "My new name"

p.translation.name will return:

p.translation.name
=> "My old name"

This is because Globalize stores the translated attributes in virtual attributes of the instantiated translatable model.

You could do:

p.translation.name = "My new name"
=> "My new name"

then:

p.translation.name_changed?
=> true

However, you lose part of the benefit of using Globalize.

What I do is that, in the Post model, I override the getter and setter for the virtual attribute I am interested in:

def name
  translation.name
end

def name=(val)
  translation.name = val
end

Now, if I do:

p.name
=> "My old name"
p.name = "My new name"
=> "My new name"
p.name_changed?
# no method error
p.translation.name_changed?
=> true
p.translation.name
=> "My new name"

and this, before saving the post.

like image 155
Freddo Avatar answered Feb 16 '23 12:02

Freddo