Monday, February 21, 2011

Ruby on Rails - Can I modify the value of an attribute before it is called?

Let's say I have this model named Product with a field named brand. Suppose the values of brand are stored in the format *this_is_a_brand*. Can I define a method in the model (or anywhere else) that allows me to modify the value of brand before it is called. For example, if I call @product.brand, I want to get This is a Brand, instead of *this_is_a_brand*.

From stackoverflow
  • In your model you can override the method call brand.

    def brand
    #code to modify the value that is stored in brand
    return modified_brand
    end
    

    This will allow it to be stored as this_is_a_brand. But, it will be returned as "this is a brand".

    sker : I tried that, but how do I reference the "internal" brand?
    sker : Ok, I got it. Attributes are stored in @attributes so I can just call @attributes['brand'] inside the method. Thanks for your help.
  • Rather than accessing @attributes directly, you should use read_attribute and write_attribute:

    def brand
      b = read_attribute(:brand) 
      b && b.transform_in_some_way
    end
    
    def brand=(b)
      b && b.transform_in_some_way
      write_attribute(:brand, b)
    end
    
    sker : What does the idiom b && b.transform_in_some_way mean?
    sker : And why is it better to use those methods?
    sker : Wait, I get it. Thanks for your help.
    webmat : For the other ppl not getting it: b && b.... is a common Ruby idiom. what's after the && is only executed if b is not nil. See also the andand gem for the same functionality: b.andand.transform_in_some_way
    JasonOng : Ah... nice. Great tip on using &&
  • I would recommend using the square bracket syntax ([] and []=) instead of read_attribute and write_attribute. The square bracket syntax is shorter and designed to wrap the protected read/write_attribute methods.

    def brand
      original = self[:brand]
      transform(original)
    end
    
    def brand=(b)
      self[:brand] = reverse_transform(b)
    end
    

0 comments:

Post a Comment