17
mit

The Rails guides to active record migrations sagt, dass Sie tun können,Reversible Migration für change_column_default aus keine Standard in Rails

change_column_default :products, :approved, from: true, to: false 

ich eine change Methode in Rails haben, die der folgenden ähnlich ist:

change_column_default :people, :height, from: nil, to: 0 

mit der Absicht, keine Standardwerte zu haben, sondern einen Standardwert von Null zu haben.

Allerdings, wenn ich es wieder versuchen, rollen, erhalte ich

ActiveRecord::IrreversibleMigration: ActiveRecord::IrreversibleMigration 

bedenkt, dass ich geben Rails ein from und to, warum es nicht zu akzeptieren?

Ich verwende Rails 4.2.0.

+0

Könnte es sein, dass Rails versucht, eine Art Zwangsproblem zu vermeiden? – max

+0

http://stackoverflow.com/questions/7098602/add-a-default-value-to-a-column-through-a-migration – max

+0

Ich sehe keine 'from' oder' to' Parameter in der [Methodendefinition] (http://api.rubyonrails.org/classes/ActiveRecord/ConnectionA) dapters/PostgreSQL/SchemaStatements.html # method-i-change_column_default) –

Antwort

7

Der mit der Frage verknüpfte Leitfaden bezieht sich auf Edge Rails, nicht auf eine freigegebene Version von Rails.

Die reversible Syntax für change_column_default ist das Ergebnis der Pull-Anforderung 20018. Die Pull-Anforderung aktualisierte auch die Rails-Guides für Edge Rails.

Von activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb:

-  def change_column_default(table_name, column_name, default) 
+  # Passing a hash containing +:from+ and +:to+ will make this change 
+  # reversible in migration: 
+  # 
+  # change_column_default(:posts, :state, from: nil, to: "draft") 
+  # 
+  def change_column_default(table_name, column_name, default_or_changes) 

Die Pull-Request 27. Juni gemacht wurde, 2015, die jünger sind als jede Version von Rails am 1. August veröffentlicht ist 2015

Die Dokumentation für migration for Rails 4.2.3 spiegelt die Tatsache, dass reversible Syntax noch nicht verfügbar ist:

change_column_default :products, :approved, false 
-3

Wenn Sie versuchen, den Datentyp in diesem Fall von value (0) auf nil herunterzustufen, wird rails diesen Fehler melden. Weil es Daten verlieren könnte

Ein anderes Beispiel würde gehen von string ->integer.

ist dies ein wirklich good article explain the same

UPDATE

Es scheint, wie Ihre Reverse Migration change_column_default in command_recorder(activerecord-4.2.0/lib/active_record/migration/command_recorder.rb#76) bitte Anrufe überprüfen, ob Sie die nil als Standardwert gesetzt.

UPDATE2

es stellt sich heraus, dass, wenn Sie change in Migrationen verwenden, müssen die in der Lage sein

reversible aber change_column ist nicht reversibel durch change Methode. So finden Sie die alten Schienen Migrationsmethode mit up und down

Lesen Sie diesen Artikel erklären die scenario

+1

'0' und' nil' sind keine Datentypen. Sie haben auch das allgemeine Konzept einer irreversiblen Migration erwähnt, aber Sie erklären nicht, warum diese Änderung eine irreversible Migration wäre. –

+0

Wo hätte ich 'nil' als Standardwert eingestellt? –

+0

@AndrewGrimm, ein weiteres Update :) – sameera207

0

allererst als Jonathan Allard sagte der from und to sind nicht in der Methode Quelle verwenden müssen, was bedeutet, dass die change_column_default akzeptiert es nicht. Es ist einfach so:

def sum(a) 
    return a 
end 

Nun, wenn Sie versuchen, zwei Variablen, um es passieren wie sum(a, b) oder irgendetwas wird es dieses Recht nicht akzeptieren. Dies versuchen Sie oben unter Verwendung von from und to.

Nun ist die korrekte Syntax hierfür ist:

change_column_default(:people, :height, 0) 

Verfahren nicht from und to nicht akzeptiert (wie sie als solche definiert ist, auch wenn sie Hash-Schlüssel sind, wenn die Methode nicht Gebrauch macht das Schlüsselwertpaar irgendwo, dann nützt es nichts, und wenn es eine neue Spalte ist, hat es offensichtlich den Standardwert nil (wenn nicht vorher gesetzt) ​​und nehme an, ob die Spalte height if vom Typ integer ist und du gibst es als Standard an Wert a wird es 0 als Standardwert (nicht 100% sicher, aber habe versucht, dies von Rails-Konsole zu tun). Es ist für Schienen nicht wichtig, was der Standardwert ist, es braucht nur den neuen Standardwert. Wenn also der aktuelle Standardwert 0 ist und Sie ihn auf nil einstellen, wird dies nicht beanstandet. Es ist Ihre Datenbank und Sie möchten, was damit zu tun ist. Nur wenn die Datenbank es unterbricht, wenn Sie etwas falsch machen, wie das Zuweisen string zu boolean dann wird es offensichtlich Fehler werfen.

Jetzt, nachdem diese Migration ausgeführt wurde, wird jetzt der Standardwert auf 0 gesetzt. Rails weiß nicht, was der vorherige Standardwert war. Wie es weg ist und es nirgends gespeichert hat. Deshalb ist change_column_default eine irreversible Migration. Und wenn Sie versuchen, es zurückzurollen, gibt es im Fall von change Methode. Bedeutet, wenn Sie verwendet haben:

def change 
    change_column_default(:people, :height, 0) 
end 

So deshalb für diese Art von Migrationen wir die Methode up und down verwenden:

def up 
    change_column_default(:people, :height, 0) 
end 

def down 
    change_column_default(:people, :height, nil) 
end 

Hoffnung, das hilft.

+0

'from: nil, to: 0' ist das gleiche wie' {: from => nil,: to => 0} ', was ein einzelnes Objekt ist. –

+0

Eigentlich glaube ich, dass Sie meinen Punkt nicht verstanden haben, die 'change_column_default' akzeptiert nur einen einzigen Wert für den Standardwert der Spalte, jetzt schreiben Sie' from: nil', so dass kein Code in der Quelle geschrieben ist welches deine 'from: nil' und' to: 0' verarbeitet. – Deep

14

, wenn Sie mysql als Adapter verwenden, dann nach diesem Link http://apidock.com/rails/ActiveRecord/ConnectionAdapters/AbstractMysqlAdapter/change_column_default, läuft Ihre change_column_default Migration wie diese

def change_column_default(table_name, column_name, default) #:nodoc: 
column = column_for(table_name, column_name) 
change_column table_name, column_name, column.sql_type, :default => default 
end 

so, wie Sie es nennt change_column in sich selbst sehen, wenn Sie change_column_default anrufen und nach diesem Link http://edgeguides.rubyonrails.org/active_record_migrations.html change_column Migration ist irreversibel.

Dies zeigt, warum Sie ActiveRecord::IrreversibleMigration: ActiveRecord::IrreversibleMigration

Also, wenn man Sie mit der Migration mit change_column_default ausführen möchten haben def up und def down hinzuzufügen.

Ich würde vorschlagen, change_column zu verwenden, da es bereits in change_column_default aufgerufen wurde.

def up 
change_column :people, :height, :integer, default: 0 
end 

def down 
change_column :people, :height, :integer, default: nil 
end 
+1

Diese Antwort ist nicht perfekt, aber es ist besser als die anderen Antworten (offensichtlich kann ich das Kopfgeld nicht mir selbst vergeben). –

+0

ja @AndrewGrimm Sie haben Recht bezüglich der perfekten Antwort. Ich habe http://edgeguides.rubyonrails.org/ als Referenz hinzugefügt, die noch nicht veröffentlicht wurde. Noch zum Hinzufügen von Informationen habe ich diesen Link http://api.rubyonrails.org/classes/ActiveRecord/Migration/CommandRecorder.html überprüft, um die Liste der reversiblen Migrationen zu sehen. und ich sehe 'change_column' ist nicht in der Liste verfügbar. zuletzt danke für die Prämie und danke für Ihre Antwort. hilfreich..:) – Athar

0

Ab Oktober 2016, Diese Funktion (mit to: und für change_column_default reversibel sein) ist jetzt auf dem 5.x-Zweig verfügbar. Leider ist es nicht verfügbar 4.2.x oder niedriger. :(

Überprüfung:.. git tag --contains f9c841927ac3d1daea2a9cebf08b18e844e5eec5 in den Schienen-Projekt

0

einfach ein paar Punkte hinzufügen Wenn Sie mit der Rails-Version stecken nicht umkehrbar change_column_default unterstützen, ist eine Option über das Problem zu erhalten, ist:

def change 
    # If your dataset is small, just cache in memory, if large, consider file dump here: 
    cache = Table.all 
    # Full column def important for reversibility 
    remove_column :table, :column, :type, { config_hash } 
    # Re-add the column with new default: 
    add_column :table, :column, :type, { config_hash, default: 0 } 
    # Now update the data with cached records (there might be more efficient ways, of course): 
    cache.each do |rec| 
     Table.find(rec.id).update(column: rec.column) 
    end 
end