2012-01-30 18 views
7

私は2つのモデルを持っています:割引は多くのBusinssesに属しています。before_saveアソシエーションコールバックで検証エラーを追加する方法

割引は、少なくとも1つのビジネスと、別の条件(たとえば、active?)を常に持っていることを検証したいと考えています。私は、次のことを試してみました:

class Discount < ActiveRecord::Base 
    has_and_belongs_to_many :businesses, 
    before_remove: :validate_publish_status 

    def validate_publish_status(*arg) 
    if active? && businesses.count == 0 
     errors[:active] << 'discount with no business' 
    end 
    end 
end 

しかし、これは動作しません(検証エラーが発生しません)、私はそれが唯一のコールバックではなく、検証であるので、これはおそらくであることに気づきました。どのようにコード化すれば、私はカスタム検証のようにerrorsを使用できますか?

(AJAX用)私が持っているコントローラのアクションは:

def remove 
    @business = Business.find(params[:business_id]) 
    if @business.in? @discount.businesses 
     @discount.businesses.delete(@business) 
    end 
    render json: @business.as_json(only: [:id, :type, :name, :address], 
            methods: [:city_name, :country_name]). 
     merge(paths: paths_for(@discount, @business)) 
    rescue ActiveRecord::RecordInvalid # even tried the generic Exception 
    respond_to do |f| 
     f.json { render json: {error: $!.message}, status: 403 } 
    end 
    end 

答えて

8

before_removeコールバックに関する構文や、検証メソッド自体で起こっていることがあります。また、コールバックメソッドにデバッグコードを追加して、それがそこに作成されているかどうかを確認することもできます。

※トランザクションは、コールバックメソッドで例外が発生した場合にのみ停止されることに注意してください。

class Discount < ActiveRecord::Base 
    has_and_belongs_to_many :businesses, :before_remove => :validate_publish_status 

    def validate_publish_status(*args) 
    if yyy? && businesses.count == 0 
    errors.add(:yyy,'discount with no business') 
    raise "Unable to remove business." 
    end 
    end 

end 

コントローラの要旨:

def update 
    @company.find(params[:id]) 
    if @company.update_attributes(params[:company]) 
     ... 
    else 
     render :action => 'edit' 
    end 
    rescue 
    render :action=>'edit' 
    end 

Association Callback Documentation.

+0

ありがとう、私はチェックしたし、メソッドを実行しました。私が ''エラー 'を発生させるなら、それは予想どおりにエラーを発生させるでしょう。 – lulalala

+0

私はいくつかの情報で答えを更新しました。トランザクションを停止するには、コールバックで例外を発生させます。これを行うには、おそらくコントローラで何らかの例外処理を行い、アクションを再レンダリングしたいと思うでしょう。 – miked

+2

また、falseを返して実行を停止することもできます。すべてのコールバック・チェーンがトランザクションでラップされています。コールバック・メソッドが正確にfalseを戻すか、例外を発生させると、実行チェーンが停止し、ROLLBACKが発行されます。 http://guides.rubyonrails.org/active_record_validations_callbacks.html#halting-execution – amree

2

あなたはこのため:presence => truevalidatesメソッドを使用することができます。関連バリデータに:presence => trueを使用

class Discount < ActiveRecord::Base 
    has_and_belongs_to_many :businesses 
    validates :businesses, :presence => true 
end 

は、関連の少なくとも1人のメンバーが存在することを保証します。

+0

おかげでこのようなケースがあるので、あなたはおそらく、アクションを再描画するために、あなたのコントローラ内で例外ロジックを処理したいと思いますそのバリデーションで1つの追加フィールドをチェックする必要があります(yyy?part)。だから私はカスタム検証を書く必要があります。 – lulalala

+1

あなたの質問を編集して、あなたが探しているものをより正確に説明できますか?あなたはyyyについて何も言及していないか、またはあなたの説明にあると思われるものについては何も言及していません。あなたのコードからyyyで何をしようとしているのかは分かりません。 –

+0

私の悪い、私はyyyを言い換えましたか?アクティブに?しかし、これはbooleanと評価される任意の式である可能性があります。 – lulalala

関連する問題