web-dev-qa-db-fra.com

Ajouter des horodatages à une table existante

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?

150
leonel

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.

189
Ben Simpson

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.

85
mu is too short

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
68
georgebrock
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

37
Pradeep Sanjaya

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.

36
Nick Davies
def change
  add_timestamps :table_name
end
8
Ian Vaughan

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
4
lightyrs

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
2
Roger

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
2
almawhoob

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.

1
Kostis

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.

1
dbrody

C'est change, pas change_table pour Rails 4.2:

class AddTimestampsToUsers < ActiveRecord::Migration
  def change
    add_timestamps(:users)
  end
end
0
Igor T.

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.

0
Reef Loretto

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
0
peter