6

デバイスとアクティブな商人を使用して登録を作成しようとしています。ユーザー オブジェクトが次のようになるという点で、フォームは複雑です。

class User < ActiveRecord::Base
  include ActiveMerchant::Utils

  # Include default devise modules. Others available are:
  # :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable, 
         :recoverable, :rememberable, :trackable, :validatable, :omniauthable

  # Setup accessible (or protected) attributes
  attr_accessible :email, :password, :password_confirmation, :remember_me, :username, :first_name, 
                  :subscription_attributes, :last_name, :zipcode, 
                  :payment_profile_attributes, :customer_cim_id, :payment_profile_id

...

  # Track multi-page registration
  attr_writer :current_step

...

  # Setup Payment Profile element (authorize.net billing profile)
  has_one :payment_profile, :dependent => :delete
  accepts_nested_attributes_for :payment_profile

現在、 PaymentProfile クラスには独自の子があり、アクティブなマーチャントからの 2 つのアイテムがあります。

require 'active_merchant'

class PaymentProfile < ActiveRecord::Base
  include ActiveMerchant::Billing
  include ActiveMerchant::Utils

  validate_on_create :validate_card, :validate_address

  attr_accessor :credit_card, :address

  belongs_to :user

  validates_presence_of :address, :credit_card

  def validate_address
    unless address.valid?
      address.errors.each do |error|
        errors.add( :base, error )
      end
    end
  end

  def address
    @address ||= ActiveMerchant::Billing::Address.new(
      :name     => last_name,
      :address1 => address1,
      :city     => city,
      :state    => state,
      :zip      => zipcode,
      :country  => country,
      :phone    => phone
    )
  end

  def validate_card
    unless credit_card.valid?
      credit_card.errors.full_messages.each do |message|
        errors.add( :base, message )
      end
    end
  end

  def credit_card
    @credit_card ||= ActiveMerchant::Billing::CreditCard.new(
      :type               => card_type,
      :number             => card_number,
      :verification_value => verification_code,
      :first_name         => first_name,
      :last_name          => last_name
    )
    @credit_card.month ||= card_expire_on.month unless card_expire_on.nil?
    @credit_card.year  ||= card_expire_on.year unless card_expire_on.nil?
    return @credit_card
  end

ここで、Ryan Bates マルチページ フォーム スクリーンキャスト ( http://railscasts.com/episodes/217-multistep-forms )のソリューションを使用して、Devise の RegistrationsController をオーバーライドしてマルチページ フォームを処理しました。Devise で動作するように少し調整する必要がありましたが、うまくいきました。Ryan のマルチページ フォームは、異なるページの同じモデルから異なるフィールドを要求しただけなのでvalid?、次のように検証メソッドに :if ブロックを追加して、メソッドをオーバーライドすることができました。

validates_presence_of :username, :if => lambda { |o| o.current_step == "account" }

しかし、私の場合、親モデル (User) から最初のフォームのすべてのフィールドを要求し、次に 2 つの孫モデル (User:PaymentProfile:Address、User:PaymentProfile:Credit_Card) からすべてのフィールドを要求しています。 ) 2 ページ目にあります。

私が直面している問題は、PaymentProfile.valid? ActiveMerchant のロジックに基づいてエラーを返しますが、フォーム自体はそれらのエラーをレンダリングしたり表示したりしません。請求ページのビュー コードは次のようになります。

<h2>Payment Details</h2>

<%= semantic_form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
    <%= devise_error_messages! %>

    <%= f.semantic_fields_for :payment_profile do |p| %>
        <%= p.semantic_fields_for :address do |a| %>
            <%= a.inputs "Billing Information", :id => "billing" do %>
                <%= a.input :type,    :label => "Credit Card", :as => :select, :collection => get_creditcards %>
                <%= a.input :number,     :label => "Card Number", :as => :numeric %>
                <%= a.input :card_expire_on, :as => :date, :discard_day => true, :start_year => Date.today.year, :end_year => (Date.today.year+10), :add_month_numbers => true %>
                <%= a.input :first_name %>      
                <%= a.input :last_name %>
                <%= a.input :verification_code, :label => "CVV Code" %>
            <% end %>
        <% end %>

        <%= f.semantic_fields_for :credit_card do |c| %>
            <%= c.inputs "Billing Address", :id => "address" do %>
                <%= c.input :address1, :label => "Address" %>
                <%= c.input :city %>
                <%= c.input :state,   :as => :select, :collection => Carmen::states %>
                <%= c.input :country, :as => :select, :collection => Carmen::countries, :selected => 'US' %>
                <%= c.input :zipcode, :label => "Postal Code" %>
                <%= c.input :phone,   :as => :phone %>
            <% end %>
        <% end %>
    <% end %>

    <%= f.commit_button :label => "Continue" %>
    <% unless @user.first_step? %>
    <%= f.commit_button :label => "Back", :button_html => { :name => "back_button" } %>
    <% end %>
<% end %>

puts errorsコードの有効な直後にメッセージを追加しましたか? コマンドを実行すると、次のように表示されます。

{:base=>[["first_name", ["cannot be empty"]], ["last_name", ["cannot be empty"]], ["year", ["expired", "is not a valid year"]], ["type", ["is required", "is invalid"]], ["number", ["is not a valid credit card number"]], ["verification_value", ["is required"]], ["address1", ["is required"]], ["city", ["is required"]], ["state", ["is required"]], ["zip", ["is required", "must be a five digit number"]], ["phone", ["is required", "must be in the format of 333-333-3333"]]]}
{:base=>[["first_name", ["cannot be empty"]], ["last_name", ["cannot be empty"]], ["year", ["expired", "is not a valid year"]], ["type", ["is required", "is invalid"]], ["number", ["is not a valid credit card number"]], ["verification_value", ["is required"]], ["address1", ["is required"]], ["city", ["is required"]], ["state", ["is required"]], ["zip", ["is required", "must be a five digit number"]], ["phone", ["is required", "must be in the format of 333-333-3333"]]]}

現在、この出力の構造は、次のような単一レイヤーのハッシュから構築された標準エラー出力の出力と一致しません。

{:username=>["can't be blank"]}

そのすべてを示した後、私の質問は次のとおりです。a) フォームが実際にエラーを吐き出すように、エラー出力を適切に表示するにはどうすればよいですか? b)parent.valid を防ぐにはどうすればよいですか? grandchildren.valid? も検証しないでください。私がそのページにいないときは?current_step が何であるかがわからないため、子モデルで :if => lambda... ソリューションを使用できません。

できるだけ多くの情報を含めたかっただけで、長い投稿で申し訳ありません。私はこれに1週間取り組んできましたが、それを乗り越えることができないようです. どんなアドバイスも非常に役に立ちます。前もって感謝します。

4

3 に答える 3

4

エラーが表示されない理由は、おそらく、個々の属性ではなくベースに入力されているためです。これは、メソッドvalidate_cardvalidate_addressメソッドで発生します。エラーをベースに追加する代わりに、エラーの原因となった特定の属性にエラーを追加する必要があります。

errors.add( attr , error )

第二に、あなたが言及したスクリーンキャストのように、検証を特定の状態に依存させたい場合は、モデルで状態フラグを保存する必要があります(おそらく親が最適です)。これは手動で行うこともできますが、gem を使用することもできます (推奨) :

幸運を。

于 2012-01-25T01:08:34.980 に答える
1

大まかに言えば、オブジェクト モデリングで継承を使用しているようで、このモデルは、ほとんど「ウィザード」のようなアプローチで、いくつかの形式で構築されています。私の提案は、オブジェクトを反映するようにモデル化することです。実際のフォームは、

First part of the form collect basic User information : UserInformation model 

Second Part of the form collect payment related information: PaymentInformation model (the Active merchant stuff)

等々...

User モデルには UserInformation が 1 つ、PaymentInformation が 1 つなどがあります。

基本的に継承を構成に置き換えます。ActiveMerchant フレームワークの拡張も回避できるかどうか試してみてください。

上記のスタイルでは、#valid? を呼び出すタイミングをより細かく制御できます。あなたのデータモデルのサブセットで。ユーザーがフォーム内を移動すると、パーツごとに構築されます。

申し訳ありませんが、具体的な解決策はありませんが、より一般的な書き換えアプローチがあります。

于 2012-01-24T05:58:10.607 に答える
0

私は Ruby-on-Rails を初めて使用し、これが上記の質問に答えないことはわかっていますが、Client-Side Validationsを試してRails-castsを見てください。お役に立てるかもしれません!

于 2011-07-08T12:49:30.593 に答える