11

私はこれらのモデルを持っています:

class Organisation < ActiveRecord::Base

  has_many    :people
  has_one     :address, :as         => :addressable,
                        :dependent  => :destroy
  accepts_nested_attributes_for :address, :allow_destroy => true

end

class Person < ActiveRecord::Base

  attr_accessible :first_name, :last_name, :email, :organisation_id, :address_attributes

  belongs_to  :user
  belongs_to  :organisation
  has_one     :address, :as         => :addressable,
                        :dependent  => :destroy
  accepts_nested_attributes_for :address, :allow_destroy => true

  # These two methods seem to have no effect at all!
  validates_presence_of :organisation,  :unless => "address.present?"
  validates_associated  :address,       :unless => "organisation.present?"

end

class Address < ActiveRecord::Base

  belongs_to :addressable, :polymorphic => true

  validates_presence_of :line1, :line2, :city, :zip

end

...そしてこれらのビュー:

_fields.html.erb :

<%= render 'shared/error_messages', :object => f.object %>
<fieldset>
<div class="left">
    <%= f.label :first_name %><br/>
    <%= f.text_field :first_name %>
</div>
<div>
    <%= f.label :last_name %><br/>
    <%= f.text_field :last_name %>
</div>
<div>
    <%= f.label :email %><br/>
    <%= f.text_field :email %>
</div>
<div>
    <%= f.label :organisation_id %><br/>
    <%= f.select(:organisation_id, current_user.organisation_names, {:include_blank => "--- None ---"}, :id => 'organisation_select') %>
</div>
</fieldset>

<%= f.fields_for :address do |address| %>
  <%= render 'shared/address', :f => address %>
<% end %>

_address.html.erb:

<fieldset id="address_fields">
<div>
    <%= f.label :line1 %>
    <%= f.text_field :line1 %>
</div>
<div>
    <%= f.label :line2 %>
    <%= f.text_field :line2 %>
</div>
<div>
    <%= f.label :zip %>
    <%= f.text_field :zip %>
</div>  
<div>
    <%= f.label :city %>
    <%= f.text_field :city %>
</div>  
</fieldset>

people_controller.rb :

def new
  puts params.inspect
  @person = Person.new(:organisation_id => params[:organisation_id])
  @person.build_address
  @title = "New person"
end

{"action"=>"new", "controller"=>"people"}

def edit
  puts params.inspect
  @title = @person.name
end

{"action"=>"edit", "id"=>"69", "controller"=>"people"}

def create
  puts params.inspect
  if params[:organisation_id]
    @person = current_user.organisations.build_person(params[:person])
  else
    @person = current_user.people.build(params[:person])
  end
  if @person.save
    flash[:success] = "Person created."
    redirect_to people_path
  else
    render :action => "new"
  end
end

{"commit"=>"Create", "action"=>"create", "person"=>{"last_name"=>"Doe", "organisation_id"=>"9", "email"=>"john.doe@email.com", "first_name"=>"John", "address_attributes"=>{"city"=>"Chicago", "zip"=>"12345", "line2"=>"Apt 1", "line1"=>"1 Main Street"}}, "authenticity_token"=>"Jp3XVLbA3X1SOigPezYFfEol0FGjcMHRTy6jQeM1OuI=", "controller"=>"people", "utf8"=>"✓"}

Person私のモデル内では、人物organisation_idが空白の場合にのみ、その人物の住所フィールドが存在する必要があることを確認する必要があります。

私はこのようなことを試しました:

validates :address, :presence => true, :if => "organisation_id.blank?"

しかし、それは機能していません。

これはどのように行うことができますか?

助けてくれてありがとう。

4

3 に答える 3

33

まず第一に、あなたがblank?ではなくを意味していることを確認したいのですpresent?。通常、次のように表示されます。

validate :address, :presence_of => true, :if => 'organisation.present?'

つまり、組織も存在する場合にのみ住所を検証する必要があります。

に関して、:accepts_nested_attributes_forネストされたフォーム属性を渡すことによってこの機能を使用していますか、またはそのようなことですか? この機能を絶対に使用する必要があることを確認したいだけです。ネストされたフォーム属性を実際に扱っていない場合は、次を使用してカスケード検証を実装できます。

validates_associated :address

を使用する必要がある場合は:accepts_nested_attributes、必ずパラメーターを確認して:reject_ifください。基本的に、特定の条件が適用される場合、属性 (およびその子孫) の追加を完全に拒否できます。

accepts_nested_attributes_for :address, :allow_destroy => true, :reject_if => :no_organisation

def no_organisation(attributes)
  attributes[:organisation_id].blank?
end

上記のいずれにも当てはまらない場合は、構文を見てみましょう。

動作し、シンボル、文字列、および procs:if/:unlessを取る必要があります。foreign_key を指す必要はありませんが、以下を指すことで簡略化できます。

:if => "organisation.blank?"

Address モデルには他の検証がありますね。望まないときに Address が検証されていますか? または、アドレスが検証されていませんか? 追加の詳細を教えていただければ、コンソールでテストするお手伝いをいたします。


  1. 自分自身で物事を簡単にするために:大量割り当て、レール構成を変更しました:config.active_record.whitelist_attributes = false
  2. あなたがフォローするための要点を作成しました
  3. サンプルプロジェクトもあります。興味があれば教えてください。

    基本的なポイント:

  4. Org または Address が有効であることを確認するために、以下を Person に追加しました。

    validates_presence_of :organisation, :unless => "address.present?" validates_associated :address, :unless => "organisation.present?"

  5. Org が存在しない場合にエラーをトリガーするように Address に検証を追加しました。 validates_presence_of :line1, :line2, :city, :zip

    ご要望に沿ったものを作ることができました。私が作成した Gist を見てください。完全なコンソール テスト計画があります。


以前の gist にコントローラ ファイルを追加しました。

概要:

  1. 個人を作成するために必要なのは、次のとおりです。 @person = current_user.people.build(params[:person])
  2. :organisation_id は、次のように :person パラメータ ノードから常に検出され params[:person][:organisation_id] ます。

controllermodel、およびformに必要な変更を加えて要点を更新しました。

概要:

  1. コントローラーをクリーンアップする必要があります。を使用してaccepts_nested_attributeいるため、:create では のみを気にしparams[:person]ます。さらに、 ではrender :new、パーシャルが使用するインスタンス変数をセットアップする必要があります。これはアクションを介して戻ることはありません:new。およびアクションも簡素化する必要があります:new:edit
  2. :reject_ifAddress フィールドが :create アクションに返されるため、Person モデルは引数を使用する必要があります:address_attributes => {:line1 => '', :line2 => '', etc}。値がある場合にのみ関連付けを作成します。その後、validates_presence_offor:organisationは正常に機能します。
  3. フォームは、組織名ではなく、組織 ID をコントローラーに渡す必要があります

    それはすべて要点にあります


最終的な要旨である必要があります。

概要:

  1. @person を作成した直後に、編集アクションに以下を追加します。

    @person.build_address の場合、@person.address.nil? これにより、@person.address が存在しない場合でも、アドレス入力が確実に得られます。accept_nested_attributes の :reject_if 条件のため、存在しません

  2. :reject_if を次のように DRY しました。少しハックですが、いくつかのユーティリティがあります。

    accepts_nested_attributes_for :address, :allow_destroy => true, :reject_if => :attributes_blank?
    
    def attributes_blank?(attrs)  
      attrs.except('id').values.all?(&:blank?)  
    end  
    

    a. attrs-> params[:person][:address] の結果
    b. .except('id')-> 「id」を除くすべてのキー値を返します
    c. .values-> ハッシュからすべての値を配列として返す
    d. .all?-> 配列内のすべての要素が次のチェックを満たしているか
    e. &:blank-> ブロックの ruby​​ 短縮形、次のように:all?{ |v| v.blank? }

于 2012-10-07T19:52:56.367 に答える
0

あなたは本当に意味がありませんでした:

validates :address, :presence => true, :if => organisation_id.nil?
于 2012-10-07T15:20:52.593 に答える