Ich verwende Rails-Migrationen zum Verwalten eines Datenbankschemas und erstelle eine einfache Tabelle, in der ich einen nicht ganzzahligen Wert als Primärschlüssel (insbesondere eine Zeichenfolge) verwenden möchte. Nehmen wir an, es gibt eine Tabelle, employees
in der Mitarbeiter durch eine alphanumerische Zeichenfolge identifiziert werden, z "134SNW"
.
Ich habe versucht, die Tabelle in einer Migration wie folgt zu erstellen:
create_table :employees, {:primary_key => :emp_id} do |t|
t.string :emp_id
t.string :first_name
t.string :last_name
end
Was mir das gibt, ist, wie es scheint, als hätte es die Zeile völlig ignoriert t.string :emp_id
und sie zu einer ganzzahligen Spalte gemacht. Gibt es eine andere Möglichkeit, Rails die PRIMARY_KEY-Einschränkung (ich verwende PostgreSQL) für mich generieren zu lassen, ohne die SQL in einem execute
Aufruf schreiben zu müssen ?
HINWEIS : Ich weiß, dass es nicht am besten ist, Zeichenfolgenspalten als Primärschlüssel zu verwenden. Bitte keine Antworten, die nur das Hinzufügen eines ganzzahligen Primärschlüssels bedeuten. Ich kann trotzdem eine hinzufügen, aber diese Frage ist immer noch gültig.
quelle
rake db:migrate
Die automatisch generierte Schemadefinition enthält diese Einschränkung nicht!Antworten:
Leider habe ich festgestellt, dass es ohne Verwendung nicht möglich ist
execute
.Warum es nicht funktioniert
Durch Untersuchen der ActiveRecord-Quelle können wir den Code finden für
create_table
:In
schema_statements.rb
:Wenn Sie also versuchen, einen Primärschlüssel in den
create_table
Optionen anzugeben , wird ein Primärschlüssel mit diesem angegebenen Namen erstellt (oder, falls keiner angegeben istid
). Dazu wird dieselbe Methode aufgerufen, die Sie in einem Tabellendefinitionsblock verwenden können :primary_key
.In
schema_statements.rb
:Dadurch wird lediglich eine Spalte mit dem angegebenen Typnamen erstellt
:primary_key
. Dies ist in den Standard-Datenbankadaptern wie folgt eingestellt:Die Problemumgehung
Da wir uns an diese als Primärschlüsseltypen halten, müssen wir
execute
einen Primärschlüssel erstellen, der keine Ganzzahl ist (PostgreSQLserial
ist eine Ganzzahl, die eine Sequenz verwendet):Und wie Sean McCleary erwähnt hat , sollte Ihr ActiveRecord-Modell den Primärschlüssel mithilfe von
set_primary_key
:quelle
self.primary_key=
statt verwendenset_primary_key
, da letzteres veraltet ist.schema.rb
emp_id
wieder eineinteger
Typspalte angezeigt wird. Es scheint, dassschema.rb
dasexecute "ALTER TABLE employees ADD PRIMARY KEY (emp_id);"
in keiner Weise speichern kann.schema.rb
aufstructure.sql
über eineconfig.active_record.schema_format
Einstellung umschalten , die entweder:sql
oder sein kann:ruby
. guides.rubyonrails.org/v3.2.13/…Das funktioniert:
Es mag nicht schön sein, aber das Endergebnis ist genau das, was Sie wollen.
quelle
drop_table :employees
schema.rb
nicht synchronisierte Methode ... sie behält die:primary_key => :emp_id
Deklaration bei, aber wenn sierake db:schema:load
aufgerufen wird, wie zu Beginn der Tests, wird eine ganzzahlige Spalte erzeugt. Es kann jedoch vorkommen, dass beim Umschalten auf die Verwendung vonstructure.sql
(Konfigurationsoption) Tests die Einstellungen beibehalten und diese Datei zum Laden des Schemas verwendet werden.Ich habe eine Möglichkeit, damit umzugehen. Das ausgeführte SQL ist ANSI SQL, daher funktioniert es wahrscheinlich auf den meisten ANSI SQL-kompatiblen relationalen Datenbanken. Ich habe getestet, dass dies für MySQL funktioniert.
Migration:
Machen Sie in Ihrem Modell Folgendes:
quelle
Ich habe es in Rails 4.2 versucht. Um Ihren benutzerdefinierten Primärschlüssel hinzuzufügen, können Sie Ihre Migration wie folgt schreiben:
Während Sie sich die Dokumentation von
column(name, type, options = {})
ansehen und die Zeile lesen:Ich habe die oben genannten IDs, wie ich gezeigt habe. Hier sind die Tabellen-Metadaten nach dem Ausführen dieser Migration:
Und von der Rails-Konsole:
quelle
schema.rb
generierte Datei nicht denstring
Typ für den Primärschlüssel widerspiegelt. Wenn Sie also die Datenbank mit a generierenload
, wird der Primärschlüssel als Ganzzahl erstellt.In Rails 5 können Sie tun
Siehe create_table-Dokumentation .
quelle
before_create :set_id
dem Modell eine Methode hinzufügen müssen, um den Wert des Primärschlüssels zuzuweisenEs sieht so aus, als ob dies mit diesem Ansatz möglich ist:
Dadurch wird die Spalte widget_id zum Primärschlüssel für die Widget-Klasse. Anschließend müssen Sie das Feld beim Erstellen von Objekten füllen. Sie sollten dies mit dem vor dem Erstellen erstellten Rückruf tun können.
Also etwas in der Art von
quelle
primary_key: true
anstatt nurprimary
in der Antwort gegebenIch bin auf Rails 2.3.5 und meine folgende Methode funktioniert mit SQLite3
Es besteht keine Notwendigkeit für: id => false.
quelle
you can't redefine the primary key column 'widgets'. To define a custom primary key, pass { id: false } to create_table.
Nach fast jeder Lösung, die besagt, dass "dies bei mir in der X-Datenbank funktioniert hat", sehe ich einen Kommentar des Originalplakats zum Effekt "hat bei Postgres nicht bei mir funktioniert". Das eigentliche Problem hier könnte tatsächlich die Postgres-Unterstützung in Rails sein, die nicht fehlerfrei ist und wahrscheinlich 2009 schlimmer war, als diese Frage ursprünglich gestellt wurde. Wenn ich mich zum Beispiel richtig erinnere, wenn Sie auf Postgres sind, können Sie im Grunde keine nützliche Ausgabe von erhalten
rake db:schema:dump
.Ich bin selbst kein Postgres-Ninja, ich habe diese Informationen aus Xavier Shays ausgezeichnetem PeepCode-Video auf Postgres erhalten. Dieses Video übersieht tatsächlich eine Bibliothek von Aaron Patterson, ich denke Texticle, aber ich könnte mich falsch erinnern. Aber ansonsten ist es ziemlich gut.
Wenn Sie auf Postgres auf dieses Problem stoßen, prüfen Sie, ob die Lösungen in anderen Datenbanken funktionieren. Vielleicht verwenden Sie
rails new
, um eine neue App als Sandbox zu generieren, oder erstellen Sie einfach so etwasin
config/database.yml
.Wenn Sie überprüfen können, ob es sich um ein Postgres-Supportproblem handelt, und einen Fix finden, fügen Sie bitte Patches zu Rails hinzu oder verpacken Sie Ihre Fixes in einem Juwel, da die Postgres-Benutzerbasis innerhalb der Rails-Community vor allem dank Heroku ziemlich groß ist .
quelle
Ich habe eine Lösung dafür gefunden, die mit Rails 3 funktioniert:
Die Migrationsdatei:
Und im Modell employee.rb:
quelle
Der Trick, der bei Rails 3 und MySQL für mich funktioniert hat, war folgender:
So:
Scheint, dass MySQL den eindeutigen Index für eine Nicht-Null-Spalte in einen Primärschlüssel konvertiert!
quelle
Sie müssen die Option verwenden: id => false
quelle
Wie wäre es mit dieser Lösung,
Warum können wir im Mitarbeitermodell keinen Code hinzufügen, der die Eindeutigkeit in der Spalte überprüft, zum Beispiel: Angenommen, Mitarbeiter ist Modell, indem Sie EmpId haben, eine Zeichenfolge, für die wir EmpId ": Eindeutigkeit => true" hinzufügen können
Ich bin nicht sicher, ob dies eine Lösung ist, aber das hat bei mir funktioniert.
quelle
Ich weiß, dass dies ein alter Thread ist, über den ich gestolpert bin ... aber ich bin schockiert, dass niemand DataMapper erwähnt hat.
Ich finde, wenn Sie von der ActiveRecord-Konvention abweichen müssen, habe ich festgestellt, dass dies eine großartige Alternative ist. Es ist auch ein besserer Ansatz für Legacy und Sie können die Datenbank "wie sie ist" unterstützen.
Ruby Object Mapper (DataMapper 2) ist vielversprechend und baut auch auf AREL-Prinzipien auf!
quelle
Das Hinzufügen eines Index funktioniert für mich, ich verwende übrigens MySql.
quelle