I have an User model (ActiveRecord).  It has many Addresses
(ActiveRecord) and one CreditCard (ActiveModel)

When I submit my nested form the CreditCard validations did not fire.

So...  in my User model I added this so the credit card validations
would get called.

  def before_validation
    credit_card.valid? unless credit_card.nil?
    return true
  end

This worked great.  the missing credit card fields were highlighted
and everything...  except

@user.errors.full_messages only contained errors for the user and
addresses.

So I updated my before_validation call again

  def before_validation
    credit_card.valid? unless credit_card.nil?
    credit_card.errors.each{|k,v|
      errors["credit_card.#{k}"] = v
    }
    return true
  end

Now everything is cool except the ugly error messages that nested
forms give you.

I chop off the credit card and addresses prefix when displaying them

      <% @user.errors.full_messages.each do |msg| %>
        <%
        message =    msg.gsub(/Credit card /, '').capitalize
        message =  message.gsub(/Addresses /, '').capitalize
      %>
        <li><%= message %></li>
      <% end %>

This seems like a lot of work and I suspect there is a 1 liner I'm
missing that will make this all automatic.

Something like this in my user model.

has_one_virtual :credit_card

Does such a thing exist?  I hope so  :-)

==================  Code snippets ====================

==== User model ====

class User < ActiveRecord::Base
  acts_as_authentic
  has_many :addresses
  accepts_nested_attributes_for :addresses
  validates :credit_card, :presence => true
  attr_accessor :email_confirmation, :credit_card

  validates_confirmation_of :email, :message => "should match
confirmation"

  def credit_card_attributes=(attributes)
    self.credit_card = CreditCard.new(attributes)
  end


  def before_validation
    credit_card.valid? unless credit_card.nil?
    credit_card.errors.each{|k,v|
      errors["credit_card.#{k}"] = v
    }
    return true
  end
end

==credit_card=================
class CreditCard

  include ActiveModel::Validations
  include ActiveModel::AttributeMethods
  include ActiveModel::Callbacks
  include ActiveModel::Conversion
  extend ActiveModel::Naming

  #  belongs_to :user
 
attr_accessor :card_type, :card_number, :card_verification, :card_expires_on, 
:agree
  validates :card_type, :presence => true
  validates :card_number, :presence => true
  validates :card_verification, :presence => true
  validates :card_expires_on, :presence => true
  validates :agree, :presence => true

  def initialize(attributes = {})
    expire_date = {}
    attributes.each do |name, value|
      if name.include?('card_expires_on')
        expire_date[name] = value
      else
        send("#{name}=", value)
      end
    end
    # yeah,  this is a total mess. Can ActiveModel handle this?
    ymd =  expire_date.map(&:last).map(&:to_i)
    begin
      send("card_expires_on=", Time.zone.local(ymd[2], ymd[1],1))
unless  ymd[1].blank? || ymd[2].blank?
    rescue
    end
  end

  def persisted?
    false
  end
end

-- 
You received this message because you are subscribed to the Google Groups "Ruby 
on Rails: Talk" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/rubyonrails-talk?hl=en.

Reply via email to