83

In my database has column names such as 'delete' or 'listen-control' and so on. These cannot be changed, so I would like to alias the names so as to avoid problems in my application.

I found the following code but it is outdated (05 Aug 2005) and doesn't work with 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

How can I alias the column names? Is it possible?

3
  • I don't see what the problem is with using 'delete' and 'listen-control' as column names? Do you run into an error or something else? Commented Oct 25, 2010 at 13:13
  • 6
    listen-control causes problems because it has a dash in the name, which makes it an invalid ruby object attribute. Ruby will interpret "object.listen-control" as "object.listen, minus control". And delete might be a reserved keyword. I don't know why you'd want to do this. Sometimes the right answer is to stop trying to fight ruby or rails. Commented Oct 25, 2010 at 13:25
  • define_method("listen-control", Proc.new { puts "bingo" }) then send("listen-control"). Where's the problem? Commented Jan 6, 2017 at 15:40

3 Answers 3

176

Declare this in your model.

alias_attribute :new_column_name, :column_name_in_db
Sign up to request clarification or add additional context in comments.

8 Comments

would this work? alias_attribute :'new-column-name', :'column-name-in-db'
Note: Arel isn't going to pay attention to this.
p.s. this only changed the method alias, if you have code like User.where("login like ?", params[:login]), you have to change it(the login here) to the new column name yourself.
This does not work for cache_key. alias_attribute :last_modified_time, :updated_at does not generate the cache_key based on the last modified timestamp.
Update from 2017: Arel still doesn't pay attention to this.
|
13

Aliasing method names won't solve your problem. As I mentioned in my comment above, you can't have dashes in ruby method or variable names, because ruby will interpret them as a "minus". so:

object.listen-control

will be interpreted by ruby as:

object.listen - control

and will fail. The code snippet you found might be failing because of ruby 1.9, not rails 3. Ruby 1.9 doesn't let you call .send on protected or private methods anymore, like 1.8 used to.

That being said, I do understand there are times when old database column names don't look very nice, and you want to clean them up. Create a folder in your lib folder called "bellmyer". Then create a file called "create_alias.rb", and add this:

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

Now in your model that needs aliasing, you can do this:

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

And it will alias properly. It's using the read_attribute and write_attribute methods of ActiveRecord to access those table columns without calling them as ruby methods.

7 Comments

Thanks for answer, but I'm tested your solution and get error: SyntaxError (/usr/lib/ruby/gems/1.9.1/gems/activemodel-3.0.0/lib/active_model/attribute_methods.rb:229: syntax error, unexpected ',' send(:vm-password=, *args) ^): when defined: alias_attribute "vm_password", "vm-password" and try to get "vm_password".
Big thanks! I tested it and finds: 1. In user.rb needs add first line: require 'bellmyer/create_alias.rb' 2. When no one records in table, your method works fine. With one or more records rails gets error: ActionView::Template::Error (/usr/lib64/ruby/gems/1.9.1/gems/activemodel-3.0.0/lib/active_model/attribute_methods.rb:273: syntax error, unexpected '-', expecting keyword_end undef :vm-password?… 3. With field name such as 'delete' this method not works because 'delete' is method name.
You can't use the old field names in your view. In my example above, you need to use "<%= user.name_this %>". You also need to custom_alias your delete field, and give it a different name. If you alias it to "delete_field" then you can call "<%= user.delete_field %>".
I'm used new names of course. My migration: paste.pocoo.org/show/281427 My controller: paste.pocoo.org/show/281428 My model: paste.pocoo.org/show/281430 My view: paste.pocoo.org/show/281433 Error: paste.pocoo.org/show/281434 Erro for enable in migration and aliased 'delete': paste.pocoo.org/show/281439 Sorry for many pastes.
+1 for a nice solution using the '.' operator but >> you can't have dashes in ruby method or variable names Isn't completely correct. You can have methods with -'s if you escape them and use send like so object.send(:'method-with-dashes').
|
0

As Jaime said, those names might cause problems.

In that case, use some sensible names. Your GUI should never dictate how your columns are named.

Suggestions: is_deleted or deleted_at, listen_control

Then, change your view accordingly, that's way easier than fighting ActiveRecord and your database.

1 Comment

… and change main application which reads and writes in/from database with only this names?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.