Verwendung von HasCustomFields in einem Plugin

Ich habe ein Modell in einem Plugin. Das Modell ist Pfaffmanager::Server, die Tabelle ist pfaffmanager_servers. Aus bestimmten Gründen möchte ich benutzerdefinierte Felder für dieses Modell haben (ich erwarte, dass es Anwendungsfälle gibt, in denen ich die Serverdaten erweitern möchte, die wahrscheinlich nur für wenige Instanzen benötigt werden, und ich möchte nicht eine riesige Anzahl von meist ungenutzten Feldern im Modell haben).

Hier ist die Migration, die die Tabelle erstellt:

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

Wenn ich pfaffmanager_server_id anstelle von server_id verwende, schlägt die Migration fehl, weil sie server_id nicht finden kann. Wenn ich jedoch pfaffmanager_server_id als Feldnamen verwende, erhalte ich beim Speichern eines Servers nach dem Erstellen eines benutzerdefinierten Feldes folgenden Fehler:

  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_...
    

Wenn die Migration also das Feld pfaffmanager_server_id enthält, schlägt die Migration fehl, und wenn der Feldname server_id ist, schlägt das Speichern fehl.

Ich sehe mir save_custom_fields in concerns/has_custom_fields.rb an, kann aber nicht ganz herausfinden, ob es eine Möglichkeit gibt, dies zu überschreiben.

Gibt es etwas, das ich tun kann, ohne das Ganze komplett umzustellen und server anstelle von pfaffmanager_server zu verwenden?

Hast du auch den add_index-Aufruf so angepasst, dass er auf pfaffmanager_server_id verweist?

Vielen Dank, David!

Ja, das könnte mein Problem sein. Ich vermute, das ist die Fehlermeldung, die ich hätte einfügen sollen. Und ich kann die Migration mit beiden Feldnamen zum Laufen bringen (obwohl bei pfaffmanager_server_id als Feldname der Indexname länger als 63 Zeichen wird, sodass ich einen anderen Namen für den Index verwenden muss).

Lass es mich noch einmal versuchen.

server_id als Feldname

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

Fehlschlag beim Speichern mit:

 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_...
                                                       ^

Es wird also nach pfaffmanager_server_id gesucht. Nun verwenden wir pfaffmanager_server_id.

pfaffmanager_server_id als Feldname

Hier ist die 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

Hier ist, was passiert, wenn ich s.custom_fields versuche (das obige konnte nil dafür zurückgeben, aber es trat kein Fehler auf, bis ich versuchte, ein benutzerdefiniertes Feld zu speichern). Ich rufe register_custom_field_type hier auf:

 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...
                                                             ^

Jetzt wird nach server_id gesucht.

Es scheint also, als ob custom_fields es auf die eine Art und save_custom_fields auf die andere Art haben möchte.

Ist es ihm egal, wie der Indexname lautet, oder?

Nein, das glaube ich nicht.

Ich denke, der zweite Ansatz ist wahrscheinlich der richtige (die Verwendung von pfaffman_server_id als Spaltenname).

Ich frage mich, ob das Überschreiben dieser Methode helfen könnte:

Du kannst den aktuellen Wert in der Konsole so prüfen:

Server.new.custom_fields_fk

Wenn das server_id ist, schlage ich vor, diese Methode in deinem Server-Modell zu überschreiben:

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

Oder vielleicht ist es dieser Teil :thinking:

Vielen Dank! Also ist Server.new.custom_fields_fk pfaffmanager_server_id, wenn ich pfaffmanager_serfver_id verwende. Vielleicht sollte ich also server_id verwenden und dann wie oben vorgeschlagen überschreiben.

Es sieht so aus, als würde refresh_custom_fields_from_db versuchen, die falschen Namen zu verwenden. Ich verstehe nicht ganz, was _custom_fields.order... macht.

Ich werde ausprobieren, was passiert, wenn ich server_id verwende, und ob ich dann custom_fields_fk überschreiben kann.

Ha! Du hast es geschafft! Vielen Dank. Ich habe es auf server_id umgestellt und habe dies in meinem server.rb-Modell gemacht:

    def custom_fields_fk
      @custom_fields_fk ||= "server_id"
    end

Solange das nur dieses Modell überschreibt und user_custom_field sowie ähnliche nicht kaputt macht, denke ich, bin ich bereit, mich wieder auf Best way to enforce permissions--controller or constraint? selbst die Köpfe zu zertrümmern. Und dann kann ich Routen hinzufügen, um Dinge zu tun wie meine neuen benutzerdefinierten Felder mit … irgendetwas zu füllen.

Ich kann dir nicht genug danken. Du hast mir wahrscheinlich einen ganzen Tag erspart. Ich schulde dir ein :beer:!

Toll! :tada: Wenn dir eine Möglichkeit einfällt, es allgemeiner zu gestalten, wären wir dafür sehr dankbar (PR-welcome).

Fällt mir etwas ein, werde ich euch Bescheid geben oder einen PR einreichen, aber ich muss davon ausgehen, dass ein Plugin, das benutzerdefinierte Felder verwenden möchte, ziemlich am Rand liegt.

OM_fk_G.

custom_fields_fk schien so dumm, dass ich annahm, es sei etwas, das ich löschen wollte und dem ich einen dummen Namen gegeben hatte, damit ich wüsste, dass es sicher zu löschen war. Es war später, also löschte ich es. Und dann schlugen meine Spezifikationen fehl.

Es gab sogar einen Kommentar mit einem Link zu diesem Thema im Code.