J'ai besoin d'ajouter des horodatages (created_at updated_at) à une table existante. J'ai essayé le code suivant mais cela n'a pas fonctionné. J'ai également essayé d'autres solutions que j'ai trouvées en ligne, mais elles ne fonctionnent pas non plus.
class AddTimestampsToUser < ActiveRecord::Migration
def change_table
add_timestamps(:users)
end
end
Comment puis-je le faire?
L'assistant d'horodatage est uniquement disponible dans le bloc create_table
. Vous pouvez ajouter ces colonnes en spécifiant les types de colonne manuellement:
class AddTimestampsToUser < ActiveRecord::Migration
def change_table
add_column :users, :created_at, :datetime, null: false
add_column :users, :updated_at, :datetime, null: false
end
end
Même si sa syntaxe abrégée n’est pas identique à celle de la méthode add_timestamps
que vous avez spécifiée ci-dessus, Rails continuera à traiter ces colonnes comme des colonnes d’horodatage et à mettre à jour les valeurs normalement.
Les migrations ne sont que deux méthodes de classe (ou méthodes d'instance dans 3.1): up
et down
(et parfois une méthode d'instance change
dans 3.1). Vous voulez que vos modifications entrent dans la méthode up
:
class AddTimestampsToUser < ActiveRecord::Migration
def self.up # Or `def up` in 3.1
change_table :users do |t|
t.timestamps
end
end
def self.down # Or `def down` in 3.1
remove_column :users, :created_at
remove_column :users, :updated_at
end
end
Si vous êtes dans la version 3.1, vous pouvez également utiliser change
(merci Dave):
class AddTimestampsToUser < ActiveRecord::Migration
def change
change_table(:users) { |t| t.timestamps }
end
end
Peut-être que vous confondez def change
, def change_table
et change_table
.
Voir le guide de migration pour plus de détails.
Votre code d'origine est très proche de la droite, il vous suffit d'utiliser un nom de méthode différent. Si vous utilisez Rails 3.1 ou une version ultérieure, vous devez définir une méthode change
au lieu de change_table
:
class AddTimestampsToUser < ActiveRecord::Migration
def change
add_timestamps(:users)
end
end
Si vous utilisez une version plus ancienne, vous devez définir les méthodes up
et down
au lieu de change_table
:
class AddTimestampsToUser < ActiveRecord::Migration
def up
add_timestamps(:users)
end
def down
remove_timestamps(:users)
end
end
class AddTimestampsToUser < ActiveRecord::Migration
def change
change_table :users do |t|
t.timestamps
end
end
end
Les transformations disponibles sont
change_table :table do |t|
t.column
t.index
t.timestamps
t.change
t.change_default
t.rename
t.references
t.belongs_to
t.string
t.text
t.integer
t.float
t.decimal
t.datetime
t.timestamp
t.time
t.date
t.binary
t.boolean
t.remove
t.remove_references
t.remove_belongs_to
t.remove_index
t.remove_timestamps
end
http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html
La réponse de @ user1899434 a révélé qu'une table "existante" pourrait signifier une table contenant déjà des enregistrements, des enregistrements que vous ne souhaitez peut-être pas supprimer. Ainsi, lorsque vous ajoutez des horodatages avec null: false, ce qui est la valeur par défaut et souvent souhaitable, ces enregistrements existants sont tous invalides.
Mais je pense que cette réponse peut être améliorée en combinant les deux étapes en une seule migration, ainsi qu'en utilisant la méthode plus sémantique de add_timestamps:
def change
add_timestamps :projects, default: Time.zone.now
change_column_default :projects, :created_at, nil
change_column_default :projects, :updated_at, nil
end
Vous pouvez remplacer DateTime.now
par un autre horodatage, par exemple si vous souhaitez plutôt que des enregistrements préexistants soient créés/mis à jour à la nuit tombée.
def change
add_timestamps :table_name
end
Nick Davies answer est le plus complet en termes d’ajout de colonnes d’horodatage à un tableau contenant des données existantes. Son seul inconvénient est qu'il soulèvera ActiveRecord::IrreversibleMigration
sur un db:rollback
.
Il devrait être modifié pour fonctionner dans les deux sens:
def change
add_timestamps :campaigns, default: DateTime.now
change_column_default :campaigns, :created_at, from: DateTime.now, to: nil
change_column_default :campaigns, :updated_at, from: DateTime.now, to: nil
end
J'ai créé une fonction simple que vous pouvez appeler pour ajouter à each table (en supposant que vous ayez une base de données existante) les champs created_at et updated_at :
# add created_at and updated_at to each table found.
def add_datetime
tables = ActiveRecord::Base.connection.tables
tables.each do |t|
ActiveRecord::Base.connection.add_timestamps t
end
end
add_timestamps (nom_table, options = {}) public
Ajoute les colonnes timestamps (created_at et updated_at) à nom_table. Des options supplémentaires (comme null: false) sont transmises à #add_column.
class AddTimestampsToUsers < ActiveRecord::Migration
def change
add_timestamps(:users, null: false)
end
end
Beaucoup de réponses ici, mais je posterai aussi les miennes car aucune des précédentes ne marchait vraiment pour moi :)
Comme certains l'ont noté, #add_timestamps
ajoute malheureusement la restriction null: false
, ce qui rendra les anciennes lignes non valides, car ces valeurs ne sont pas renseignées. La plupart des réponses suggèrent de définir une valeur par défaut (Time.zone.now
), mais je ne voudrais pas le faire car ces horodatages par défaut pour les anciennes données ne seront pas corrects. Je ne vois pas l'intérêt d'ajouter des données incorrectes à la table.
Donc ma migration était simplement:
class AddTimestampsToUser < ActiveRecord::Migration
def change_table
add_column :projects, :created_at, :datetime
add_column :projects, :updated_at, :datetime
end
end
Non null: false
, pas d'autres restrictions. Les anciennes lignes resteront valables avec created_at
comme NULL
et update_at
comme NULL
(jusqu'à ce qu'une mise à jour de la ligne soit effectuée). Les nouvelles lignes auront created_at
et updated_at
renseignés comme prévu.
Les réponses précédentes semblent correctes, mais je suis confronté à des problèmes si mon tableau contient déjà des entrées.
J'obtiendrais 'ERROR: column created_at
contient null
values'.
Pour réparer, j'ai utilisé:
def up
add_column :projects, :created_at, :datetime, default: nil, null: false
add_column :projects, :updated_at, :datetime, default: nil, null: false
end
J'ai ensuite utilisé gem migration_data pour ajouter l'heure des projets en cours sur la migration, tels que:
def data
Project.update_all created_at: Time.now
end
Tous les projets créés après cette migration seront alors correctement mis à jour. Assurez-vous également que le serveur est redémarré pour que Rails ActiveRecord
commence à suivre les horodatages de l'enregistrement.
C'est change
, pas change_table
pour Rails 4.2:
class AddTimestampsToUsers < ActiveRecord::Migration
def change
add_timestamps(:users)
end
end
je ne sais pas quand exactement cela a été introduit, mais dans Rails 5.2.1, vous pouvez le faire:
class AddTimestampsToMyTable < ActiveRecord::Migration[5.2]
def change
add_timestamps :my_table
end
end
pour plus d'informations, voir " en utilisant la méthode de modification " dans les documents de migration d'enregistrement actifs.
Pour ceux qui n'utilisent pas Rails mais utilisent activerecord, ce qui suit ajoute également une colonne à un modèle existant, par exemple un champ entier.
ActiveRecord::Schema.define do
change_table 'MYTABLE' do |table|
add_column(:mytable, :my_field_name, :integer)
end
end