覆盖rails模型中的所有默认访问器

时间:2010-11-03 11:54:25

标签: mysql ruby-on-rails ruby activerecord ruby-on-rails-3

 class Song < ActiveRecord::Base
    # Uses an integer of seconds to hold the length of the song

    def length=(minutes)
      write_attribute(:length, minutes.to_i * 60)
    end

    def length
      read_attribute(:length) / 60
    end
  end

这是rails api doc的简单示例。

是否可以覆盖模型的所有属性而不会覆盖每个属性?

2 个答案:

答案 0 :(得分:0)

你正在寻找类似的东西吗?不知道你为什么要这样做,但在这里你去:)

class Song < ActiveRecord::Base

  self.columns_hash.keys.each do |name|
    define_method :"#{name}=" do
      # set
    end

    define_method :"#{name}" do
      # get
    end

    # OR

    class_eval(<<-METHOD, __FILE__, __LINE__ + 1)
       def #{name}=
         # set
       end

       def #{name}
         # get
       end
    METHOD

  end

end

答案 1 :(得分:0)

我不确定这是一个好主意的用例。但是,所有rails模型都动态地为它们分配了属性(假设它不在类中)。答案部分在你的问题中。

您可以覆盖read_attribute()和write_attribute()方法。这会将您的转换应用于每个属性,无论它们是由访问者写入还是在控制器中批量填充。请注意不要改变像'id'属性这样的重要属性。

Ruby有一个快捷方式,可以在rails代码中使用,可以帮助您。它是%w关键字。 %w将根据括号内的符号创建一个单词数组。因为它是一个数组,你可以做这样有用的事情:

@excludes = %w(id, name)

def read_attribute name
    value = super
    if(not @excludes.member? name)
        value = value.to_i * 60
    end

    value
end

def write_attribute name, value
    if(not @excludes.member? name)
        value = value.to_i / 60
    end

    super
end

这应该让你开始。有更多高级构造,如使用lambdas等。请记住,您应该编写一些彻底的单元测试,以确保您没有任何意外的后果。您可能必须在排除列表中包含更多属性名称。

编辑:(读|写)_attributes - &gt; (读|写)_attribute