2013-06-30 4 views
13

Ich möchte eine Spalte namens "payment_type" in meine Tabelle "orders" einfügen. HierSpalte zu Tabelle hinzufügen und Wert für vorhandene Datensätze in Rails fixieren

ist die Migration, die ich bisher haben:

def change 
    add_column :orders, :payment_type, :string 
end 

Ich möchte, dass payment_type den Wert „normal“ für alle Datensätze zu halten, die sich derzeit in der DB sind. Jedoch nicht für die zukünftigen Aufzeichnungen. Ich möchte keinen Standardwert für zukünftige Datensätze. Wie kann ich das machen?

Antwort

30

Wie Sie nur Werte festlegen möchten für alle vorhandene Datensätze, können Sie update_all verwenden, die als Schleifen über viel schneller ist, alle Instanzen der Ordnung, da es nur Datenbankanweisungen verwendet und nicht Instanciate alle die Aufträge:

def up 
    add_column :orders, :payment_type, :string 
    Order.reset_column_information 
    Order.update_all(payment_type: 'normal') 
end 

def down 
    remove_column :orders, :payment_type 
end 

update_all ruft keine Validierungen oder Trigger.

+7

Ich würde empfehlen, die Haupt-Order-Klasse nicht zu verwenden, stattdessen sollten Sie eine Stub-Order-Klasse innerhalb Ihrer Migrationen definieren, sonst werden die Migrationen in Zukunft nicht mehr funktionieren, wenn die Order-Klasse nicht mehr existiert. –

+1

Auch Sie können ändern Methode anstelle von oben und unten Methoden. dies oben Block wird auf def add_column ändern ändern: Aufträge,: payment_type,: string Order.reset_column_information Order.update_all (payment_type: 'normal') Ende – Amit

+0

sorry, ich falsch Kommentar geschrieben, 'change' funktioniert . –

2
def change 
    add_column :orders, :payment_type, :string 
    Order.all.each do |order| 
    order.update_attributes(:payment_type => 'normal') 
    end 
end 
+0

Gut zu wissen, dass Sie dies in der Methode 'change' tun können, und müssen nicht schreiben trennen nach oben und unten Methoden. – contradictioned

+2

Ich weiß, das ist super alt, aber es ist nicht ratsam, ActiveRecord innerhalb von Migrationen zu verwenden. Ihre Modelle sind auf dem neuesten Stand, sobald Sie klonen, aber während der Migration befindet sich Ihre Datenbank in einem älteren Zustand. Wenn einige Änderungen in der Zukunft auftraten, in denen Order ein default_scope erhalten hatte, konnten alle Datensätze nicht aktualisiert werden (obwohl das default_scope beim Erstellen der Migration nicht vorhanden war). –

0

Wenn Sie mit der Migration auf aktuelle Spalte Stick wollen dann über Antworten genial, Aber wenn Sie möchten Spalte aktualisieren, die lokal auf dem eigenen Rechner, so dass, wenn Sie Code teilen dann andere sind nicht in der Lage das aktualisierte Attribut, um zu sehen, einfach gehen zu Rails-Konsole und Schleife ...

orders = Order.all 

orders.each do |o| 
    o.update_attribute(:payment_type, 'normal') 
end 

Rails 4

+1

auch in der Konsole, verwenden Sie 'Order.update_all (payment_type: 'normal')', es sei denn, Sie benötigen Validierungen (in diesem einfachen Fall nicht sehr wahrscheinlich). Es ist viel schneller, siehe oben, und es ist ein One-Liner. –

+0

awww, es ist cool genug, Danke, up-vote für Ihre obige Antwort, es ist auch brilliant ... – Awais

1

ich denke, der einfachste Weg, es zu tun:

class AddStateToSites < ActiveRecord::Migration[5.1] 
     def up 
     add_column :sites, :state, :string, default: :complete # sets default value for existed records 
     change_column :sites, :state, :string, default: nil # changes default value for next 
     end 

     def down 
     remove_column :sites, :state 
     end 
    end 

Und nach, dass es in der Konsole überprüfen:

>> Site.last.state 
    Site Load (0.6ms) SELECT "sites".* FROM "sites" ORDER BY "sites"."id" DESC LIMIT $1 [["LIMIT", 1]] 
=> "complete" 
>> Site.new.state 
=> nil 
0

Wie andere erwähnt haben es nicht gute Praxis auf Klassen verlassen, die in der Zukunft entfernt werden, da es würde Bremse die Migration zu diesem Zeitpunkt .

Stattdessen verwenden, um ich direkt roh mySQL ausführen:

execute "UPDATE `orders` SET `payment_type` = 'normal'" 
Verwandte Themen