如何猴子补丁Commontator ::评论(或任何铁路引擎)?

时间:2015-02-13 16:28:59

标签: ruby-on-rails ruby monkeypatching

我刚刚学会了猴子补丁这个术语,所以我不确定自己是否正确。

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

我有这个:

# 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" = $1 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>'

2 个答案:

答案 0 :(得分:1)

Looking at the library,您的父对象has_one :thread, :as => :commontable,而thread has_many :comments

因此,在Comment内,thread.commontable可以让您反过来回到原来的父母身边。

答案 1 :(得分:0)

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

一般情况下,我希望将其作为实例方法调用,因此我的原始代码是正确的。我只是说错了。要调用实例方法,请执行以下操作之一:

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