2011-03-28 3 views
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 클래스가 자신의 아이들, 활성 상인에서 두 항목이 있습니다 :

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 

지금은 RegistrationsController에서 오버라이드 한을 양식 내 사용자 개체는 다음과 같습니다 점에서 복잡 Ryan Bates의 다중 페이지 양식 스크린 캐스트 (http://railscasts.com/episodes/217-multistep-forms)의 솔루션을 사용하여 다중 페이지 양식을 처리하도록 작성하십시오. Devise와 함께 작동 시키려면 약간 조정해야했지만 성공했습니다. 라이언의 여러 페이지 양식은 단순히 다른 페이지에서 동일한 모델에서 다른 필드를 요청 이제 때문에, 그는 추가하여 자신의 valid? 메소드를 오버라이드 (override) 할 수 있었다 : 경우 라 자신의 validate 메소드에 블록 :

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

그러나에 내 경우, 부모 모델 (사용자)의 첫 번째 양식에있는 모든 입력란을 물어보고 내 두 손자 모델 (User : PaymentProfile : Address, User : PaymentProfile : Credit_Card)의 모든 입력란에 대해 묻습니다. 두 번째 페이지.

제가 직면 한 문제는 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 메시지를 추가? 그래서

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

:

{: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"]]]} 

지금이 출력의 구조가 같은 단일 층의 해시를 구축하는 표준 오류 출력의 출력과 일치하지 않는 다음과 같이 명령과 그 보여줍니다 그 모든 것을 보여준 후에 제 질문은 다음과 같습니다 : a) 오류 출력이 어떻게 제대로 표시되도록하면 양식이 실제로 출력되는지 알아낼 수 있습니까? b) parent.valid를 어떻게 막을 수 있습니까? 손자를 확인하는 것에서부터. 내가 그 페이지에 없을 때? 자식 모델에 : if => lambda ... 솔루션을 사용할 수 없습니다. 왜냐하면 그들은 current_step이 무엇인지 모르기 때문입니다.

그런 긴 게시물에 대해 사과드립니다. 가능한 한 많은 정보를 제공해 드리고 싶었습니다. 나는 1 주일 동안 이걸 가지고 씨름하고 있었고 나는 그걸 지나갈 수 없었다. 조언이 도움이 될 것입니다. 미리 감사드립니다.

답변

4

오류가 표시되지 않는 이유는 개별 특성이 아니라 기준에 채워지는 것일 수 있습니다. 이는 validate_cardvalidate_address 방법에서 발생합니다. 기본에 오류를 추가하는 대신 오류를 유발 한 특정 속성에 오류를 추가해야합니다. 당신은 당신이 언급 한 스크린 캐스트로, 특정 상태에 대한 당신의 검증 의존 만들고 싶어

errors.add(attr , error) 

둘째, 당신은 모델 (아마 가장 상위)로 상태 플래그를 저장해야합니다. 이 작업을 직접 수행하거나 더 나은 방법으로 보석을 사용할 수 있습니다 (권장) : state_machine

행운을 빕니다.

0

Ruby-on-Rails를 처음 사용하고 있는데 위 질문에 대한 답변이 없지만 Client-Side Validations을 시도하고 Rails-casts을 살펴보아야합니다. 그것은 당신에게 도움이 될 수 있습니다!

+2

클라이언트 측 유효성 검사는 훌륭한 추가 기능이지만 서버 측 유효성 검사를 대체 할 수는 없습니다. 클라이언트 측 유효성 검사는 JS 가능 브라우저를 사용하지 않는 악의적 인 스크립트에 의해 쉽게 제거됩니다. 데이터의 무결성을 높이기 위해 서버 측 유효성 검사가 유일한 신뢰할 수있는 메커니즘입니다. –

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) 

등등 ...

을 좋아하는 곳 중 하나를 사용자 모델, 하나 UserInformation을 가지고 있으므로 하나 PaymentInformation하고 있습니다.

기본적으로 상속을 Composition으로 바꿉니다. ActiveMerchant 프레임 작업을 확장하는 것을 피할 수 있는지보십시오.

위 스타일을 사용하면 #valid를 호출 할 때를 더 효과적으로 제어 할 수 있습니다. 데이터 모델의 하위 집합입니다. 사용자가 양식을 이동하면서 부분적으로 생성됩니다.

죄송합니다. 구체적인 해결책은 없지만보다 일반적인 재 작성 방법은 없습니다.