如何在Rails中重命名与表名同名的变量?
问题描述
我想重命名代码库中一个和Rails表名同名的变量,我知道列重命名可以用alias_attribute,有没有类似方法来重命名这个和表名同名的变量?
附schema.rb内容
ActiveRecord::Schema.define(version: 2015_05_19_181601) do create_table "todos", force: :cascade do |t| t.string "title" t.boolean "is_completed", default: false t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "session_user_id" end end
相关代码示例
class Content < ActiveRecord::Base # 有一个todos属性 end class Email < Content alias_attribute :subject, :todos end e = Email.find(1) e.todos # => "Superstars" e.subject # => "Superstars" e.subject? # => true e.subject = "Megastars" e.todos # => "Megastars"
尝试的代码及错误
我试了下面这段代码:
class Content < ActiveRecord::Base self.table_name = 'todos' end
结果出现了如下错误:
An error occurred while loading ./spec/decorators/todos_decorator_spec.rb. Failure/Error: module Content TypeError: Content is not a module app/models/content_controller.rb:1: previous definition of Content was here # ./app/models/concerns/content_types.rb:1:in `<top (required)>' # ./config/environment.rb:5:in `<top (required)>' # ./spec/rails_helper.rb:13:in `require' # ./spec/rails_helper.rb:13:in `<top (required)>' # ./spec/decorators/todos_decorator_spec.rb:1:in `require' # ./spec/decorators/todos_decorator_spec.rb:1:in `<top (required)>'
解决方案
1. 先解决Content命名冲突错误
你遇到的TypeError: Content is not a module,是因为代码里已经在content_controller.rb定义了一个Content类,但在content_types.rb里又把Content当成模块来声明(写了module Content),导致命名冲突。
解决办法二选一:
- 把
content_types.rb里的模块名改成别的,比如ContentTypes,避免和已有的Content类重名; - 给已有的
Content类加上命名空间,比如改成class App::Content < ActiveRecord::Base,这样就不会和模块名冲突。
2. 重命名与表名同名的变量
根据你的需求场景,分两种情况处理:
场景一:模型对应todos表,同时给实例属性todos起别名
如果todos是Content模型的一个数据库列,直接用alias_attribute即可,同时指定模型对应的表:
class Content < ActiveRecord::Base self.table_name = 'todos' # 绑定到todos表 alias_attribute :custom_name, :todos # 给todos属性起别名custom_name end
这样使用时,content.custom_name和content.todos完全等价,包括读写和判断方法(比如custom_name?)。
场景二:给模型类本身起别名(用Content代替Todo模型)
如果你的需求是让Content作为Todo模型的别名(对应todos表),可以直接给常量赋值:
# 在config/initializers/目录下新建文件,比如model_aliases.rb Content = Todo
或者用Active Support提供的alias_const方法(需要确保加载了active_support/core_ext/module/aliasing):
module YourAppName alias_const :Content, :Todo end
这样Content就和Todo是同一个模型类,所有针对Todo的操作都可以用Content来执行。
内容的提问来源于stack exchange,提问作者fig-newtons
相关产品推荐
相关产品推荐

