23

Ho avuto una migrazione add_column che funzionava correttamente. Tuttavia, dopo averlo eseguito e acceso una console, troverei le colonne first_name e last_name completamente vuote. Ho provato ad utilizzare save! invece e ha avuto lo stesso effetto - nessun errore segnalato. Ecco l'originale:Rails 3.1: impossibile scrivere nella colonna nella stessa migrazione che lo aggiunge

class UserAddFirstNameAndLastName < ActiveRecord::Migration 
    def change 
    # add column first name, last name string 
    add_column :users, :first_name, :string 
    add_column :users, :last_name, :string 

    User.all.each do |u| 
     u.first_name = 'first name' 
     u.last_name = 'last name' 
     u.save 
    end 
    end 
end 

Ho anche pensato che questo potrebbe essere qualche problema di caricamento delle classi, così ho inserito la linea User per forzare la classe utente per ricaricare prima del ciclo. Niente da fare.

Quando ho suddiviso questo in due migrazioni, l'effetto desiderato è stato raggiunto. Qualcuno ha una spiegazione per questo? Giuro di averlo fatto anche nello stesso progetto con le migrazioni passate.

Altre note: Devise per il motore utente, ha aggiunto le nuove colonne a attr_accessible in Classe utente prima di eseguire la migrazione.

+1

mu è troppo breve ha una risposta fantastica per spiegare cosa sta succedendo e cosa fare ma ti consigliamo anche di suddividere questi due in diverse migrazioni. Crea colonne in una, inseriscile in un'altra. Ciò impedisce il problema che stai vedendo e rende i rollback meno soggetti a errori. –

risposta

37

Si sta caricando la classe Utenti da qualche parte prima della migrazione, quindi User è un po 'confuso sulla propria struttura. La soluzione è di chiamare reset_column_information dopo aver aggiunto la colonna:

Ripristina tutte le informazioni memorizzate nella cache relative alle colonne, che causeranno il loro ricaricamento alla richiesta successiva.

Il modello di utilizzo più comuni per questo metodo è probabilmente in una migrazione, quando subito dopo la creazione di una tabella che si desidera popolarlo con alcuni valori di default

La sezione Using Models in Your Migrations del Migrations Guide potrebbe essere la pena dare un'occhiata anche.

provare a rotolare indietro e con una migrazione come questo:

def change 
    # add column first name, last name string 
    add_column :users, :first_name, :string 
    add_column :users, :last_name, :string 

    User.reset_column_information 

    User.all.each do |u| 
    u.first_name = 'first name' 
    u.last_name = 'last name' 
    u.save 
    end 
end 

ho controllato questo con tre migrazioni come questo:

# 1: Don't touch Model before the new columns. 
def change 
    add_column :models, :some_column, :string 
    Model.all.each { |m| m.some_column = 'pancakes'; m.save } 
end 

# 2: Pull in Model before adding the new columns. 
def change 
    puts Model.all.count 
    add_column :models, :some_column, :string 
    Model.all.each { |m| m.some_column = 'pancakes'; m.save } 
end 

# 3: Pull in Model before adding the new columns but use reset_column_information 
def change 
    puts Model.all.count 
    add_column :models, :some_column, :string 
    Model.reset_column_information 
    Model.all.each { |m| m.some_column = 'pancakes'; m.save } 
end 

Il primo funziona bene, il secondo si aggiunge some_column ma lo lascia con valori NULL, anche il terzo funziona.

Direi che qualcosa nell'inizializzazione dell'applicazione (probabilmente da Devise) sta causando il caricamento di Utente e del suo schema, quindi si aggiunge una colonna. Ma, a quanto pare, l'Utente conosce solo parzialmente la nuova colonna mentre la chiamata u.first_name funziona ma qualcosa viene memorizzato nella cache all'interno dell'Utente per impedire che l'attributo venga scritto nel database.

+0

Confermato che questo era il problema con un avvertimento. Ho appena usato il tuo primo e il terzo esempio insieme in un'unica migrazione. Il primo non è stato salvato nel database. Ho grep'd la nostra cartella DB e avevo ragione su prima - ho vecchie migrazioni con salvataggi come questo. Qualcosa che abbiamo aggiunto al nostro progetto sta causando il precaricamento dei modelli prima delle migrazioni ... Sospetto che potrebbe essere la gemma 'active_reload'. Non abbiamo ancora aggiornato a Rails 3.2 ma ho notato che questa è una funzionalità standard ora. Spero di confermare/confutare questo con test se ho tempo. –

+0

@Eric: Qualcosa nella tua inizializzazione sta pre-caricando la tua classe del modello. (1) ha funzionato per me perché nulla nella mia inizializzazione è in grado di precaricare nulla; il 'mette Model.all.count' in (2) e (3) è solo un modo semplice per simulare il precaricamento che sta accadendo nel tuo ambiente. 'active_reload' sembra un probabile sospetto. Aggiungere 'reset_column_information' se si altera e si usa un modello in una migrazione è probabilmente una buona abitudine. –

+0

Questo non funziona in Rails 4. –