0

I guess that in many ways I'm still a newbie with some of this rails stuff. I have ActiveRecord Model for Payments. But, it only has two things that get added to it's table and those are done once we get a positive response back from authorize.net. In the Controller for this model I have my Cart form. Within the Cart form I have billing information with default values pulled from @client and the credit card information. It looks a bit like this:

<%= form_for @payment, :url => { action: "checkout" } do |f| %>
...show errors ...
<%= f.fields_for @client do |ff| %>
    <%= ff.label :firstname, 'First Name*' %>
    <%= ff.text_field :firstname %>
    ...more fields ....
    <%= ff.label :zip, 'Zip*' %>
    <%= ff.text_field :zip %>
<% end %>
<%= f.label :cardnumber, 'Card Number*' %>
<%= f.text_field :cardnumber %>
... more cc info fields ...
<% end %>

Now in the Model I have added attr_accessor :cardnumber, and other card info fields.

I don't have any getter or setter methods for these (perhaps that is what I am missing).

However, I do have this in the Payment Model:

validates :zip, presence: true, numericality: true
validates :cardnumber, presence: true, numericality: true

Yet, so far the form will bypass this validation all together and goes direction to the checkout. Any help would be greatly appreciated! How do I get these validations to work properly?

Drew Harris
  • 486
  • 1
  • 5
  • 13

1 Answers1

1

If you want to get into the technical details, most of Rails' baked-in validators inherit from ActiveModel::EachValidator and this validator explicitly checks the attributes collection from ActiveModel via #read_attribute_for_validation. If #zip and #cardnumber have been set up with attr_accessor they are most likely not part of #attributes and thus skipped by the validator.

The simplest workaround would be to write a private method that validates zip/cardnumber and then call .validates with the name of that validation method. The pattern that was recommended by Koz would look like this...

class Payment
  attr_accessor :zip

  validate :assure_zip_not_blank

  private
    def assure_zip_not_blank
      errors.add(:zip, 'cannot be blank') if zip_blank? && new_record?
    end

    def zip_blank?
      self.zip.blank?
    end
end

Separating the validation into two methods (assure_zip_not_blank and zip_blank?) may be overkill in this particular case but it's helpful when the logic becomes more complicated and/or you can reuse the logic.

AndyV
  • 3,696
  • 1
  • 19
  • 17
  • Well, I added it and I am getting this now: ArgumentError in PaymentsController#cart You need to supply at least one validation – Drew Harris Nov 18 '13 at 02:14
  • Sorry, typo in that code. The validation line should have said 'validate' instead of 'validates' (no s). Fixed. – AndyV Nov 18 '13 at 13:36
  • That worked for me. I had an rspec FactoryGirl build passing, as the valid method was passing over my virtual attributes. Adding a custom validation solved it. – Tim Jul 11 '15 at 22:09