Override Validations In An Extension

400 views
Skip to first unread message

Jim Mulholland

unread,
Sep 24, 2009, 1:43:15 AM9/24/09
to Spree
We have a requirement for phone number to be optional in both the
billing and shipping address.

The Address model has a "validates_presence_of :phone".

How would I go about removing this validation in an extension?

I tried the following without any luck:

Address.class_eval do
validates_presence_of :phone if false
end

Thanks!

Jim Mulholland

unread,
Sep 24, 2009, 2:13:41 AM9/24/09
to Spree
I solved my own issue.

Turns out that I forgot to remove ":class -> 'required'" for my :phone
text_field in the _billing.html.erb partial so the client-side
JavaScript validation was still catching it.

Jim Mulholland

unread,
Sep 24, 2009, 2:19:41 AM9/24/09
to Spree
Looks like I spoke too soon. The server side validation is still
kicking in on order confirmation unless I override the entire
Address.rb model in my extension to delete the validates_presence_of.

Is this the only way to do this? Overwrite the whole model?

Marcin Raczkowski

unread,
Sep 24, 2009, 6:33:42 AM9/24/09
to spree...@googlegroups.com
Jim Mulholland wrote:
> Looks like I spoke too soon. The server side validation is still
> kicking in on order confirmation unless I override the entire
> Address.rb model in my extension to delete the validates_presence_of.
>
> Is this the only way to do this? Overwrite the whole model?
>

Address.class_eval do
validates_presence_of :phone, :if => false
end

Should do the trick, your declaration was doing nothing, becouse it was
never running (if false prevented it). I'm redifining it with built in
guard.

regards
Marcin Raczkowski

Jim Mulholland

unread,
Sep 24, 2009, 11:44:55 AM9/24/09
to Spree
Thanks Marcin. I would definitely help if I used the correct syntax!

Unfortunately, still no luck.

Using :if => false, Spree was returning the following Rails error in a
flash message:

"Unable to Authorize Credit Card: Callbacks must be a symbol denoting
the method to call, a string to be evaluated, a block to be invoked,
or an object responding to the callback method. "

So I modified to use a proc like so:

Address.class_eval do
validates_presence_of :phone, :if => Proc.new {1 == 2 }
end

which then just didn't pass server side validation again.

As an aside, when this validation fails, the error message that Spree
renders in a flash message is "Unexpected failure in card
authorization -- please contact site support" which is very
misleading. The card authorization had nothing to do with the
failure.

Marcin Raczkowski

unread,
Sep 24, 2009, 11:57:52 AM9/24/09
to spree...@googlegroups.com
Jim Mulholland wrote:
> Thanks Marcin. I would definitely help if I used the correct syntax!
>
> Unfortunately, still no luck.
>
> Using :if => false, Spree was returning the following Rails error in a
> flash message:
>
> "Unable to Authorize Credit Card: Callbacks must be a symbol denoting
> the method to call, a string to be evaluated, a block to be invoked,
> or an object responding to the callback method. "
>
> So I modified to use a proc like so:
>
> Address.class_eval do
> validates_presence_of :phone, :if => Proc.new {1 == 2 }
> end
>
> which then just didn't pass server side validation again.
>
> As an aside, when this validation fails, the error message that Spree
> renders in a flash message is "Unexpected failure in card
> authorization -- please contact site support" which is very
> misleading. The card authorization had nothing to do with the
> failure.

Strange, I thought it would accept false as parameter, you can try:
Address.class_eval do
validates_presence_of :phone, :if => lambda { false }
end

anyway back to the point, please check if gateway does not require phone
address, it's qute possible you solved one problem just to stumble on
another .

Jim Mulholland

unread,
Sep 24, 2009, 12:19:43 PM9/24/09
to Spree
I greatly appreciate the help, Marcin, but I am now thinking it is not
possible core validations to be overwritten in extensions.

I updated the CheckoutsController failure.wants.html code block to
flash the @object.errors message and it is returning "Bill address
phone can't be blank" even after trying the lambda block. I had also
verified that the form can be submitted successfully if I override the
entire Address model without the phone validation, so I do not think
it is a gateway issue.

So I guess our options are to override the entire Address model
without the validation which would mean I have to keep that in sync
with future Spree versions or just continue to require that phone is
mandatory.

Thanks again!

Roman Smirnov

unread,
Sep 24, 2009, 12:28:36 PM9/24/09
to Spree
> I am now thinking it is not possible core validations to be overwritten in extensions.

Never say never...

Address.class_eval do
def validate
self.errors.clear
attr_names = [:firstname, :phone]
self.errors.add_on_blank(attr_names, :blank)
end
end

:-)

Jim Mulholland

unread,
Sep 24, 2009, 1:31:08 PM9/24/09
to Spree
Excellent idea, Roman!

I did it a little differently, but it did work. Instead of readding
every potential validation manually via "add_on_blank", I decided just
to capture all of the errors, clear the error list, and then readd all
but the ones tied to "phone".

Address.class_eval do
#Override validation on phone
def validate
errors = self.errors.map {|attr, message| [attr, message]}
self.errors.clear
errors.each do |attr, message|
self.errors.add(attr, message) unless attr == "phone"
end
end
end

Thanks!

Roman Smirnov

unread,
Sep 24, 2009, 4:28:35 PM9/24/09
to Spree
Yes, you can realize any custom validation logic in validate method.
Glad to help.
Reply all
Reply to author
Forward
0 new messages