2015-12-07 12 views
7

Perché i binari non popolano una colonna autoincrementante nell'elemento restituito da una creazione? C'è un modo migliore per farlo?Perché activerecord non popola una colonna autoincrementante nell'elemento restituito da una creazione?

in Rails, quando si esegue a = Foo.create poi a.id è popolata

Ma se si dispone di un campo che è stato creato tramite

def up 
    execute "ALTER TABLE my_table ADD COLUMN my_auto_incrementing_column INTEGER AUTO_INCREMENT not null UNIQUE KEY;" 
end 

Poi quel campo non viene visualizzato quando si utilizza creare. Devi anche usare una ricarica.

a = Foo.create 
a.id # not nil 
a.my_auto_incrementing_column # nil 
a.reload 
a.my_auto_incrementing_column # is now populated 

Informazioni Versione:

$ ruby -v 
ruby 1.9.3p484 (2013-11-22 revision 43786) [x86_64-darwin14.5.0] 
$ bundle exec rails -v 
Rails 3.2.12 
$ mysql --version 
mysql Ver 14.14 Distrib 5.6.26, for osx10.10 (x86_64) using EditLine wrapper 

Alcuni retroscena:

Questo codice viene applicato ad un grande esistente rotaie base di codice in-produzione che richiede che tutti i campi siano id UUID. La colonna auto_increment non è una chiave primaria, perché è stata aggiunta dopo aver scoperto che un nuovo partner di integrazione esterno non poteva gestire utilizzando i nostri identificatori univoci lunghi (UUID) esistenti.

Stiamo lavorando per aggiornare la nostra versione di ruby, ma non vogliamo aspettarla come soluzione a questo problema. Inoltre, dopo aver letto i changelog in activerecord, non ho ancora la prova che qualsiasi versione futura di ruby ​​/ rails conterrà un bugfix per questo problema.

Il codice che voglio migliorare:

class Foo < ActiveRecord::Base 
    has_one :object_containing_auto_incrementing_column 

    def my_method 
    if self.object_containing_auto_incrementing_column.nil? 
     self.object_containing_auto_incrementing_column = ObjectContainingAutoIncrementingColumn.create(owner: self) 
     self.object_containing_auto_incrementing_column.reload 
    end 
    self.object_containing_auto_incrementing_column.my_auto_incrementing_column 
    end 
end 
+0

Forse un duplicato di http://stackoverflow.com/a/9534482/531479 – CWitty

+0

@CWitty http://stackoverflow.com/questions/9513739/generate-an-auto-increment-field-in-rails/9534482 # 9534482 è stato molto utile nel progettare questa soluzione, ma non spiega perché le rotaie abbiano questo bug o come aggirarlo. Inoltre è basato su postgres, quindi alcuni dei consigli hanno una sintassi che non si applica. – compiledwrong

+1

Si prega di scoprire cosa 'SHOW CREATE TABLE' pensa che la tabella sia simile. Voglio vedere se activerecord ha tradotto correttamente ciò che ha detto il tuo codice. –

risposta

2

Dopo aver guardato il source code non sembra che ActiveRecord cerca per popolare le colonne incremento automatico. Assegna solo il valore restituito dall'istruzione INSERT all'attributo #id e nient'altro.

# ActiveRecord:: Persistence::ClassMethods 
def create 
# ... 
    self.id ||= new_id if self.class.primary_key 
# ... 
end 

Se si desidera popolare my_auto_incrementing_column senza colpire il DB due volte, penso che non v'è alcun modo per aggirare l'applicazione di patch ActiveRecord stessa.

Date un'occhiata a come il insert method è implementato:

# Returns the last auto-generated ID from the affected table. 
    # 
    # +id_value+ will be returned unless the value is nil, in 
    # which case the database will attempt to calculate the last inserted 
    # id and return that value. 
    # 
    # If the next id was calculated in advance (as in Oracle), it should be 
    # passed in as +id_value+. 
    def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = []) 
    sql, binds = sql_for_insert(to_sql(arel, binds), pk, id_value, sequence_name, binds) 
    value  = exec_insert(sql, name, binds) 
    id_value || last_inserted_id(value) 
    end 

potrebbe non esserci alcun modo banale per cambiare l'API corrente per popolare il campo in questione.

Problemi correlati