기존 테이블에 타임 스탬프 추가


173

기존 테이블 에 타임 스탬프 ( created_at& updated_at) 를 추가해야 합니다. 다음 코드를 시도했지만 작동하지 않았습니다.

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

답변:


211

타임 스탬프 도우미는 create_table블록 에서만 사용할 수 있습니다 . 열 유형을 수동으로 지정하여 이러한 열을 추가 할 수 있습니다.

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

add_timestamps위에서 지정한 방법 과 동일한 간결한 구문 이 없지만 Rails는 여전히 이러한 열을 타임 스탬프 열로 취급하고 값을 정상적으로 업데이트합니다.


10
Rails 4에서는이 기능이 작동하지 않았습니다. 아래의 "mu is too short"솔루션이 작동합니다.
newUserName 여기

21
rails g migration AddTimestampsToUser created_at:datetime updated_at:datetime-위의 마이그레이션을 생성하는 바로 가기입니다.
Konstantine Kalbazov

2
PG::NotNullViolation: ERROR: column "created_at" contains null value 테이블에 null 제약 조건을 위반하지 않는 데이터가 이미 포함되어 있기 때문에이 마이그레이션을 실행하면 오류가 발생 합니다. 처음에는 null이 아닌 제약 조건을 제거한 다음 나중에 추가하는 것보다 더 좋은 방법은 무엇입니까?
M. Habib

1
@ M.Habib 그렇게 생각하지 않지만 이 답변 은 한 번의 마이그레이션으로 모든 것을 잘 캡슐화합니다.
littleforest

1
@ M.Habib은 당신이 할 수있는 기본값에 가장 적합한 것으로 생각하는 것에 달려 있습니다 add_column :users, :updated_at, :datetime, null: false, default: Time.zone.now. Time.zone.now예를 들어, 논리에 적합한 값을 사용해야합니다.
Delong Gao

91

마이그레이션은 두 가지 클래스 메소드 (또는 3.1의 인스턴스 메소드) updown(그리고 때로는 change3.1 의 인스턴스 메소드)입니다. 변경 사항이 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

3.1에 있다면 changeDave를 사용할 수도 있습니다 .

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

아마 당신은 혼란하고 def change, def change_table하고 change_table.

자세한 내용은 마이그레이션 안내서 를 참조 하십시오.


1
( change이 경우에는 문제가 아니지만 지금 방법이 있습니다.)
Dave Newton

@Dave : 사실, 나는 버전 문제를 피하기 위해 일반적으로 갔지만 change언급 할 가치가 있으므로 그것을 추가 할 것입니다.
mu는 너무 짧습니다

진정한 뮤 그러나 나는 그것이 3.1로 실제로 바뀌고 있으며 '다운'이 실제로 사라지고 있다고 들었습니다. 다운 방법을 자동으로 알아내는 레일. 그것에 대해 들었습니까?
Michael Durrant

@ Michael : 저는 현재 작업중 인 3.1 앱에서만 MongoDB를 사용하고있어 3.1 AR 마이그레이션으로 작업하지 않았습니다. 문서는 모든 것이 인스턴스 메소드로 이동하고 있음을 나타냅니다 (알 수없는 이유로).
mu는 너무 짧아

@MichaelDurrant, "변경"이 현재 다루지 않는 많은 시나리오가 있습니다. 위 / 아래로 가면 화난 사람들이있을 것입니다 :) 이 말을 철회 ...) 당신 이이 의견을 말한 후 3 년이 지난 후에도 나는 그것이 바뀌고 있다고 생각하지 않습니다. :)
frandroid

76

원래 코드는 매우 가까이에 있으므로 다른 메소드 이름 만 사용해야합니다. Rails 3.1 이상을 사용하는 경우 다음 change대신 메소드 를 정의해야합니다 change_table.

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

이전 버전을 사용하는 경우 대신 다음 updown대신 메소드 를 정의해야합니다 change_table.

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

  def down
    remove_timestamps(:users)
  end
end

59

@ user1899434의 응답은 여기에 "기존"테이블이 이미 레코드가 포함 된 테이블을 의미 할 수 있다는 사실에서 발견되었습니다. 따라서 기본값 인 null 인 false : false를 사용하여 타임 스탬프를 추가하면 기존 레코드가 모두 유효하지 않습니다.

그러나 두 단계를 하나의 마이그레이션으로 결합하고보다 의미있는 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

DateTime.now대신 새벽에 기존 레코드를 생성 / 업데이트하려는 경우와 같이 다른 타임 스탬프를 대신 사용할 수 있습니다.


2
놀랄 만한. 감사합니다! 한 가지 참고 사항- Time.zone.now코드가 올바른 시간대를 준수하도록하려면 사용해야합니다.
John Gallagher

4
Time.zone.now마이그레이션을 실행할 때 생성 된 Time 인스턴스를 반환하고 해당 시간을 기본값으로 사용한다는 기본값을 설정하는 데 문제 가 있습니다. 새로운 객체는 새로운 Time 인스턴스를 얻지 못합니다.
Tovi Newman

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

사용 가능한 변환은

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의 답변 은 기존 데이터가있는 테이블에 타임 스탬프 열을 추가 할 때 가장 완벽합니다. 그것의 유일한 단점은 그것이 올릴 것입니다 ActiveRecord::IrreversibleMigration켜짐 db:rollback.

양방향으로 작동하도록 수정해야합니다.

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.2.7 (내 생각에 나를 위해 작성된이 정확하게 작동하지 않았다 change_column_default지원하지 않습니다 fromto해당 버전에?),하지만이 아이디어를 가져다가 만든 up/down대신 하나의 방법 change방법과 마법처럼 일했다!
gar


4

이것이 정확히 언제 도입되었는지 확실하지 않지만 레일 5.2.1에서 다음을 수행 할 수 있습니다.

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

자세한 내용 은 활성 레코드 마이그레이션 문서에서 " 변경 방법 사용 " 참조하십시오 .


나는 마이그레이션과 함께 작동하지 않았다 [5.1]; 그런 다음 숫자를 [5.2]로 변경했고 Rails는 5.1, 5.0 또는 4.2 만 사용할 수 있다고 말했습니다. 나는 성공으로 5.0을 시도한 다음 성공으로 4.2를 시도했다.
Ma 님

옛날, 나도 알아,하지만 당신은 기존 레코드가있는 경우 추가 : , null: true애프터:my_table
jomar

2

created_atupdated_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

add_timestamps (table_name, 옵션 = {}) 공개

타임 스탬프 (created_at 및 updated_at) 열을 table_name에 추가합니다. 추가 옵션 (예 : null : false)은 #add_column으로 전달됩니다.

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

1

이전 답변은 옳은 것처럼 보이지만 테이블에 이미 항목이 있으면 문제가 발생했습니다.

'오류 : 열에 값이 created_at포함되어 null있습니다'.

수정하기 위해 다음을 사용했습니다.

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

그런 다음 gem migration_data 를 사용 하여 마이그레이션과 같은 현재 프로젝트의 시간을 추가했습니다.

def data
  Project.update_all created_at: Time.now
end

그런 다음이 마이그레이션 후에 생성 된 모든 프로젝트가 올바르게 업데이트됩니다. Rails ActiveRecord가 레코드의 타임 스탬프 추적을 시작 하도록 서버도 다시 시작해야합니다 .


1

여기에 많은 답변이 있지만 이전 게시물 중 어느 것도 실제로 나를 위해 일하지 않았기 때문에 내 게시물도 게시 할 것입니다. :)

일부 사람들이 지적했듯이 #add_timestamps불행히도 null: false제한을 추가하면 이러한 값이 채워지지 않아 오래된 행이 유효하지 않게됩니다. 대부분의 답변은 기본값 ( Time.zone.now)을 설정하는 것이 좋지만 이전 데이터의 기본 타임 스탬프가 올바르지 않기 때문에 그렇게하고 싶지 않습니다. 테이블에 잘못된 데이터를 추가 할 때 값이 표시되지 않습니다.

그래서 나의 이주는 간단했습니다.

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

아니요 null: false, 다른 제한 사항이 없습니다. 이전 행은 created_atas NULLupdate_atas 로 계속 유효 NULL합니다 (행에 일부 업데이트가 수행 될 때까지). 새 행이 예상대로 채워 created_at지고 updated_at채워집니다.


1

여기에 대부분의 답변이있는 문제는 Time.zone.now모든 레코드 를 기본값으로 사용 하면 마이그레이션이 기본 시간으로 실행 된 시간을 가질 것입니다. 레일 5에서는 대신을 사용할 수 있습니다 now(). 마이그레이션이 실행 된 시간과 새로 삽입 된 레코드에 대한 커밋 트랜잭션의 시작 시간으로 기존 레코드의 타임 스탬프가 설정됩니다.

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


1

Time.current좋은 스타일을 사용 하는 것은 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

또는

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

기존 테이블에 타임 스탬프를 추가하는 간단한 방법입니다.

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

0

Rails를 사용하지 않고 activerecord를 사용하는 사람들을 위해 다음은 기존 모델에 열을 추가합니다 (예 : 정수 필드).

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

0

그건 change아니, change_table레일 4.2 :

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

0

이것은 Rails 5.0.7의 깨끗한 솔루션 인 것 같습니다 (change_column_null 메서드 발견).

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을 사용하고 있으며 이러한 옵션 중 어느 것도 작동하지 않았습니다.

효과가 있었던 유일한 유형은 : datetime이 아닌 : timestamp입니다.

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

-1

나는 개인적으로 다음을 사용했으며 현재 시간 / 날짜로 모든 이전 레코드를 업데이트했습니다.

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

Rails 5에서 같은 문제가 발생했습니다.

change_table :my_table do |t|
    t.timestamps
end

다음을 사용하여 타임 스탬프 열을 수동으로 추가 할 수있었습니다.

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

이것은 항상 마이그레이션이 실행되는 시간으로 기본값을 설정하지 않습니까? (실제로 DB가 처리하는 동적 타임 스탬프가 아님)
Guillaume Petit

db에 이미 존재하는 레코드의 경우 예, created_at 및 updated_at을 마이그레이션이 실행 된 날짜로 설정합니다. 그래도 그 값을 가지지 않고, idk는 어떻게 그 값을 초기화 할 수 있을까요. 편집 : 그것은 단지 행의 역사의 시작으로 간주됩니다
안드레스 로살레스를
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.