问题描述
ActiveRecord 是否有任何默认读取器方法,以便每当我从数据库中获取值时,都会调用此读取器方法?(Property.last.name 或 Student.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