Rails模型别名从关系调用中获得“未初始化的常量”

时间:2014-08-10 18:12:31

标签: ruby-on-rails model alias

在建立belongs_to :author这样的关系时,我总是使用:class_name => 'User'选项,但我从不喜欢它。它不是语义,IMO。

所以我在想我的User模型的别名。 "嗯",我想,"模型只是一个常数,所以让我们给它起另一个名字。

然后我写了Author = User并将其保存在app/models/author.rb

看起来很好,并且除了一个以外的所有目的都很好。当我尝试使用我的关系时,请说post.build_author我得到uninitialized constant Post::Author

为什么ruby找不到常量Author

似乎Post无法联系到它,所以我尝试了这个:

class Post
  def author_class_test
    Author
  end
end

=> Post.new.author_class_test
=> User(...)

所以,我认为Post可以"看" Author。但是在处理关系时,有没有人知道为什么会这样?

提前致谢。

更新

所以,出于好奇我尝试了这个:

class Post
  Author = User
  ...
end

然后又Post.new.build_author又让我uninitialized constant Post::Author。但至少现在我知道他对我撒谎。 :P

跟踪在此处结束:https://github.com/rails/rails/blob/master/activerecord/lib/active_record/inheritance.rb#L142

我开始认为它是ActiveRecord不考虑的边缘情况。

2 个答案:

答案 0 :(得分:0)

我看到你可以这样做的一种方法是创建一个存储这些别名的模块。

例如:

module UserAliases
  Author = User
end

class User < ActiveRecord::Base
  include UserAliases
  # ...
end

将模块放在应用程序的某个位置,需要它并将其包含在您的模型中,这应该可以解决问题。如果有效,请告诉我。

答案 1 :(得分:0)

您应该使用Class.new

您可以在回溯中看到,rails正在尝试使用compute_type构建关联类型。要使compute_type起作用,类名必须正确。

让我们谈谈在定义一个类时我们究竟在做什么。

class A
  def self.foo
    puts "#{self.name} foo"
  end
end

这是定义类的最常用方法,但它实际上只是将块传递给Class.new的别名。 Class.new也接受一个参数,您可以提供另一个类。将类传递给Class.new时,它会生成一个新类,并将传入的类设置为其超类。一个例子将清除这一点:

B = Class.new(A)
C = A

此处我们有BC,它们都与A具有相同的行为。但是,在将A分配给C和设置之间存在一些重要的区别A作为B的超类。与你相关的是:

A.foo
B.foo
C.foo

#=> A foo
#=> B foo
#=> A foo

您会看到我们何时使用作业,C没有使用您提供的名称。当我们使用Class.new时,我们告诉B采用我们给出的名称,而不是与分配类相同的名称。

你实际上是在创建一个行为类似于User的类,即使你问它的名字是什么,但是你仍然在没有设置类名的情况下调用关联Author

请改为:

Author = Class.new(User)