Переопределение метода модуля из гема в Rails

Гем will_paginate не работает в моей версии Oracle. Метод по умолчанию paginate_by_sql в модуле WillPaginate вставляет дополнительный AS в запрос и вызывает его сбой.

Сам код легко исправить, но я не уверен, как лучше всего заставить Rails принять мои изменения.

Я не хочу менять код в самом геме, так как это приведет к поломке моего кода на других машинах.

Я попытался создать файл lib / test.rb, содержащий:

module WillPaginate
  def paginate_by_sql
    (my code goes here)
  end
end

и требует его от environment.rb, но он не принимает мои изменения. Я также пробовал требовать его из controllers / application.rb, но опять же, не собирая свои изменения.

Временно я заставил его работать, переопределив метод в самой конкретной модели, но это своего рода взлом и означает, что я не могу использовать его ни на одной из других моделей в этом проекте.

Я уверен, что есть простой способ сделать это, но мне не удалось отследить его с помощью Google.

Ответов (3)

Решение

То, что вы делаете, будет работать, но ваш код должен выглядеть так:

module WillPaginate
  module Finder
    module ClassMethods
      def paginate_by_sql(sql, options)
        # your code here
      end
    end
  end
end

Другими словами, зайдите в finder.rb, удалите все, кроме заголовков модулей и метода, который вы хотите переопределить, затем сохраните в файл в lib и включите в environment.rb. Вуаля, мгновенный патч обезьяны!

Хорошо, я просто собираюсь облегчить это для таких людей, как я, которые приходят и все еще немного борются после прочтения других ответов.

Сначала найдите код, который вы хотите изменить, в репозитории github, выполнив поиск строки кода (вы можете легко найти ее с помощью pry ), которую хотите изменить в геме, а затем выберите Code слева вместо Issues

введите описание изображения здесь

введите описание изображения здесь

Затем скопируйте содержимое модуля, который вы хотите изменить, и поместите его в .rb файл с подходящим названием внутри папки config / 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

Теперь измените его на:

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

Теперь внесите любые дополнительные изменения в код и перезапустите сервер.

Вы уходите!

Более лаконичное решение:

WillPaginate::Finder::ClassMethods.module_eval do
 def paginate_by_sql sql, options
   # Your code here
 end
end

Поместите код в файл инициализатора в config / initializers. Это правильное место для размещения кода, который должен запускаться при загрузке среды. Это также лучше организует ваш код, делая более понятным намерение каждого файла, поэтому ошибки будет легче отследить. Не загромождайте environment.rb!