这就是alias_attribute实际上在做的Source
module_eval <<-STR, __FILE__, __LINE__ + 1
def #{new_name}; self.#{old_name}; end # def subject; self.title; end
def #{new_name}?; self.#{old_name}?; end # def subject?; self.title?; end
def #{new_name}=(v); self.#{old_name} = v; end # def subject=(v); self.title = v; end
STR
所以本质上这正在变成
def MyColumn; self.My#Column; end
def MyColumn?; self.My#Column?; end
def MyColumn=(val); self.My#Column= val; end
请注意,这是在一行中,这意味着self.My 之后的所有内容都成为注释(包括end),因此您收到的错误。即使这不是rails 中的一行,ruby 也会简单地引发NoMethodError,因为My 不是一种方法,因为#Column 部分将被视为注释。
这似乎也很奇怪,因为ActiveModel#alias_attribute 有一个通过define_proxy_call 完全相同的功能实现,看起来像
def define_proxy_call(include_private, mod, name, send, *extra)
defn = if NAME_COMPILABLE_REGEXP.match?(name)
"def #{name}(*args)"
else
"define_method(:'#{name}') do |*args|"
end
extra = (extra.map!(&:inspect) << "*args").join(", ".freeze)
target = if CALL_COMPILABLE_REGEXP.match?(send)
"#{"self." unless include_private}#{send}(#{extra})"
else
"send(:'#{send}', #{extra})"
end
mod.module_eval <<-RUBY, __FILE__, __LINE__ + 1
#{defn}
#{target}
end
RUBY
end
在这里您可以看到它实际上检查新名称(name)和原始名称(send)是否“可编译”,如果不是,它会适当地处理它们。
而不是alias_attribute,它会遇到本质上是评论字符的问题。我建议使用public_send 手动实现相同的操作,例如
def MyColumn
self.public_send("My#Column")
end
def MyColumn=(val)
self.public_send("My#Column=",val)
end
def MyColumn?
self.public_send("My#Column?")
end
这应该会产生相同的结果,但不会出现语法问题。