【问题标题】:Aliasing Column with Hashtag in Name in RailsRails 中名称中带有井号标签的列的别名
【发布时间】:2017-12-21 13:15:15
【问题描述】:

我有一个旧数据库,其中有一列名为 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

问题似乎是#。我曾尝试像\# 一样逃避它,但我得到了同样的错误。我不明白为什么会出现语法错误,因为这种符号在其他地方也对我有用。

我该怎么做才能让这个别名起作用?

【问题讨论】:

    标签: ruby-on-rails ruby alias sequel


    【解决方案1】:

    这就是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
    

    这应该会产生相同的结果,但不会出现语法问题。

    【讨论】:

    • 感谢您抽出宝贵时间对此进行解释。我学到了一两件事。它奏效了。干杯!
    猜你喜欢
    • 2011-02-04
    • 1970-01-01
    • 2020-08-17
    • 2011-07-05
    • 2012-04-22
    • 2020-10-07
    • 2020-12-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多