2017-01-10 2 views
0

나는 이벤트 테이블과 세션 테이블을 가지고 있습니다. 이벤트 has_many 세션, 이것은 협회입니다. 이제 세션 테이블의 time_zone 열을 이벤트 테이블로 이동하려고합니다. 그렇다면 마이그레이션의 도움으로 어떻게해야합니까? 세션 테이블의 time_zone에 대한 기존 레코드를 이벤트 테이블로 이동하려면 어떻게합니까?레일 마이그레이션의 데이터로 열 업데이트

답변

-1

다음 마이그레이션을 사용하면됩니다.

class Test < ActiveRecord::Migration 
    def change 
    add_column :events, :time_zone, :string 

    Event.all.each do |e| 
     e.update_attributes(time_zone: e.sessions.last.time_zone) 
    end 

    remove_column :sessions, :time_zone 
    end 
end 
+0

마이그레이션 할 때 모델을 사용하면 안됩니다. 콜백, 유효성 검사 등을 트리거 할 수 있으며 시간에 따라 변경할 수 있습니다 (예 : 6 개월 후에 모델을 삭제하면 이전이 중단됨). –

1

먼저 동일한 이벤트와 연결된 세션이 동일한 표준 시간대를 유지해야합니다. 그와 관련된 시간대의 수에 event_id 매핑 해시를 반환합니다

Session.group(:event_id).count(:time_zone) 

이 : 당신은이 작업을 수행 할 수 있습니다. 이 번호는 항상 하나 여야합니다.

둘째로, 새로운 코드가 생산 중이며 얼마 동안 작동 한 후에 별도의 마이그레이션에서 을 추가하고 사용을 시작하여 sessions.time_zone을 제거하는 것이 좋습니다. 나는 이전에 모델을 재정의

class AddTimeZoneToEvents < ActiveRecord::Migration 
    class Event < ActiveRecord::Base; end 
    class Session < ActiveRecord::Base; end 

    def up 
    # Add a NULLable time_zone column to events. Even if the column should be 
    # non-NULLable, we first allow NULLs and will set the appropriate values 
    # in the next step. 
    add_column :events, :time_zone, :string 

    # Ensure the new column is visible. 
    Event.reset_column_information 

    # Iterate over events in batches. Use #update_columns to set the newly 
    # added time_zone without modifying updated_at. If you want to update 
    # updated_at you have at least two options: 
    # 
    # 1. Set it to the time at which the migration is run. In this case, just 
    #  replace #update_columns with #update! 
    # 2. Set it to the maximum of `events.updated_at` and 
    #  `sessions.updated_at`. 
    # 
    # Also, if your database is huge you may consider a different query to 
    # perform the update (it also depends on your database). 
    Event.find_each do |event| 
     session = Session.where(event_id: event.id).last 
     event.update_columns(time_zone: session.time_zone) 
    end 

    # If events don't always need to have time zone information then 
    # you can remove the line below. 
    change_column_null :events, :time_zone, false 
    end 

    def down 
    remove_column :events, :time_zone 
    end 
end 

참고 :

셋째, 다음과 같이한다 events.time_zone를 추가 할 수있는 마이그레이션 (I 명확성에 대한 몇 가지 의견을 추가). 그 이유는 다음과 같습니다.

  1. 원본 모델에 콜백 및 유효성 검사가 적용될 수 있습니다 (물론 건너 뛸 수 있지만 값이 0 인 추가주의 사항).
  2. 도로를 6 개월 만에 모델을 제거하면 마이그레이션이 중단됩니다.

변경 사항이 예상대로 작동하면 sessions.time_zone을 제거 할 수 있습니다. 오류가 발생하면 위의 마이그레이션을 롤백하고 작업 버전을 쉽게 복원 할 수 있습니다.

+0

이것은 작동합니다. 다운 된 경우 세션 테이블에서 time_zone을 복원 할 수있는 방법이 없어야합니까? – Nikhil

+0

** sessions.time_zone을 제거하지 ** 않았습니다 **. 마지막 단락을 참조하십시오. - 먼저 새 열로 마이그레이션하고 코드에서 사용하도록 설정하고 작동하면 이전 열을 제거하는 것이 좋습니다. 데이터베이스 저장소가 저렴하기 때문에 서두를 필요가 없습니다. –

+0

아 .. 그 부분을 놓쳤습니다.이 다음에 도움이됩니다. events_sessions 테이블과 같은 연결을 저장하기 위해 세 번째 테이블을 만드는 것이 합리적일까요? – Nikhil