Surcharger user_guardian.rb dans un plugin (pas de fork nécessaire !)

Salut, désolé pour cette question de débutant. J’ai lu la documentation mais j’ai besoin d’un peu d’aide, s’il vous plaît.

J’ai fait un fork de Discourse et apporté mes propres modifications, que je souhaite ensuite déployer moi-même. Le guide de contribution explique comment apporter des modifications et soumettre une PR, mais dans ce cas, je ne veux pas faire de PR. Je voudrais simplement prendre ma petite modification et faire fonctionner une installation de Discourse à partir de là. Je pensais que la méthode consistait à modifier cette ligne pour pointer vers mon propre dépôt :

Je l’ai fait et j’ai procédé à l’installation, mais mes modifications n’apparaissent pas. Il est donc clair que je fais quelque chose de mal. Des idées ? Merci !

EDIT :
Pour être transparent, et au cas où quelqu’un aurait une méthode plus simple, tout ce que j’essaie de faire, c’est permettre aux utilisateurs anonymes de modifier leurs noms d’utilisateur lorsqu’ils entrent en mode anonyme. C’est aussi simple que de changer false en true à cette ligne :

S’il existe une meilleure méthode, je suis preneur. Mais c’est tout ce dont j’ai besoin pour l’activer. Je suis compétent en Python, Java et dans de nombreuses autres technologies back-end, mais je ne connais absolument rien à Ruby/JavaScript/HTML/etc.

EDIT2 :
Comme indiqué dans un post que j’ai vu ailleurs, j’ai mis à jour app.yml comme suit :

run:
- exec:
 cd: /var/www/discourse
 cmd:
    - sudo -u discourse git remote set-url origin https://github.com/my/forked/discourse.git
    - sudo -u discourse git fetch origin
    - sudo -u discourse git checkout origin/master

Toujours rien après avoir reconstruit l’application. Elle se lance correctement, mais mes modifications ne semblent pas être présentes.

N’est-il pas possible d’encapsuler vos modifications dans un plugin et de l’utiliser à la place ?

Tous ceux qui l’ont fait ont regretté. Et vous ne pourrez pas obtenir beaucoup d’aide ici.

Quoi que vous fassiez, faites-le dans un plugin.

D’accord. Avez-vous une idée de comment je pourrais faire cela via un plugin ?

Salut @leighno5,

D’après mon expérience personnelle, je pense que pour faire ce que tu fais dans ton « fork », il est beaucoup plus simple d’écrire un plugin Ruby, à condition de bien comprendre Ruby et Rails pour pouvoir facilement créer un plugin pour Discourse (ou modifier n’importe quelle classe Rails).

Si nous ne maîtrisons pas assez Rails et Ruby pour écrire un plugin Discourse, mon expérience me dit que forké Discourse et bidouiller le cœur du système est « malavisé ».

Je dirais que l’analogie est la suivante (désolé pour cette idée simple) :

« Quelqu’un trouve difficile de marcher ; alors il décide de courir à la place. »

Laisse-moi t’expliquer, si tu n’y vois pas d’inconvénient :

Avant de commencer à écrire des applications Rails (rien à voir avec Discourse) et d’essayer d’écrire des plugins pour Discourse, j’étais un peu perdu ; je me suis même senti un peu agacé par Discourse, je crois. C’est comme quand on veut frapper une balle de golf pour la première fois ; elle ne va pas tout droit et il faut beaucoup d’efforts pour la faire atterrir au milieu du fairway. Forker Discourse, c’est comme sortir le gros driver sur le range avant même de savoir faire des chips et des putts avec les fers courts !

J’ai pris une pause dans la bidouille de Discourse (il y a plusieurs mois) et j’ai travaillé pendant un certain temps à construire réellement plusieurs applications Rails de zéro ; et ensuite (et seulement ensuite) j’ai commencé à développer une connaissance « instinctive » de Rails. Après cela, quand j’ai décidé de modifier Discourse (je fais actuellement tourner 6 plugins personnalisés que j’ai écrits en production pour Discourse), tout est devenu intuitif et les plugins modifiant le cœur de Ruby sont devenus trop simples.

Ruby est très flexible. Nous pouvons surcharger n’importe quelle classe, n’importe quel objet. Nous pouvons redéfinir chaque aspect de Ruby. Avec un peu d’expérience, on commence à se dire « WAOUH », je ne savais pas que Ruby était aussi flexible (et puissant), et on commence à « devenir dangereux » parce qu’on peut voler comme Superman avec Ruby et Rails. Nous sommes alors au début de notre voyage avec Ruby et Rails, pas à la fin !

Avec les connaissances en Ruby et Rails que j’ai acquises en 2020, sachant ce que je sais maintenant, je ne forkerais jamais Discourse pour modifier le cœur de Ruby et Rails comme tu le proposes, car les plugins sont tout simplement trop faciles pour surcharger et modifier les classes Ruby, dès qu’on comprend les bases des classes Ruby et les bases de la méta-programmation.

Ce que je veux dire, désolé d’être si direct, c’est que si quelqu’un pense avoir besoin de bidouiller le cœur de Discourse pour apporter quelques modifications mineures en Ruby, alors il ne comprend pas assez Ruby et Rails ; car s’il les comprenait, il ne bidouillerait pas le cœur et écrirait simplement un plugin rapide pour surcharger les classes et adorerait le monkey-patching.

D’un autre côté, si je voulais faire quelque chose de fou et me mettre dans une situation misérable, comme remplacer EmberJS de Discourse par React et Ant Design, alors le fork serait la seule voie à suivre ! Cependant, à mon avis, « Discourse » n’est pas défini par les « librairies Javascript ». Discourse est défini par les compétences de l’équipe de développement principale (les personnes) et leur attention aux détails, leur service client, leur approche d’équipe du développement de code open source, leur pipeline de fonctionnalités SPA, et tout leur travail acharné ! Ce serait un peu fou (à mon sens) de jeter tout ce capital intellectuel simplement parce qu’on pourrait préférer Ant Design (avec React) ou VueJS à Ember.

C’est tout aussi vrai, voire encore plus, si nous comptons simplement modifier le cœur de Discourse ici et là ! Ce serait un peu « dingue » de le forké pour cela, en jetant les « personnes » qui sont le « vrai » Discourse (et pas le code).

Je ne parle que de mon parcours personnel en 2020 pour apprendre Ruby et Rails. Maintenant, les bases deviennent faciles et je suis « dangereux », LOL. Je peux « bidouiller n’importe quoi avec du monkey-patching », ce qui n’est pas toujours bon ; et c’est là que les plugins Discourse interviennent.

Gardez le cœur solide comme un roc, et amusez-vous à « bidouiller » Discourse avec des plugins.

J’espère que cela t’aidera.

Note : en écrivant cette réponse, tu as écrit :

Cela prouve un peu mon point, n’est-ce pas ?

Écrire un « plugin » dans Discourse, c’est écrire du « code Ruby » (à un niveau), et pour d’autres, cela va beaucoup plus loin (en EmberJS).

Avant de commencer à écrire des plugins pour Discourse, mon conseil amical, qui peut sembler sans valeur à tes yeux, est de commencer par développer quelques applications Ruby on Rails. Apprends tes marques en Ruby et Rails, au moins les bases ; après cela, tu auras répondu toi-même à ta question ci-dessus.

Le chemin le plus court pour écrire des plugins Discourse, à mon avis, est d’apprendre Rails en premier.

J’espère que cela t’aidera !

Voici un bon point de départ :

Non, vous avez tout à fait raison. Je n’ai aucune expérience avec Ruby, alors je ne suis absolument pas offensé !

J’ai consulté le guide des plug-ins et l’ai parcouru plusieurs fois, mais malheureusement, mon ignorance en Ruby continue de me frustrer. Je n’ai aucune idée de la façon dont je pourrais écrire un plug-in qui remplacerait ce petit bout de code dans le fichier user-guardian afin de permettre aux utilisateurs anonymes de modifier leurs noms. :confused:

Bonjour @leighno5,

Oui, je comprends.

Ces sujets « HOWTO » sur les plug-ins ont été rédigés par des développeurs très talentueux disposant de plus d’une décennie d’expérience en programmation Rails et Ruby (voire davantage). En fait, certains d’entre eux comptent parmi les meilleurs développeurs Ruby et JS au monde.

Je suis absolument certain à 100 % que tous ces développeurs ont appris Rails et Ruby bien avant d’écrire leur premier plug-in Discourse.

Apprendre Rails n’est pas si difficile ; mais il faut réellement accomplir le « rituel pratique » consistant à construire quelques applications Rails de zéro. Pas seulement suivre un tutoriel sur YouTube (ce qui est bien), mais réellement créer une application fonctionnelle où vous devez gérer la configuration de la base de données, générer vos propres modèles, créer vos propres contrôleurs, écrire des validations de modèles, rédiger des initialisateurs, des modules d’aide, effectuer des migrations (modifications) de la base de données, travailler avec Ruby embarqué, et bien plus encore.

C’est en réalité très amusant et c’est le « chemin le plus court » pour apprendre à se sentir à l’aise afin d’écrire un plug-in (en ce qui concerne la partie Rails, je ne fais pas vraiment d’Ember personnellement, mais j’adore la partie Rails de l’architecture !).

De plus, vous devez apprendre à maîtriser la console Rails ! La console Rails est vraiment amusante et je l’utilise quotidiennement avec plaisir !

Aujourd’hui, mon client préféré et moi-même étions en session AnyDesk et il m’a demandé : « Peux-tu nous montrer cette nouvelle vue de l’inventaire ? ». Il voulait me regarder faire tout le processus. Une fois que nous avons tout mis en place et fait fonctionner, à la fin de l’appel, il a déclaré : « Tu as fait quelque chose dans Rails en 30 minutes qui aurait pris plusieurs semaines il y a quelques décennies !! ». Vraiment impressionnant, @leighno5. Fonce !

Une fois que vous aurez appris Rails, vous direz : « WAOUH », écrire des plug-ins Discourse est assez facile, du moins pour la partie Rails et Ruby !

J’espère que cela vous aidera.

Regardez le code #plugin existant. Il y en a absolument des tonnes maintenant, donc beaucoup d’exemples. Ne négligez pas la lecture des travaux antérieurs afin de pouvoir les exploiter.

Il semble que vous souhaitiez simplement remplacer une méthode, ce qui revient à la redéfinir dans votre fichier plugin.rb (bien que la meilleure pratique soit, à mon avis, de la séparer dans son propre fichier par module, mais cela ne vaut pas la peine pour une seule méthode !)

Au risque de révéler encore mon ignorance et de profiter de la gentillesse que vous m’avez déjà témoignée, seriez-vous disposé à développer un peu ce point ? Ou si vous connaissez un autre exemple où quelqu’un a remplacé un module et peut en fournir le lien, je vous en serais reconnaissant. Je ne suis absolument pas opposé à la lecture de la documentation, mais mon manque de compréhension du fonctionnement de Discourse est frustrant, malgré tout le temps passé à parcourir divers tutoriels et documents. Et oui, je sais que des questions aussi basiques donnent l’impression que je n’ai pas fait beaucoup d’efforts, mais je vous promets que ce n’est pas le cas !

Voici un exemple où nous avons défini une méthode dans PostGuardian :

Vous pourriez faire quelque chose de similaire pour UserGuardian en utilisant le nom de méthode existant, ce qui devrait le remplacer.

Solution simple (pour que cela fonctionne, même si ce n’est pas robuste) :

Écrivez littéralement le code original de la méthode et apportez votre modification. Inconvénient : si Discourse modifie le code, votre plugin pourrait faire planter l’instance.

Solution avancée (solution plus robuste) :

Pour aller plus loin, vous pourriez peut-être utiliser super pour hériter de la méthode originale, mais cela n’est pas garanti de fonctionner pour des raisons que je ne détaillerai pas ici. C’est néanmoins la meilleure pratique, car les mises à jour de cette méthode dans Discourse seront alors toujours prises en compte sans que vous ayez à modifier votre plugin.

Discourse est une plateforme. Cela prend du temps pour la maîtriser. Procédez simplement étape par étape.

C’est exactement ce qui m’inquiétait. La méthode avancée mentionnée dans votre paragraphe suivant est-elle couverte dans le guide pratique ? Existe-t-il un bon exemple simple de son utilisation dans un plugin existant qui pourrait être utilisé (copié) pour créer un nouveau plugin ?

Ne vous inquiétez pas pour l’instant de la méthode avancée. Concentrez-vous simplement sur le fait de faire fonctionner le système. Vous pouvez vous renseigner sur Ruby on Rails en général ailleurs dans les guides en ligne. Cela sort un peu du cadre spécifique de Discourse et de ce forum. Gardez-le à l’esprit.

D’accord, merci ! Disons que je finis par écrire un petit plugin. Si j’ai bien compris, je devrais ensuite vérifier le code principal à chaque mise à jour et réécrire le plugin si le code principal concerné a changé. C’est bien ça ? Merci.

C’est exact. Vérifiez-le occasionnellement, et surtout s’il commence à dysfonctionner. Le code Guardian est un peu plus critique car il s’agit de l’autorisation du site de codage, alors gardez un œil dessus.

Une autre solution consiste à ajouter des cas de test (aka spécifications) et à configurer une tâche automatisée pour les exécuter… mais cela devient compliqué !

Une autre tâche bonus consiste à configurer travis-ci.org pour exécuter les tests de votre plugin, afin que vous soyez prévenu en cas de dysfonctionnement.

Clairement, ce n’est pas une tâche à prendre à la légère. J’aimerais modifier les modales de connexion/création de compte et supprimer l’image de Twitter. Peut-être que cette dernière serait un meilleur premier projet. Merci.

Si quelqu’un tombe sur ce message et qu’il était aussi perdu que moi, je fournis ci-dessous mon code, car j’ai réussi à le faire fonctionner comme prévu. Je n’ai modifié aucun fichier. J’ai simplement créé un nouveau fichier plugin.rb et y ai placé le contenu suivant :

# about: Permet aux utilisateurs en mode anonyme de modifier leurs noms d'utilisateur
# version: 0.1


require_dependency 'guardian'
require_dependency 'guardian/user_guardian'

class ::Guardian
end

module ::UserGuardian
  def can_edit_username?(user)
    return false if SiteSetting.sso_overrides_username?
    return true if is_staff?
    return false if SiteSetting.username_change_period <= 0
    return true if is_anonymous?
    is_me?(user) && ((user.post_count + user.topic_count) == 0 || user.created_at > SiteSetting.username_change_period.days.ago)
  end


  def can_edit_name?(user)
    return false unless SiteSetting.enable_names?
    return false if SiteSetting.sso_overrides_name?
    return true if is_staff?
    return true if is_anonymous?
    can_edit?(user)
  end
end

Cela remplace la classe user_guardian.rb dans le cœur de Discourse afin de permettre aux utilisateurs de modifier le nom d’utilisateur et le nom de leurs comptes anonymes.

Si vous comparez ce que j’ai ici avec ce qui se trouve dans user_guardian.rb dans le cœur de Discourse, vous verrez qu’il y a beaucoup d’autres éléments avec lesquels je n’avais pas besoin de faire quoi que ce soit, donc je les ai laissés tels quels. Tout ce dont j’avais besoin était de modifier ces deux méthodes can_edit_username et can_edit_name en changeant certaines valeurs de retour de false à true, et j’ai pu obtenir ce dont j’avais besoin.

Il est certain qu’il y a des améliorations à apporter, et il existe probablement des meilleures pratiques que j’ai pu dégager en lisant les publications liées ici et ailleurs, mais si vous êtes tout nouveau dans Ruby comme moi et que vous voulez simplement ajuster quelque chose de très simple dans le cœur, c’est un exemple minimaliste fonctionnel de ce que vous devez faire.

Un grand merci aux personnes de ce fil pour leur patience, leurs encouragements et leur aide ! En particulier @merefield, qui m’a en fait aidé dans un autre post par le passé.

LOL

Tu as fait un long chemin depuis ton idée initiale de forker tout Discourse et d’abandonner la branche principale pour ce genre de tâches simples.

Bien joué :slight_smile:

Avez-vous suivi tout le chemin Install Discourse on Ubuntu or Debian for Development ou avez-vous simplement travaillé sur votre site de production en espérant le meilleur ?