从Rails中的gem重写模块方法

Dav*_*lie 48 ruby gem ruby-on-rails will-paginate

will_paginate gem在我的Oracle版本上被破坏了.paginate_by_sqlWillPaginate模块中的默认方法是在查询中插入额外的"AS"并使其失败.

代码本身很容易修复,但我不确定让Rails接受我的更改的最佳方法.

我不想更改gem本身的代码,因为这会使我的代码在其他机器上被破坏.

我尝试创建一个包含以下内容的lib/test.rb文件:

module WillPaginate
  def paginate_by_sql
    (my code goes here)
  end
end
Run Code Online (Sandbox Code Playgroud)

并要求它来自environment.rb,但它没有接受我的更改.我也尝试过来自controllers/application.rb,但是再次提到我的更改.

暂时,我通过覆盖特定模型本身的方法来使其工作,但这有点像黑客,并且意味着我不能在该项目中的任何其他模型上使用它.

我确信有一个简单的方法可以做到这一点,但我没有运气跟踪它使用谷歌.

Ste*_*ham 67

更简洁的解决方案:

WillPaginate::Finder::ClassMethods.module_eval do
 def paginate_by_sql sql, options
   # Your code here
 end
end
Run Code Online (Sandbox Code Playgroud)

将代码放入config/initializers中的初始化文件中.这是放置环境时需要运行的代码的正确位置.它还可以更好地组织您的代码,使每个文件的意图更加清晰,从而更容易追踪错误.不要混淆环境.rb!

  • 很酷。在新的`paginate_by_sql`中,我可以访问它的旧版本吗?我可以调用类似 `super(sql, options)` 之类的东西吗? (2认同)

Abr*_*ram 49

好吧,我只是想让像我这样的人更容易,并且在阅读其他答案后仍然有点挣扎.

首先通过搜索代码行找到你要在github repo上更改的代码(你可以很容易地使用pry找到它)你要在gem中更改,然后Code在左边选择而不是Issues

在此输入图像描述

在此输入图像描述

下一步复制要更改的模块的内容,并将其放入.rbconfig/initializers文件夹中的适当命名的文件中.这是一个例子:

module Forem
  module TopicsHelper
    def link_to_latest_post(post)
      text = "#{time_ago_in_words(post.created_at)} #{t("ago_by")} #{post.user}"
      link_to text, forum_topic_path(post.topic.forum, post.topic, :anchor => "post-#{post.id}")
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

现在,将其更改为:

Forem::TopicsHelper.module_eval do
  def link_to_latest_post(post)
    text = "#{time_ago_in_words(post.created_at)} #{t("ago_by")} #{post.user}"
    link_to text, forum_topic_path(post.topic.forum, post.topic, :anchor => "post-#{post.id}")
  end
end
Run Code Online (Sandbox Code Playgroud)

现在,对代码进行任何其他更改并重新启动服务器.

你去吧!

  • 你能像这样调用原始方法吗?或者你有alias_method_chain(无论如何在Rails中)吗? (2认同)

Sar*_*Mei 29

你正在做什么会工作,但你的代码需要看起来像这样:

module WillPaginate
  module Finder
    module ClassMethods
      def paginate_by_sql(sql, options)
        # your code here
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

换句话说,进入finder.rb,删除除模块头和要覆盖的方法之外的所有内容,然后保存到lib中的文件并包含在environment.rb中.瞧,即时猴子补丁!

  • 这应该在初始化器`config/initializers`中 - 不要把它放在`environment.rb`文件中! (17认同)