【问题标题】:Alias for column names in RailsRails 中列名的别名
【发布时间】:2010-10-25 13:10:40
【问题描述】:

在我的数据库中有列名,例如'delete'或'listen-control'等。这些不能更改,所以我想给这些名称起别名以避免在我的应用程序中出现问题。

我找到了the following code,但它已经过时(2005 年 8 月 5 日)并且不适用于 Rails 3:

module Legacy
  def self.append_features(base)
    super
    base.extend(ClassMethods)
  end
  module ClassMethods
    def alias_column(options)
      options.each do |new_name, old_name|
        self.send(:define_method, new_name) { self.send(old_name) }
        self.send(:define_method, "#{new_name}=") { |value| self.send("#{old_name}=", value) }
      end
    end
  end
end

ActiveRecord::Base.class_eval do
  include Legacy
end

如何给列名取别名?有可能吗?

【问题讨论】:

  • 我看不出使用“delete”和“listen-control”作为列名有什么问题?您是否遇到错误或其他问题?
  • listen-control 会导致问题,因为它的名称中有一个破折号,这使其成为无效的 ruby​​ 对象属性。 Ruby 会将“object.listen-control”解释为“object.listen, minus control”。并且 delete 可能是保留关键字。我不知道你为什么要这样做。有时正确的答案是停止尝试与 ruby​​ 或 rails 作斗争。
  • define_method("listen-control", Proc.new { puts "bingo" }) 然后send("listen-control")。问题出在哪里?

标签: ruby-on-rails database ruby-on-rails-3 activerecord


【解决方案1】:

在您的模型中声明这一点。

alias_attribute :new_column_name, :column_name_in_db

【讨论】:

  • 这行得通吗? alias_attribute :'new-column-name', :'column-name-in-db'
  • 注意:Arel 不会关注这个。
  • 附注这只改变了方法别名,如果你有User.where("login like ?", params[:login])这样的代码,你必须自己把它(这里的登录名)改成新的列名。
  • 这不适用于 cache_key。 alias_attribute :last_modified_time, :updated_at 不会根据最后修改的时间戳生成 cache_key。
  • 2017 年更新:Arel 还是没注意这个。
【解决方案2】:

别名方法名称不会解决您的问题。正如我在上面的评论中提到的,ruby 方法或变量名中不能有破折号,因为 ruby​​ 会将它们解释为“减号”。所以:

object.listen-control

将被 ruby​​ 解释为:

object.listen - control

并且会失败。您找到的代码 sn-p 可能因为 ruby​​ 1.9 而不是 rails 3 而失败。Ruby 1.9 不再允许您在受保护或私有方法上调用 .send,就像 1.8 过去那样。

话虽如此,我确实理解有时旧的数据库列名称看起来不太好,并且您想清理它们。在您的 lib 文件夹中创建一个名为“bellmyer”的文件夹。然后创建一个名为“create_alias.rb”的文件,并添加:

module Bellmyer
  module CreateAlias
    def self.included(base)
      base.extend CreateAliasMethods
    end

    module CreateAliasMethods
      def create_alias old_name, new_name
        define_method new_name.to_s do
          self.read_attribute old_name.to_s
        end

        define_method new_name.to_s + "=" do |value|
          self.write_attribute old_name.to_s, value
        end
      end
    end
  end
end

现在在需要别名的模型中,您可以这样做:

class User < ActiveRecord::Base
  include Bellmyer::CreateAlias
  create_alias 'name-this', 'name_this'
end

它会正确地别名。它使用 ActiveRecord 的 read_attributewrite_attribute 方法来访问这些表列,而不将它们称为 ruby​​ 方法。

【讨论】:

  • 感谢您的回答,但我已经测试了您的解决方案并收到错误:SyntaxError (/usr/lib/ruby/gems/1.9.1/gems/activemodel-3.0.0/lib/active_model/ attribute_methods.rb:229: 语法错误,意外 ',' send(:vm-password=, *args) ^): 当定义时:alias_attribute "vm_password", "vm-password" 并尝试获取 "vm_password"。跨度>
  • 非常感谢!我对其进行了测试并发现: 1. 在 user.rb 中需要添加第一行:require 'bellmyer/create_alias.rb' 2. 当表中没有任何记录时,您的方法可以正常工作。有一条或多条记录时,rails 出现错误:ActionView::Template::Error (/usr/lib64/ruby/gems/1.9.1/gems/activemodel-3.0.0/lib/active_model/attribute_methods.rb:273: 语法错误, 意外的'-', 期待keyword_end undef :vm-password?... 3. 使用'delete' 等字段名称时,此方法不起作用,因为'delete' 是方法名称。
  • 您不能在视图中使用旧的字段名称。在我上面的示例中,您需要使用“”。您还需要 custom_alias 您的删除字段,并给它一个不同的名称。如果将其别名为“delete_field”,则可以调用“”。
  • 我当然用过新名字。我的迁移:paste.pocoo.org/show/281427 我的控制器:paste.pocoo.org/show/281428 我的模型:paste.pocoo.org/show/281430 我的观点:paste.pocoo.org/show/281433 错误:paste.pocoo.org/show/281434 迁移中启用的错误和别名“删除”:paste.pocoo.org/show/281439 抱歉有很多粘贴。跨度>
  • +1 使用 '.' 获得一个不错的解决方案运算符但 >> 你不能在 ruby​​ 方法或变量名中有破折号不完全正确。如果您对它们进行转义并使用 send 像这样 object.send(:'method-with-dashes'),则可以使用带有 -'s 的方法。
【解决方案3】:

正如 Jaime 所说,这些名称可能会引起问题。

在这种情况下,请使用一些合理的名称。你的 GUI 永远不应该规定你的列是如何命名的。

建议:is_deleteddeleted_atlisten_control

然后,相应地更改您的视图,这比对抗 ActiveRecord 和您的数据库要容易得多。

【讨论】:

  • ... 并更改仅使用此名称在/从数据库中读取和写入的主应用程序?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-17
  • 1970-01-01
  • 1970-01-01
  • 2011-08-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多