14

次のモデルを使用して Rails 3.2 アプリケーションを開発しています。

class User < ActiveRecord::Base
  # Associations
  belongs_to :authenticatable, polymorphic: true

  # Validations
  validates :authenticatable, presence: true # this is the critical line
end

class Physician < ActiveRecord::Base
  attr_accessible :user_attributes

  # Associations
  has_one :user, as: :authenticatable
  accepts_nested_attributes_for :user
end

私がやろうとしているのは、ユーザーが常に認証可能な親を持っているかどうかを検証することです。これ自体は問題なく動作しますが、私のフォームでは、ユーザー モデルは認証対象が存在しないと不平を言っています。

次のコントローラーを使用して、ユーザーのネストされた属性を受け入れる新しい医師のフォームを表示しています。

def new
  @physician = Physician.new
  @physician.build_user

  respond_to do |format|
    format.html # new.html.erb
    format.json { render json: @physician }
  end
end

そして、これは私の作成方法です:

def create
  @physician = Physician.new(params[:physician])

  respond_to do |format|
    if @physician.save
      format.html { redirect_to @physician, notice: 'Physician was successfully created.' }
      format.json { render json: @physician, status: :created, location: @physician }
    else
      format.html { render action: "new" }
      format.json { render json: @physician.errors, status: :unprocessable_entity }
    end
  end
end

フォームを送信すると、ユーザーの認証可能なものを空にしてはならないことが示されます。ただし、authenticatable_id とauthenticatable_type は、@physician保存後すぐに割り当てる必要があります。同じフォームを使用して医師とそのユーザーを編集すると、id とタイプが割り当てられるため、問題なく動作します。

ここで何が間違っていますか?

4

5 に答える 5

8

私はこれが期待されていると信じています:

https://github.com/rails/rails/issues/1629#issuecomment-11033182 (最後の 2 つのコメント)。

rails apiからこれもチェックしてください:

1 対 1 の関連付け

オブジェクトを has_one 関連付けに割り当てると、外部キーを更新するために、そのオブジェクトと置き換えられるオブジェクト (存在する場合) が自動的に保存されます (親オブジェクトが保存されていない場合を除く (new_record? == true))。

これらの保存のいずれかが (オブジェクトの 1 つが無効なために) 失敗した場合、ActiveRecord::RecordNotSaved 例外が発生し、割り当てがキャンセルされます。

オブジェクトを保存せずに has_one アソシエーションに割り当てたい場合は、build_association メソッド (以下に記載) を使用します。置き換えられるオブジェクトは、その外部キーを更新するために引き続き保存されます。

外部キー フィールドが親に属しているため、belongs_to 関連付けにオブジェクトを割り当てても、オブジェクトは保存されません。親も保存しません。

この

build_association(attributes = {}) 属性でインスタンス化され、外部キーを介してこのオブジェクトにリンクされているが、まだ保存されていない関連型の新しいオブジェクトを返します。

最初に親を作成する必要があります。次に、その ID をポリモーフィック オブジェクトに割り当てます。

私が見る限り、ユーザーを構築するオブジェクト Physician.new を作成しますが、この時点ではまだ保存されていないため、ID がないため、ポリモーフィック オブジェクトに割り当てるものはありません。したがって、検証は保存前に呼び出されるため、常に失敗します。

つまり、あなたの場合、 build_user を呼び出すと、 User.new NOT User.create が返されます。したがって、authenticatable には、authenticatable_id が割り当てられていません。

いくつかのオプションがあります:

  • 最初に関連付けられたユーザーを保存します。

    また

  • 検証を after_save コールバックに移動します (可能ですが、非常に面倒で悪いです)

    また

  • アプリの構造を変更してください - おそらくポリモーフィックな関連付けを避けて、has_many に切り替えますか? 内部とビジネス要件がわからないため、判断するのは難しいです。しかし、これはポリモーフィック アソシエーションの良い候補ではないように思えます。認証できるモデルは User だけではありませんか?

IMHO ポリモーフィック アソシエーションの最適な候補は、電話、住所などです。住所は、ユーザー、顧客、会社、組織、Area51 などに属することができ、ホーム、配送、または請求のカテゴリになります。つまり、複数の用途に対応するためにMORPHできるため、抽出するのに適したオブジェクト。しかし、Authenticatable は少し不自然で、必要のないところに複雑さを加えているように思えます。認証可能である必要がある他のオブジェクトはありません。

認証可能なモデルとその理由、そして移行 (?) を提示できれば、さらにアドバイスできます。今、私はこれを何もないところから引っ張り出しているところです :-) しかし、リファクタリングの良い候補のようです。

于 2013-06-20T15:23:57.383 に答える
3

検証を before_save コールバックに移動するだけで問題なく動作します。

class User < ActiveRecord::Base
  # Associations
  belongs_to :authenticatable, polymorphic: true

  # Validations
  before_save :check_authenticatable

  def check_authenticatable
    unless authenticatable
      errors[:customizable] << "can't be blank"
      false
    end
  end
end
于 2014-02-17T13:25:12.057 に答える
-1

これで問題が解決するかどうかはわかりませんが、ポリモーフィックな親が存在することを検証するときに、このようなものを使用します。

これは、多形関連としてのvideoモデルで使用したコードです。parentこれは入ったvideo.rb

  validates_presence_of :parent_id, :unless => Proc.new { |p|
      # if it's a new record and parent is nil and addressable_type is set
      # then try to find the parent object in the ObjectSpace
      # if the parent object exists, then we're valid;
      # if not, let validates_presence_of do it's thing
      # Based on http://www.rebeccamiller-webster.com/2011/09/validate-polymorphic/
      if (new_record? && !parent && parent_type)
        parent = nil
        ObjectSpace.each_object(parent_type.constantize) do |o|
          parent = o if o.videos.include?(p) unless parent
        end
      end
      parent
    }
于 2013-01-28T06:57:57.717 に答える