Rails 中名称中带有标签的别名列
Aliasing Column with Hashtag in Name in Rails
我有一个遗留数据库,其中一个列的名称类似于 My#Column
,我正在尝试为其添加别名。在我的 Sequel 模型中,我有:
alias_attribute :MyColumn, :"My#Column"
但我收到语法错误:
...Ruby24-x64/lib/ruby/gems/2.4.0/gems/activesupport-5.1.4/lib/active_support/core_ext/module/aliasing.rb:26: syntax error, unexpected end-of-input, expecting keyword_end
问题似乎出在 #
。我试过像 \#
一样转义它,但我得到了同样的错误。我不明白为什么我会收到语法错误,因为这种符号在其他地方对我有用。
我该怎么做才能使这个别名起作用?
这就是 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
) 是否为"compilable",如果不是,它会适当地处理它们。
而不是 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
这应该会产生相同的结果,但不会出现语法问题。
我有一个遗留数据库,其中一个列的名称类似于 My#Column
,我正在尝试为其添加别名。在我的 Sequel 模型中,我有:
alias_attribute :MyColumn, :"My#Column"
但我收到语法错误:
...Ruby24-x64/lib/ruby/gems/2.4.0/gems/activesupport-5.1.4/lib/active_support/core_ext/module/aliasing.rb:26: syntax error, unexpected end-of-input, expecting keyword_end
问题似乎出在 #
。我试过像 \#
一样转义它,但我得到了同样的错误。我不明白为什么我会收到语法错误,因为这种符号在其他地方对我有用。
我该怎么做才能使这个别名起作用?
这就是 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
) 是否为"compilable",如果不是,它会适当地处理它们。
而不是 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
这应该会产生相同的结果,但不会出现语法问题。