ActiveRecord Rails 4

问题描述

ActiveRecord 是否有任何认读取器方法,以便每当我从数据库获取值时,都会调用此读取器方法?(Property.last.nameStudent.first.course )。我想以这种方式覆盖此方法,如果数据类型是字符串,则将其转换为大写。我不想在每个模型中为每一列添加单独的 getter。

例如:

def reader(column)
  column.upcase if column.is_a? String
end

解决方法

有一个方法 ActiveRecord::AttributeMethods::Read#read_attribute 在类型转换后返回值。所以猴子修补(或改进)这个方法可能会给你你想要的 - 所有字符串值都将被转换。

但我会认真地重新考虑这种方法:如果您不想射自己的腿,所有数据转换都应该是明确可见的。

这并不意味着您不能避免手动重新定义 getter。例如,你可以做某事。像这样(免责声明:快速而肮脏的例子):

module TransformValues
  def transform(*attributes_to_transform,transformer: nil,&block)
    attributes_to_transform.each do |attribute_name|
      define_method attribute_name do
        case transformer = (block || transformer)
        when Proc
          transformer.call(self[attribute_name])
        when Symbol
          self[attribute_name].__send__(transformer)
        else
          self[attribute_name]
        end
      end
    end
  end
end

# and then

class User < ActiveRecord::Base
  extend TransformValues
  transform :first_name,:last_name,transformer: :upcase
  transform :whatever do |val|
    do_smth_with(val)
  end
  # etc
end

在这种情况下,您的所有转换或多或少都保持明确,而无需大量手动编写的样板。如果您所需要的只是大写的字符串,那么所有这些都可以大大简化为 smth。喜欢

module UpcaseAttributes
  def always_upcase(*attributes_to_transform)
    attributes_to_transform.each do |attribute_name|
      define_method attribute_name do
        case value = self[attribute_name]
        when String
          value.upcase
        else
          value
        end
      end
    end
  end
end

class User < ActiveRecord::Base
  extend UpcaseAttributes
  always_upcase :first_name,:last_name
end