Rails中列名的别名


68

在我的数据库中有列名,例如“ delete”或“ listen-control”等。这些不能更改,因此我想为名称加上别名,以避免我的应用程序出现问题。

我找到了以下代码,但是它已经过时了(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'作为列名是什么问题?您是否遇到错误或其他问题?
阿里让

5
listen-control会引起问题,因为它的名称中带有破折号,这使其成为无效的ruby对象属性。Ruby会将“ object.listen-control”解释为“ object.listen,减去控件”。并且delete可能是保留关键字。我不知道你为什么要这么做。有时正确的答案是停止尝试与红宝石或铁轨作斗争。
Jaime Bellmyer,2010年

define_method("listen-control", Proc.new { puts "bingo" })然后send("listen-control")。哪里出问题了?
rthbound

Answers:


153

在您的模型中声明。

alias_attribute :new_column_name, :column_name_in_db

1
这会工作吗? alias_attribute :'new-column-name', :'column-name-in-db'
Josiah Kiehl

9
注意:Arel将不会对此进行注意。
罗伯·霍华德

2
ps这仅更改了方法别名,如果您有类似的代码User.where("login like ?", params[:login]),则必须自己将其(此处的登录名)更改为新的列名。
沉思为申思维

2
这不适用于cache_key。alias_attribute :last_modified_time, :updated_at不会基于上次修改的时间戳生成cache_key。
Pratik Khadloya 2014年

3
2017年更新:Arel仍然没有对此进行关注。
jrg

9

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

object.listen-control

红宝石将解释为:

object.listen - control

并会失败。您发现的代码片段可能是由于ruby 1.9而不是rails 3而失败的。Ruby1.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”。
user486421

太谢谢了!我对其进行了测试,发现: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民主基金:VM-密码... 3.字段名,如“删除”这种方法并不适用,因为“删除”是方法名。
user486421

您不能在视图中使用旧的字段名称。在上面的示例中,您需要使用“ <%= user.name_this%>”。您还需要custom_alias您的删除字段,并给它一个不同的名称。如果将其别名为“ delete_field”,则可以调用“ <%= user.delete_field%>”。
Jaime Bellmyer 2010年

我当然用过新名字。我的迁移: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 为迁移启用Erro并使用别名“删除”:paste.pocoo.org/show/281439 对不起,很多粘贴。
user486421

1
+1是使用“。”的理想解决方案。运算符,但是>>您不能在ruby方法中使用破折号或变量名并非完全正确。如果您对它们进行转义,可以使用带有-的方法,并且使用send这样的object.send(:'method-with-dashes')。
死了

1

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

在这种情况下,请使用一些明智的名称。您的GUI绝对不能决定列的命名方式。

建议:is_deleteddeleted_atlisten_control

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


3
…并更改仅使用此名称在数据库中读写数据的主应用程序?
user486421
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.