23

うまく動作するadd_columnの移行がありました。しかし、それを実行し、コンソールを起動した後、私はfirst_name列とlast_name列が完全に空であることがわかります。代わりにsave!を使ってみましたが、同じ効果がありました。エラーは報告されていませんでした。ここでは、元のです:Rails 3.1:同じマイグレーションで追加したカラムに書き込むことができません

class UserAddFirstNameAndLastName < ActiveRecord::Migration 
    def change 
    # add column first name, last name string 
    add_column :users, :first_name, :string 
    add_column :users, :last_name, :string 

    User.all.each do |u| 
     u.first_name = 'first name' 
     u.last_name = 'last name' 
     u.save 
    end 
    end 
end 

私はまた、これはいくつかのクラスローディングの問題かもしれないと思ったので、私はループの前に再ロードするユーザークラスを強制的に行Userを挿入しました。サイコロはありません。

これを2つの移行に分割すると、目的の効果が達成されました。誰かがこれについて説明していますか?過去の移行で同じプロジェクトでこれをやったことを誓っています。

その他の注意事項:ユーザーエンジンの開発者は、移行を実行する前にユーザークラスのattr_accessibleに新しい列を追加しました。

+1

muが短すぎます。何が起こっているのか、何をすべきかを説明する素晴らしい答えがありますが、これらの2つを異なる移行に分割することもおすすめします。 1つの列を作成し、別の列に作成します。これにより、表示されている問題を回避し、ロールバックのエラーを少なくします。 –

答えて

37

あなたの移行が実行される前にどこかでUsersクラスをロードしていますので、Userはそれ自身の構造についてちょっと混乱しています。解決策は、列を追加した後にreset_column_informationに電話することです。

次の要求で再読み込みされる列に関するすべてのキャッシュ情報をリセットします。

この方法の最も一般的な使用パターンはいくつかのデフォルト値

とあなたがそれを移入するテーブルを作成した後Migrations GuideUsing Models in Your Migrationsセクションは一見の価値があるかもしれないときには、移行におそらくあります同じように。

はロールバックし、このような移行を使用してみてください:

def change 
    # add column first name, last name string 
    add_column :users, :first_name, :string 
    add_column :users, :last_name, :string 

    User.reset_column_information 

    User.all.each do |u| 
    u.first_name = 'first name' 
    u.last_name = 'last name' 
    u.save 
    end 
end 

私はこのような3つのマイグレーションでこれを確認:最初のものは二つsome_columnを追加し、うまく動作します

# 1: Don't touch Model before the new columns. 
def change 
    add_column :models, :some_column, :string 
    Model.all.each { |m| m.some_column = 'pancakes'; m.save } 
end 

# 2: Pull in Model before adding the new columns. 
def change 
    puts Model.all.count 
    add_column :models, :some_column, :string 
    Model.all.each { |m| m.some_column = 'pancakes'; m.save } 
end 

# 3: Pull in Model before adding the new columns but use reset_column_information 
def change 
    puts Model.all.count 
    add_column :models, :some_column, :string 
    Model.reset_column_information 
    Model.all.each { |m| m.some_column = 'pancakes'; m.save } 
end 

が、それにNULL値を残すと、3番目のものも動作します。

私はあなたのアプリケーションの初期化(おそらくDeviseから)によってユーザーとそのスキーマがロードされていると推測して、列を追加します。しかし、明らかに、ユーザーはu.first_name呼び出しが動作するときに新しい列について部分的にしか知りませんが、属性がデータベースに書き込まれないようにユーザー内に何かがキャッシュされています。

+0

これが1つの注意点の問題であることを確認しました。 1回のマイグレーションで、最初の例と3つ目の例を一緒に使用しました。最初のものはデータベースに保存されませんでした。私はDBフォルダをgrep'dしていました。私はこれまでと同じように保存されていました。私たちのプロジェクトに追加したものは、マイグレーションの前にモデルをプリロードすることです...私は 'active_reload'という宝石かもしれないと思います。私たちはまだRails 3.2にアップグレードしていませんが、これは今標準的な機能であることがわかりました。私は時間があればテストでこれを確認/反論したいと思う。 –

+0

@Eric:初期化中の何かがモデルクラスをプリロードしています。 (1)私のために働いたのは、私の初期設定では何もプリロードしていないからです。 'はModel.allを置きます。(2)と(3)の「count」は、あなたの環境で行われているプリロードをシミュレートする簡単な方法です。 'active_reload'は疑わしい疑いのある容疑者のように聞こえます。あるマイグレーションでモデルを変更して使用する場合、 'reset_column_information'を追加することは、おそらく良い習慣です。 –

+0

これはRails 4では機能しません。 –

関連する問題