2011-03-28 17 views
6

के लिए एक जटिल मॉडल पर प्रमाणीकरण मैं devise और सक्रिय व्यापारी का उपयोग करके पंजीकरण लिखने की कोशिश कर रहा हूं। प्रपत्र जटिल है कि मेरे उपयोगकर्ता वस्तु इस तरह दिखता है:एक बहु-पृष्ठ फ़ॉर्म

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 overrided गए रयान बेट्स मल्टी-पेज फॉर्म स्क्रीनकास्ट (http://railscasts.com/episodes/217-multistep-forms) से समाधान का उपयोग करके मल्टी-पेज फॉर्म को संभालने के लिए तैयार करें। मुझे इसे डेविस के साथ काम करने के लिए थोड़ा सा ट्विक करना पड़ा, लेकिन मैं सफल रहा। अब क्योंकि रयान की बहु-पृष्ठ प्रपत्र बस विभिन्न पृष्ठों पर एक ही मॉडल से विभिन्न क्षेत्रों के लिए कहा है, वह एक जोड़कर अपने valid? विधि ओवरराइड करने में सक्षम था: अगर उसकी सत्यापित करें विधि एक ला करने के लिए ब्लॉक:

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

लेकिन में मेरा मामला, मैं अपने मूल मॉडल (उपयोगकर्ता) से पहले फॉर्म पर सभी फ़ील्ड मांग रहा हूं, और फिर अपने दो पोते मॉडल (उपयोगकर्ता: भुगतान प्रोफाइल: पता, उपयोगकर्ता: भुगतान प्रोफाइल: क्रेडिट_Card) से सभी फ़ील्ड मांग रहा हूं तेह दूसरा पृष्ठ।

मुझे जिस समस्या का सामना करना पड़ रहा है वह यह है कि हालांकि PayProfile.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"]]]} 

अब इस उत्पादन की संरचना एक मानक त्रुटि उत्पादन है जो इस तरह के रूप में एक परत हैश बंद बनाया गया है के उत्पादन से मेल नहीं खाता: आदेश और इसे इस प्रकार से पता चलता आपको यह सब दिखाने के बाद, मेरे प्रश्न ये हैं: ए) मैं त्रुटि आउटपुट को सही तरीके से दिखाने के लिए कैसे प्राप्त करूं ताकि फ़ॉर्म वास्तव में उन्हें थूक सके? बी) मैं माता-पिता को कैसे रोकूं? वैध? पोते को वैध करने से भी। वैध? जब मैं उस पृष्ठ पर नहीं हूं? मैं इसका उपयोग नहीं कर सकता: if => lambda ... बाल मॉडल पर समाधान क्योंकि वे नहीं जानते कि current_step क्या है।

इतनी लंबी पोस्ट के लिए मेरी माफ़ी, मैं बस जितना संभव हो उतना जानकारी शामिल करना चाहता था। मैं इसके साथ एक हफ्ते तक कुश्ती कर रहा हूं और मुझे इससे पहले प्रतीत नहीं होता है। कोई सलाह बेहद सहायक होगी। अग्रिम में धन्यवाद।

उत्तर

4

त्रुटियों को प्रदर्शित नहीं करने का कारण शायद यह है कि वे आधार पर आबादी वाले हैं, व्यक्तिगत गुणों पर नहीं। यह आपके validate_card और validate_address विधियों में होता है। आधार पर त्रुटियों को जोड़ने के बजाय, आपको उन्हें उस विशेष विशेषता में जोड़ना चाहिए जिससे त्रुटि उत्पन्न हुई हो।

errors.add(attr , error) 

दूसरे, आपको अपने सत्यापन, एक निश्चित राज्य पर निर्भर स्क्रीनकास्ट आप का उल्लेख के रूप में करना चाहते हैं, तो आप मॉडल (शायद सबसे अच्छा माता पिता) के साथ राज्य ध्वज को बचाने के लिए की जरूरत है। आप इसे हाथ से या बेहतर कर सकते हैं, आप इसके लिए एक मणि का उपयोग कर सकते हैं (अनुशंसित): state_machine

शुभकामनाएँ।

0

मैं रूबी-ऑन-रेल के लिए नया हूं और मुझे पता है कि यह ऊपर दिए गए सवालों का जवाब नहीं देता है लेकिन आपको Client-Side Validations को आजमाएं और Rails-casts पर एक नज़र डालें। यह आपके लिए सहायक हो सकता है!

+2

क्लाइंट-साइड सत्यापन एक अच्छा अतिरिक्त है, लेकिन सर्वर-साइड सत्यापन के लिए बिल्कुल कोई प्रतिस्थापन नहीं है। क्लाइंट-साइड सत्यापन आसानी से दुर्भावनापूर्ण स्क्रिप्ट द्वारा अवरुद्ध किया जाता है जो जेएस-सक्षम ब्राउज़र का उपयोग नहीं करते हैं। यह सुनिश्चित करने के लिए कि आपका डेटा उच्च अखंडता का है, सर्वर-साइड सत्यापन केवल विश्वसनीय तंत्र है। –

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 और इतने पर है।

अनिवार्य रूप से संरचना के साथ विरासत को प्रतिस्थापित करें। कोशिश करें और देखें कि क्या आप ActiveMerchant फ्रेम कार्य को विस्तारित करने से बच सकते हैं।

उपर्युक्त शैली, जब आप # valid को कॉल करना चाहते हैं तो आपको अधिक नियंत्रण मिलेगा? आपके डेटा मॉडल के सबसेट पर। यह फ़ॉर्म के माध्यम से भाग लेते हैं क्योंकि उपयोगकर्ता फॉर्म के माध्यम से स्थानांतरित होता है।

क्षमा करें, मेरे पास आपके लिए विशिष्ट समाधान नहीं है लेकिन एक सामान्य सामान्य पुनर्लेखन दृष्टिकोण है।

संबंधित मुद्दे