I am trying to write a registration with the help of a developer and an active trader. The form is complex in that my custom object looks like this:
class User < ActiveRecord::Base include ActiveMerchant::Utils
Now the PaymentProfile class has its own child elements, two elements from the active merchant:
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
Now I have redefined RegistrationsController from Devise to handle a multi-page form using a solution from the multi-page Ryan Bates form ( http://railscasts.com/episodes/217-multistep-forms ). I had to tweak it a bit to get it working with Devise, but I was successful. Now, since the multi-page Ryan form just asked for different fields from the same model on different pages, was he able to override his valid? method valid? by adding an if if block to his a la check method:
validates_presence_of :username, :if => lambda { |o| o.current_step == "account" }
But in my case, I request all the fields in the first form from my parent model (User), and then I request all the fields from two grandson models (User: PaymentProfile: Address, User: PaymentProfile: Credit_Card) on the second page.
The problem I am facing is that although PaymentProfile.valid? returns errors based on ActiveMerchant logic; the form itself does not display or even does not display these errors. The view code for the billing page is as follows:
<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 %>
I added puts errors to my code right after the actual one? and it shows the following:
{: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"]]]}
Now the structure of this output does not correspond to the output of the standard error output, which is built on a single-layer hash, for example:
{:username=>["can't be blank"]}
So, showing you all this, my questions are: a) how can I get the error output to display correctly so that the form actually spits them out? b) how can i prevent parent.valid? from credibility check. when am I not on this page? I can not use the solution: if => lambda ... for child models because they do not know what current_step is.
My apologies for such a long post, I just wanted to include as much information as possible. I struggled with this for a week, and I seem to be unable to get past him. Any advice would be extremely helpful. Thanks in advance.