1

Q:如何在嵌套类中共享父类的信息

class Post
  MODEL = self
  extend PostMod
  has_many :comments, :class_name => 'Post::Comment'

  class Comment
    include CommentMod
    belongs_to :model, :class_name => "Post"
    def method_in_comment
      puts MODEL
    end
  end
  class Another

  end
end
module  CommentMod
  def method_in_mod1
    puts self.class::MODEL
  end
  def method_in_mod2
    puts MODEL
  end
end
module  PostMod
  def method_in_mod1
    puts self::Comment
  end
end
b = Post::Comment.new
b.method_in_comment # Post
b.method_in_mod1 # uninitialized constant Post::Comment::MODEL (NameError)
b.method_in_mod2 # uninitialized constant CommentMod::MODEL (NameError)

这种设计的原因,在这个例子中(实际系统要复杂得多),只是通过“包含模块”来为任何模型添加注释。那将添加控制器、视图和模型方法

所有模型的评论行为都是相似的。但是,如果需要调整某些东西,模型可能会覆盖 Comment 类中的任何方法。

棘手的部分是,模块对顶级类(Post)和同一级别的类(Comment 和Another)一无所知,但它们需要在它们上调用一些类方法

我现在正在使用 class.name 解析来获取顶级类的类名,但应该还有其他方法。

欢迎任何建议,包括更改设计。

更新

帖子和评论只是一个例子,我的项目中没有这个模型。

我正在从下划线 nonation(或 CamelCase)迁移到嵌套类(从 ArticleTranslation 到 Article::Translation)。这对我来说看起来更清楚。在以前的版本中,我使用模型名称来调用类上的类方法(在 ModelTranslation 等上)现在,在重构 lib 模块之后,我不再需要知道 model_name。

但我掉进了陷阱:在 ruby​​ 中,你可以重新开课,比如

class Post < ActiveRecord::Base

end
class Post::Comment < ActiveRecord::Base
  belongs_to  :language
end

class Post::Comment::Another1 < ActiveRecord::Base

end

class Post::Comment::Another2 < ActiveRecord::Base

end

class Language < ActiveRecord::Base
  has_many :post_comments, :class_name => "Post::Comment"
end

我有一个问题:如果页面在服务器启动后立即加载——一切正常,但下一次调用该页面会引发错误:没有这样的关联;调用包含的模块方法——没有方法错误。我认为,rails 为 Post::Comment 加载了错误的文件,最糟糕的是我无法调试这个错误......但这是另一个问题。

更新2

第二个问题解决了。问题出在助手类中。

4

3 回答 3

1

因此,根据您后来的评论,这有点像您使用 Module.extended 之后的内容:

module PostMod
  def self.extended(klass)
    klass.send :include, InstanceMethods
  end

  module InstanceMethods
    def method_in_mod1
      puts "from PostMod#method_in_mod1: #{self.class.inspect}"
    end
  end
end

module CommentMod
  def self.extended(klass)
    klass.send :include, InstanceMethods
  end

  module InstanceMethods
    def method_in_mod1
      puts "from CommentMod#method_in_mod1: #{self.class.inspect}"
    end

    def method_in_mod2
      puts "from CommentMod#method_in_mod2: #{self.class.ancestors.inspect}"
    end
  end
end

class Post
  extend PostMod

  class Comment
    extend CommentMod

    def method_in_comment
      puts "from Post::Comment#method_in_comment: #{self.class.inspect}"
    end
  end

  class Another

  end
end


b = Post::Comment.new
b.method_in_comment # Post::Comment
b.method_in_mod1 # Post::Comment
b.method_in_mod2 # [Post::Comment, CommentMod::InstanceMethods, Object, Kernel]

尽管输出与您的示例不完全相同。以您尝试的方式共享类变量可能很困难,因为您实际上没有使用任何继承,只是使用嵌套类。

您能否详细说明共享这些变量的意图,也许有更好的方法来实现目标?

于 2011-02-10T17:28:06.140 回答
1

我通过重构代码自己解决了问题。因此不再需要共享 class.name。如果我需要最好的方法是使用 class.name.scan 或匹配来获得顶级类名,然后重构代码并删除 class.name.scan =) 共享类名是个坏主意。

于 2011-02-10T23:26:51.917 回答
1

您能否澄清“仅通过“包含模块”向任何模型添加注释”。?你的意思是你有一个 ActiveRecord 模型评论,并且你想多态地将它与许多其他模型相关联,例如

Post
  has_many :comments

Article
 has_many :comments

...ETC?

于 2011-02-09T23:04:19.253 回答