web-dev-qa-db-fra.com

Substitution d'une méthode de module à partir d'une gemme dans Rails

La gemme will_paginate est cassée sur ma version d'Oracle. Le défaut paginate_by_sql dans le module WillPaginate insère un "AS" supplémentaire dans une requête et provoque son échec.

Le code lui-même est facilement corrigé, mais je ne suis pas sûr de la meilleure façon d'obtenir Rails pour récupérer ma modification.

Je ne veux pas changer le code dans la gemme elle-même, car cela laissera mon code cassé sur d'autres machines.

J'ai essayé de créer un fichier lib/test.rb contenant:

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

et l'exige de environment.rb, mais il ne reprend pas mes modifications. J'ai également essayé de l'exiger de controllers/application.rb, mais encore une fois, je n'ai pas repris mes modifications.

Temporairement, je l'ai fait fonctionner en remplaçant la méthode dans le modèle spécifique lui-même, mais c'est un peu un hack, et signifie que je ne peux pas l'utiliser sur aucun des autres modèles de ce projet.

Je suis sûr qu'il existe un moyen facile de le faire, mais je n'ai aucune chance de le retrouver à l'aide de Google.

47
Dave Smylie

Ce que vous faites fonctionnera, mais votre code doit ressembler à ceci:

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

En d'autres termes, allez dans Finder.rb, supprimez tout sauf les en-têtes de module et la méthode que vous souhaitez remplacer, puis enregistrez dans un fichier dans lib et incluez dans environment.rb. Voila, patch de singe instantané!

29
Sarah Mei

Une solution plus concise:

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

Mettez le code dans un fichier d'initialisation dans config/initializers. C'est le bon endroit pour mettre du code qui doit être exécuté lorsque l'environnement est chargé. Il organise également mieux votre code, ce qui rend l'intention de chaque fichier plus claire, ainsi les bogues seront plus faciles à traquer. N'encombrez pas environment.rb!

67
Steve Graham

D'accord, je vais simplement faciliter les choses pour les gens comme moi qui viennent et luttent encore un peu après avoir lu les autres réponses.

Tout d'abord recherchez le code que vous souhaitez modifier sur le référentiel github en recherchant la ligne de code (vous pouvez facilement le trouver en utilisant pry ) que vous souhaitez modifier dans la gemme, puis en sélectionnant Code sur la gauche au lieu de Issues

enter image description here

enter image description here

Suivant Copiez le contenu du module que vous souhaitez modifier et placez-le dans un _ bien nommé .rb fichier à l'intérieur de votre dossier config/initializers. Voici un exemple:

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

Maintenant, changez-le en:

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

Maintenant, apportez des modifications supplémentaires au code et redémarrez votre serveur.

C'est parti!

49
Abram