2011-02-10 4 views
1

私は、単一テーブル継承を使用し、異なるタイプ(学期または学期のどちらかの学年)のモデルを持っており、各タイプには独自の検証があります。ユーザーがレコードのタイプを変更しようとすると、ドロップダウンからどの年度タイプを選択して変更することができます。しかし、ユーザーが型を変更した場合、新しいクラスの検証を実行する方法と古い検証を実行する方法を理解できません。次のように例えば、私のコードは次のとおりです。今年のタイプは学期で、ユーザーは四半期にそれを変更した場合タイプの列を使用して、レコードのタイプを変更し、正しいクラスのバリデーションをレールで実行するにはどうすればよいですか?

@school_year = SchoolYear.find(params[:id]) 
respond_to do |format| 
    if SchoolYear::SUBCLASSES.include? params[:school_year]['type'] 
    @school_year[:type] = params[:school_year]['type'] 
    else 
    raise "Invalid type" 
    end 

    if @school_year.update_attributes(params[:school_year]) 
    # done 
    else 
    # validation problem? 
    end 

は今、私はQuarterSchoolYearの検証は、学期のそれらの実行としないことを期待しています。コードを変更して動作させるにはどうすればよいですか?

答えて

3

タイプを変更した後にオブジェクトをリロードする必要があります。 'type'属性に新しい値を代入しても、オブジェクトのルビクラスは変更されません。もちろん、型変更の直後にオブジェクトを保存すると、古いバリデーションが使用されます。

データベースの型属性を更新し、オブジェクトを読み込もうとすることがあります。以下のような 何か:

[..] 
if type_differs_and_is_acceptable_to_change 
    SchoolYear.update_all(
    ['type = ?', params[:shool_year][:type] ], 
    ['id = ?',@school_year.id ] 
) 
    @school_year = SchoolYear.find(@school_year.id) 
end 
if @school_year.update_attributes... 

は持っているようにしてください:このクラスのattr_accessibleにタイプではありません。

それ以外にも、オブジェクトの種類を変更するのは少し気になりますが、それは私の個人的な恐怖かもしれません。 :)

1

検証を実行するには、正しいタイプのモデルでインスタンス化する必要があります。私は新しいタイプで保存し、再びそれを見つけることを除いて、これを行う方法が表示されない:

new_type = params[:school_year]['type'] 
@school_year[:type] = new_type 
@school_year.save! 
@school_year = new_type.constantize.find(@school_year.id) 
@school_year.update_attributes(params[:school_year]) 

update_attributes場合は、タイプの変更をロールバックできるようあなたはおそらく、トランザクションでこれを入れたいと思います失敗する。

+0

トランザクションで実際には保存されず、検索が失敗するため、urコードの4行目で失敗します。 – umar

+0

「実際に取引でそれを保存しない」という意味はどうですか? 'save!'は例外を発生させますか? – zetetic

+0

私が意味することは、トランザクションに2つ以上の「保存」を入れ、トランザクション内でクラッシュしないと、すべてが書き込まれ、それ以外の場合は書き込まれないということです。トランザクション中に、「保存」を書いてそれを見つけようとすると、まだ実際には書き込まれていないので、それを見つけることができず、メモリからのアクセス以外はアクセスできません。その行は実際に行3で変更されていないので、行4のurコードのfindは失敗します。このアプローチはうまくいきません – umar

3

これは古かったですが、@ Arsen7の提案に基づいて改良されました。オブジェクトを新しいタイプとして再ロードする最も良い方法は、以下のActiveRecordメソッドを使用することです(これは非常に理由があります)その型を変更した後にオブジェクトを保存する必要があります。この方法では、データベースに2回ヒットすることはありません。

[..] 
if type_differs_and_is_acceptable_to_change 
    @school_year.type = params[:school_year][:type] 
    @school_year = @school_year.becomes(@school_year.type.constantize) 
end 
if @school_year.update_attributes... 
+1

これは完全に機能します。私はタイプを変更し、保存を実行する検証を強制することができます! –

関連する問題