如何修改 Commontator::Comment(或任何 rails 引擎)?

How to monkey patch Commontator::Comment (or any rails engine)?

我最近才知道猴子补丁这个词,所以我不确定我是否正确。

我正在使用 Commontator gem 在我的博客(Monologue::Post 模型)和我的其他模型上提供评论功能。我 运行 遇到一个问题,我试图从我的评论中获取父对象(即评论的内容)。看起来我必须做三个连接。与其在我的控制器中调用它,我想我可以扩展 gem 的模型以具有一个函数 comment_parent,该函数 return 父模型。

我有这个:

# config/initializers/comment_model_extenders.rb
module Commontator
  class Comment < ActiveRecord::Base
    def comment_parent
      # do some magic
      "return parent here"
    end
  end
end

我一定是做错了,因为我得到了这个错误:

irb(main):010:0> c=Commontator::Comment
=> Commontator::Comment(id: integer, creator_type: string, creator_id: integer, editor_type: string, editor_id: integer, thread_id: integer, body: text, deleted_at: datetime, cached_votes_up: integer, cached_votes_down:
integer, created_at: datetime, updated_at: datetime)
irb(main):011:0> c.comment_parent
NoMethodError: undefined method `comment_parent' for #<Class:0xab743d0>
        from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/dynamic_matchers.rb:26:in `method_missing'
        from (irb):11
        from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/console.rb:90:in `start'
        from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/console.rb:9:in `start'
        from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/commands_tasks.rb:69:in `console'
        from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
        from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands.rb:17:in `<top (required)>'
        from bin/rails:4:in `require'
        from bin/rails:4:in `<main>'

编辑:

根据 Fredrick 的评论,我将代码更改为

...
def self.comment_parent
...

但是输出如下:

irb(main):022:0*  c=Commontator::Comment
=> Commontator::Comment(id: integer, creator_type: string, creator_id: integer, editor_type: string, editor_id: integer, thread_id: integer, body: text, deleted_at: datetime, cached_votes_up: integer, cached_votes_down:
integer, created_at: datetime, updated_at: datetime)
irb(main):023:0> c.comment_parent
=> "return parent here"
irb(main):024:0> test = c.find(1)
  Commontator::Comment Load (35.7ms)  SELECT  "commontator_comments".* FROM "commontator_comments"  WHERE "commontator_comments"."id" =  LIMIT 1  [["id", 1]]
=> #<Commontator::Comment id: 1, creator_type: "User", creator_id: 2, editor_type: nil, editor_id: nil, thread_id: 2, body: "Love this parser.", deleted_at: nil, cached_votes_up: 0, cached_votes_down: 0, created_at: "201
5-02-12 22:04:48", updated_at: "2015-02-12 22:04:48">
irb(main):025:0> test.comment_parent
NoMethodError: undefined method `comment_parent' for #<Commontator::Comment:0xad08a10>
        from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activemodel-4.1.8/lib/active_model/attribute_methods.rb:435:in `method_missing'
        from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/attribute_methods.rb:213:in `method_missing'
        from (irb):25
        from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/console.rb:90:in `start'
        from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/console.rb:9:in `start'
        from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/commands_tasks.rb:69:in `console'
        from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
        from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands.rb:17:in `<top (required)>'
        from bin/rails:4:in `require'
        from bin/rails:4:in `<main>'

根据评论,这是我的解决方案:

总的来说,我希望它作为一个实例方法被调用,所以我的原始代码是正确的。我只是说错了。要调用实例方法,请执行以下操作之一:

Model.new.custom_method

my_model = Model.new #or .find(n)
my_model.custom_method

对于我的具体情况,我找到了这个解决方案:

module Commontator
  class Comment < ActiveRecord::Base
    def comment_parent
      # do some magic
      thread = Commontator::Thread.find(self.thread_id)
      parent_class = thread.commontable_type.camelize.constantize

      parent_class.find(thread.commontable_id)
    end
  end
end

Looking at the library, your parent object has_one :thread, :as => :commontable, while the thread has_many :comments.

因此,在 Comment 中,thread.commontable 应该可以让您回到原来的 parent。