Utilisation de HasCustomFields dans un plugin

J’ai un modèle dans un plugin. Le modèle est Pfaffmanager::Server et la table est pfaffmanager_servers. Pour des raisons spécifiques, je souhaite avoir des champs personnalisés pour ce modèle (je m’attends à ce qu’il existe des cas où je veux étendre les données du serveur, mais uniquement pour quelques instances, et je ne veux pas d’une multitude de champs peu utilisés dans le modèle).

Voici la migration qui crée la table :

class CreatePfaffmanagerServerCustomField < ActiveRecord::Migration[6.0]
  def change
    create_table :pfaffmanager_server_custom_fields do |t|
      t.integer :server_id, null: false
      t.string :name, limit: 256, null: false
      t.text :value
      t.timestamps null: false
    end
    add_index :pfaffmanager_server_custom_fields, [:server_id, :name]
  end
end

Si j’utilise pfaffmanager_server_id au lieu de server_id, la migration échoue car elle ne peut pas trouver server_id. Cependant, lorsque j’utilise pfaffmanager_server_id comme nom de champ, lors de l’enregistrement d’un serveur après la création d’un champ personnalisé, j’obtiens l’erreur suivante :

  Pfaffmanager::ServerCustomField Load (0.4ms)  SELECT "pfaffmanager_server_custom_fields".* FROM "pfaffmanager_server_custom_fields" WHERE "pfaffmanager_server_custom_fields"."server_id" = 1
   (0.2ms)  ROLLBACK
PG::UndefinedColumn: ERROR:  column "pfaffmanager_server_id" of relation "pfaffmanager_server_custom_fields" does not exist
LINE 1: INSERT INTO pfaffmanager_server_custom_fields (pfaffmanager_...
    

Ainsi, si la migration contient le champ pfaffmanager_server_id, la migration échoue, et si le nom du champ est server_id, l’enregistrement échoue.

J’examine la méthode save_custom_fields dans concerns/has_custom_fields.rb, mais je ne parviens pas à déterminer s’il existe un moyen de la surcharger.

Existe-t-il une solution autre que de refactoriser entièrement le code pour utiliser server au lieu de pfaffmanager_server ?

Avez-vous également mis à jour l’appel add_index pour pointer vers pfaffmanager_server_id ?

Merci beaucoup, David !

Oui. Cela pourrait être mon problème. Je suppose que c’est le message d’erreur que j’aurais dû inclure. Je peux faire fonctionner la migration avec l’un ou l’autre champ (bien qu’avec pfaffmanager_server_id comme nom de champ, le nom de l’index dépasse 63 caractères, je dois donc utiliser un nom différent pour l’index).

Laissez-moi réessayer.

server_id comme nom de champ

class CreatePfaffmanagerServerCustomField < ActiveRecord::Migration[6.0]
  def change
    create_table :pfaffmanager_server_custom_fields do |t|
      t.integer :server_id, null: false
      t.string :name, limit: 256, null: false
      t.text :value
      t.timestamps null: false
    end
    add_index :pfaffmanager_server_custom_fields, [:server_id, :name]
  end
end

Échoue à l’enregistrement avec :

 Pfaffmanager::ServerCustomField Load (3.8ms)  SELECT "pfaffmanager_server_custom_fields".* FROM "pfaffmanager_server_custom_fields" WHERE "pfaffmanager_server_custom_fields"."server_id" = 1
   (1.4ms)  ROLLBACK
PG::UndefinedColumn: ERROR:  column "pfaffmanager_server_id" of relation "pfaffmanager_server_custom_fields" does not exist
LINE 1: INSERT INTO pfaffmanager_server_custom_fields (pfaffmanager_...
                                                       ^

Il cherche donc pfaffmanager_server_id. Maintenant, utilisons pfaffmanager_server_id.

pfaffmanager_server_id comme nom de champ

Voici la migration :

class CreatePfaffmanagerServerCustomField < ActiveRecord::Migration[6.0]
  def change
    create_table :pfaffmanager_server_custom_fields do |t|
      t.integer :pfaffmanager_server_id, null: false
      t.string :name, limit: 256, null: false
      t.text :value
      t.timestamps null: false
    end
    add_index :pfaffmanager_server_custom_fields,
      [:pfaffmanager_server_id, :name],
      name: 'index_pfaffmanager_server_custom_fields_on_server_id_and_name'

  end
end

Voici ce qui se passe lorsque j’essaie s.custom_fields (ce qui précède pouvait retourner nil pour cela, mais n’a échoué que lorsque j’ai essayé d’enregistrer un champ personnalisé). J’utilise register_custom_field_type ici) :

 pry(main)> s.custom_fields
   (1.1ms)  SELECT "pfaffmanager_server_custom_fields"."name", "pfaffmanager_server_custom_fields"."value" FROM "pfaffmanager_server_custom_fields" WHERE "pfaffmanager_server_custom_fields"."server_id" = 1 ORDER BY id asc
ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR:  column pfaffmanager_server_custom_fields.server_id does not exist
LINE 1: ...e" FROM "pfaffmanager_server_custom_fields" WHERE "pfaffmana...
                                                             ^

from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rack-mini-profiler-2.3.0/lib/patches/db/pg.rb:69:in `exec_params'
Caused by PG::UndefinedColumn: ERROR:  column pfaffmanager_server_custom_fields.server_id does not exist
LINE 1: ...e" FROM "pfaffmanager_server_custom_fields" WHERE "pfaffmana...
                                                             ^

Maintenant, il cherche server_id.

Il semble donc que custom_fields le veuille d’une manière, tandis que save_custom_fields le veut de l’autre.

Ce n’est pas grave quel est le nom de l’index, n’est-ce pas ?

Je ne pense pas, non.

Je pense que la deuxième approche est probablement celle à privilégier (en utilisant pfaffman_server_id comme nom de colonne).

Je me demande si la surcharge de cette méthode pourrait aider :

Vous pouvez vérifier la valeur actuelle dans la console comme ceci :

Server.new.custom_fields_fk

Si cela retourne server_id, je suggère de surcharger cette méthode dans votre modèle Server :

class Server < ...
  def custom_fields_fk
    "pfaffman_server_id"
  end
end

Ou peut-être est-ce cet extrait :thinking:

Merci beaucoup ! Donc Server.new.custom_fields_fk est pfaffmanager_server_id si j’utilise pfaffmanager_serfver_id. Alors peut-être que je devrais utiliser server_id et ensuite le surcharger comme vous l’avez suggéré plus haut.

Il semble que refresh_custom_fields_from_db essaie d’utiliser les mauvais noms. Je ne comprends pas tout à fait ce que fait _custom_fields.order....

Je vais voir ce qui se passe si j’utilise server_id et si je peux ensuite surcharger custom_fields_fk

Ha ! Vous l’avez fait ! Merci beaucoup. J’ai basculé sur server_id et j’ai ensuite fait ceci dans mon modèle server.rb :

    def custom_fields_fk
      @custom_fields_fk ||= "server_id"
    end

Tant que cela ne remplace cette valeur que pour ce modèle et ne casse pas user_custom_field et les autres, je pense que je suis prêt à me taper à nouveau la tête contre les murs sur Best way to enforce permissions--controller or constraint?. Ensuite, je pourrai ajouter des routes pour faire des choses comme remplir mes nouveaux champs personnalisés avec… quelque chose.

Je ne saurais trop vous remercier. Vous m’avez probablement évité une journée entière de travail. Je vous dois une bière :beer: !

Super ! :tada: Si vous trouvez un moyen de le rendre plus générique, cela sera certainement le bienvenu via une PR.

Si quelque chose me vient à l’esprit, je vous en informerai ou soumettrai une PR, mais je pense qu’un plugin souhaitant utiliser des champs personnalisés se situe plutôt en marge.

OM_fk_G.

custom_fields_fk me semblait tellement stupide que j’ai supposé que c’était quelque chose que j’avais l’intention de supprimer et que je lui avais donné un nom stupide pour savoir qu’il était sûr de le supprimer plus tard. C’était plus tard, alors je l’ai supprimé. Et puis mes spécifications ont échoué.

Il y avait même un commentaire avec un lien vers ce sujet dans le code.