Varolan bir tabloya zaman damgaları ekleme


173

Varolan bir tabloya zaman damgaları ( created_at& updated_at) eklemeniz gerekir . Aşağıdaki kodu denedim ama işe yaramadı.

class AddTimestampsToUser < ActiveRecord::Migration
    def change_table
        add_timestamps(:users)
    end
end

Yanıtlar:


211

Zaman damgası yardımcısı yalnızca create_tableblokta kullanılabilir. Sütun türlerini manuel olarak belirterek bu sütunları ekleyebilirsiniz:

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

Bu, add_timestampsyukarıda belirttiğiniz yöntemle aynı kısa sözdizimine sahip olmasa da , Rails yine de bu sütunlara zaman damgası sütunları olarak davranır ve değerleri normal olarak güncelleştirir.


10
Bu Rails 4 benim için işe yaramadı. "Mu çok kısa" tarafından aşağıdaki çözüm çalışıyor.
newUserNameHere

21
rails g migration AddTimestampsToUser created_at:datetime updated_at:datetime- yukarıdaki taşımayı oluşturmak için bir kısayol.
Konstantine Kalbazov

2
PG::NotNullViolation: ERROR: column "created_at" contains null value Tablonuz zaten boş kısıtlamayı ihlal eden veriler içerdiğinden, bu geçişin çalıştırılması hataya neden oluyor . Bunu yapmanın daha iyi bir yolu, önce boş olmayan kontratı kaldırmak ve sonra eklemek.
M. Habib

1
@ M.Habib Ben öyle düşünmüyorum, ama bu cevap hepsini tek bir göçte güzelce içeriyor .
littleforest

1
@ M.Habib, yapabileceğiniz varsayılan değer için en anlamlı olanın ne olduğuna bağlıdır add_column :users, :updated_at, :datetime, null: false, default: Time.zone.now. Time.zone.nowsadece bir örnek, mantığınız için anlamlı olan her değeri kullanmalısınız.
Delong Gao

91

Taşıma işlemleri yalnızca iki sınıf yöntemidir (veya 3.1'deki örnek yöntemler): upve down(ve bazen change3.1'deki bir örnek yöntemidir). Değişikliklerinizin upyönteme geçmesini istiyorsunuz :

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

3.1 yılında iseniz o zaman da kullanabilirsiniz change(teşekkürler Dave):

class AddTimestampsToUser < ActiveRecord::Migration
  def change
    change_table(:users) { |t| t.timestamps }
  end
end

Belki karıştırıyorsun def change, def change_tableve change_table.

Daha fazla ayrıntı için taşıma kılavuzuna bakın.


1
(Peki, changeşimdi yöntem var, ancak bu durumda, sorun değil :)
Dave Newton

@Dave: Yeterince doğru, sürüm sorunlarından kaçınmak için genel için gittim ama changebahsetmeye değer, bu yüzden ben de ekleyeceğim.
mu çok kısa

Doğru mu ama bunun 3.1 ile gerçekten değiştiğini duydum ve 'aşağı' gerçekten gidiyor. Aşağı yöntemi otomatik olarak bulmak için raylar. Bunu duydun mu?
Michael Durrant

@Michael: MongoDB'yi sadece üzerinde çalıştığım 3.1 uygulamasıyla kullanıyorum, bu yüzden 3.1 AR geçişi ile çalışmadım. Dokümanlar, her şeyin örnek yöntemlere doğru ilerlediğini gösterir (bilinmeyen nedenlerle).
mu çok kısa

@MichaelDurrant, şu anda "değişim" in kapsamadığı pek çok senaryo var, eğer yukarı / aşağı giderseniz bazı kızgın insanlar olacak :) Bu geri dönüşü ...) Bu yorumu yaptıktan 3 yıl sonra bile, bunun değiştiğini sanmıyorum. :)
frandroid

76

Orijinal kodunuz sağa çok yakın, sadece farklı bir yöntem adı kullanmanız gerekiyor. Rails 3.1 veya üstünü kullanıyorsanız, aşağıdakiler changeyerine bir yöntem tanımlamanız gerekir change_table:

class AddTimestampsToUser < ActiveRecord::Migration
  def change
    add_timestamps(:users)
  end
end

Eski bir sürüm kullanıyorsanız aşağıdakileri tanımlamanız upve downyöntemleriniz gerekir change_table:

class AddTimestampsToUser < ActiveRecord::Migration
  def up
    add_timestamps(:users)
  end

  def down
    remove_timestamps(:users)
  end
end

59

@ user1899434'ün yanıtı, buradaki "mevcut" bir tablonun, içinde zaten kayıtların bulunduğu bir tablo, bırakmak istemeyebileceğiniz kayıtlar olabileceği gerçeğini aldı. Bu nedenle, varsayılan ve genellikle istenen null: false ile zaman damgaları eklediğinizde, varolan bu kayıtların tümü geçersizdir.

Ancak, iki adımı bir geçişte birleştirerek ve daha semantik add_timestamps yöntemini kullanarak bu cevabın geliştirilebileceğini düşünüyorum:

def change
  add_timestamps :projects, default: Time.zone.now
  change_column_default :projects, :created_at, nil
  change_column_default :projects, :updated_at, nil
end

DateTime.nowÖnceden varolan kayıtların zamanın başlangıcında oluşturulmasını / güncellenmesini istiyorsanız, bunun yerine başka bir zaman damgasını kullanabilirsiniz.


2
İnanılmaz. Teşekkür ederim! Sadece bir not - Time.zone.nowkodumuzun doğru saat dilimine uymasını istiyorsak ne kullanmamız gerektiğidir.
John Gallagher

4
Varsayılanın ayarlanmasında bir sorun vardır Time.zone.now; bunun nedeni, taşıma çalıştırıldığında oluşturulan Time örneğini döndürmesi ve bu zamanı varsayılan olarak kullanmasıdır. Yeni nesneler yeni bir Zaman örneği almaz.
Tovi Newman

38
class AddTimestampsToUser < ActiveRecord::Migration
  def change
    change_table :users do |t|
      t.timestamps
    end
  end
end

Mevcut dönüşümler

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


10

Nick Davies yanıtı , mevcut verileri içeren bir tabloya zaman damgası sütunları ekleme açısından en eksiksiz yanıttır . Tek dezavantajı, ActiveRecord::IrreversibleMigrationa db:rollback.

Her iki yönde de çalışacak şekilde değiştirilmelidir:

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

Bu tam olarak benim için Rails 4.2.7 (sanmıyorum ve bu sürümde change_column_defaultdesteklemiyor mu?) Yazdığı gibi çalışmadı , ama bu fikri aldım ve tek bir yöntem yerine yöntemler oluşturdum ve bir cazibe gibi çalıştı! fromtoup/downchange
gar


4

tam olarak ne zaman tanıtıldığından emin değilim, ancak raylar 5.2.1'de bunu yapabilirsiniz:

class AddTimestampsToMyTable < ActiveRecord::Migration[5.2]
  def change
    add_timestamps :my_table
  end
end

daha fazla bilgi için etkin kayıt taşıma belgelerindeki " değişiklik yöntemini kullanma " konusuna bakın .


Göç ile çalışmasını sağlayamadım [5.1]; daha sonra bu sayıyı [5.2] olarak değiştirdim ve Rails bana yalnızca 5.1, 5.0 veya 4.2 kullanabileceğimi söyledi. Ben 5.0 ile, sonra 4.2 ile başarı ile denedim.
Ma

Eski, biliyorum, ancak mevcut kayıtlarınız varsa ekleyin:, null: true:my_table
jomar

2

Ben her tabloya (varolan bir veritabanı var varsayalım) oluşturulan_at ve updated_at alanları eklemek için arayabilirsiniz basit bir işlev yaptı :

  # 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

add_timestamps (tablo_adı, seçenekler = {}) herkese açık

Tablo_adı'na zaman damgaları (created_at ve updated_at) sütunları ekler. Ek seçenekler (null: false gibi) # add_column öğesine yönlendirilir.

class AddTimestampsToUsers < ActiveRecord::Migration
  def change
    add_timestamps(:users, null: false)
  end
end

1

Önceden cevaplar doğru görünüyor ancak masamın girişleri varsa sorunlarla karşılaştım.

'HATA: sütun değerleri created_atiçerir ' alırım null.

Düzeltmek için kullandım:

def up
  add_column :projects, :created_at, :datetime, default: nil, null: false
  add_column :projects, :updated_at, :datetime, default: nil, null: false
end

Sonra taş kullanılan migration_data göç gibi güncel projeler için saat eklemek için:

def data
  Project.update_all created_at: Time.now
end

Bu geçişten sonra oluşturulan tüm projeler doğru şekilde güncellenecektir. Sunucunun da yeniden başlatıldığından emin olun, böylece Rails ActiveRecordkayıttaki zaman damgalarını izlemeye başlar.


1

Burada bir sürü cevap var, ama benimkini de göndereceğim çünkü öncekilerden hiçbiri gerçekten benim için çalışmadı :)

Bazılarının belirttiği gibi, #add_timestampsmaalesef null: falsebu satırları doldurmadıkları için eski satırların geçersiz olmasına neden olacak kısıtlamayı ekler . Çoğu yanıt burada bazı varsayılan değer ( Time.zone.now) ayarlamanızı öneririz , ancak eski veriler için bu varsayılan zaman damgaları doğru olmayacağı için bunu yapmak istemiyorum. Tabloya yanlış veri ekleme değeri görmüyorum.

Bu yüzden göçüm basitçe:

class AddTimestampsToUser < ActiveRecord::Migration
  def change_table
    add_column :projects, :created_at, :datetime
    add_column :projects, :updated_at, :datetime
  end
end

Hayır null: false, başka kısıtlama yok. Eski satırlar created_atas NULLve update_atas ile geçerli olmaya devam eder NULL(satıra bir miktar güncelleme yapılana kadar). Yeni satırlar beklendiği gibi doldurulur created_atve updated_atdoldurulur.


1

Buradaki yanıtların çoğuyla ilgili sorun, Time.zone.nowtüm kayıtlara varsayılan olarak geçişin varsayılan zamanları olarak çalıştırıldığı zamana sahip olmasıdır, bu da muhtemelen istediğiniz şey değildir. Raylarda 5 kullanabilirsiniz now(). Bu, geçişin çalıştırıldığı zaman ve yeni eklenen kayıtlar için tamamlama işleminin başlangıç ​​zamanı olarak mevcut kayıtların zaman damgalarını ayarlar.

class AddTimestampsToUsers < ActiveRecord::Migration def change add_timestamps :users, default: -> { 'now()' }, null: false end end


1

Kullanımı Time.currentiyi bir stildir https://github.com/rubocop-hq/rails-style-guide#timenow

def change
  change_table :users do |t|
    t.timestamps default: Time.current
    t.change_default :created_at, from: Time.current, to: nil
    t.change_default :updated_at, from: Time.current, to: nil
  end
end

veya

def change
  add_timestamps :users, default: Time.current
  change_column_default :users, :created_at, from: Time.current, to: nil
  change_column_default :users, :updated_at, from: Time.current, to: nil
end

1

Bu, varolan tabloya zaman damgası eklemek için basit bir yöntemdir.

class AddTimeStampToCustomFieldMeatadata < ActiveRecord::Migration
  def change
    add_timestamps :custom_field_metadata
  end
end

0

Rails kullanmayan ancak activerecord kullananlar için, aşağıdakiler mevcut bir modele bir sütun ekler, örnek bir tamsayı alanı içindir.

ActiveRecord::Schema.define do
  change_table 'MYTABLE' do |table|
    add_column(:mytable, :my_field_name, :integer)
  end
end

0

O var changedeğil, change_tableRaylar 4.2 için:

class AddTimestampsToUsers < ActiveRecord::Migration
  def change
    add_timestamps(:users)
  end
end

0

Bu, Rails 5.0.7'de temiz bir çözüm gibi görünüyor (change_column_null yöntemini keşfetti):

def change
  add_timestamps :candidate_offices, default: nil, null: true
  change_column_null(:candidate_offices, :created_at, false, Time.zone.now)
  change_column_null(:candidate_offices, :created_at, false, Time.zone.now)
end

0

Rails 5.0'dayım ve bu seçeneklerin hiçbiri işe yaramadı.

İşe yarayan tek şey şu şekilde kullanmaktı: timestamp ve not: datetime

def change
    add_column :users, :created_at, :timestamp
    add_column :users, :updated_at, :timestamp
end

-1

Şahsen aşağıdakileri kullandım ve önceki tüm kayıtları güncel saat / tarih ile güncelledi:

add_column :<table>, :created_at, :datetime, default: Time.zone.now, null: false
add_column :<table>, :updated_at, :datetime, default: Time.zone.now, null: false

-2

Aynı sorunu Rails 5 kullanmaya çalıştım

change_table :my_table do |t|
    t.timestamps
end

Zaman damgası sütunlarını aşağıdakilerle manuel olarak ekleyebildim:

change_table :my_table do |t|
    t.datetime :created_at, null: false, default: DateTime.now
    t.datetime :updated_at, null: false, default: DateTime.now
end

bu her zaman varsayılan değeri taşıma işleminin yapıldığı saatle ayarlamaz mı? (yani DB tarafından ele alınan dinamik bir zaman damgası değil)
Guillaume Petit

db'nizde zaten var olan kayıtlar için, evet, oluşturulan_at ve updated_at öğelerini geçişin çalıştırıldığı tarihe ayarlar. Bu değerlere önceden sahip olmadan, bu değerleri başka nasıl başlatacağınızı idk. EDIT: O satır tarihinin başlangıcı olarak kabul edilir
Andres Rosales
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.