Best way to validate input values


#1

Hi, I have a form that submits values from text fields and a check box.
The values posted are: camp location name, number of nights, number of
parents, number of children, value from the check box “family claim”.
Where camp name can’t be nil, nights can’t be more than 2, parents and
children together can’t be more than 8 and if there are no children
specified check box can’t be checked. Here’s my unsuccessful
implementation for this:

def add_to_cart
begin
cart=find_cart
camp_loc = params[:camp][:id]
nights=params[:nights]
parents=params[:parents]
children=params[:children]
family_rate_claim=params[:family_claim]
rescue
redirect_to_booking(“Invalid input.”)
end
if camp_loc.blank? || nights.blank? || parents.blank?
redirect_to_booking(“Fields with ‘*’ are required fields.”)
elsif (nights.to_i > 2) || ((parents.to_i + children.to_i) > 8)
redirect_to_booking(“Limitation: Maximum stay of 2 nights with group
of maximum 8 people.”)
elsif children.nil? and family_rate_claim == “1”
redirect_to_booking(“You are not eligible for claiming family
rate.”)
else
…add the stuff in the cart
end
end

def redirect_to_booking(msg)
flash[:notice]=msg
render :action => :online_booking
end

When I click the button without giving anything as the input I get this:

Render and/or redirect were called multiple times in this action. Please
note that you may only call render OR redirect, and at most once per
action. Also note that neither redirect nor render terminate execution
of the action, so if you want to exit an action after redirecting, you
need to do something like “redirect_to(…) and return”.

but what I want is to to get redirected to the same page with error
information.
thanks…


#2

the “render or redirect called multiple times” error is because you
haven’t called ‘return’ after you called ‘render’ or indeed
‘redirect_to’. It doesn’t actually do the render or redirect
immediately. It only occurs after the method has returned.

RobL


#3

I wouldn’t do any vaildation in the controller, its messy and not ideal.

I’d have some kind of ‘Booking’ object which presumably is what you are
adding to your cart and validate it inside that using the rails
validation helpers.

RobL


#4

Jay P. wrote:

you specific problem here is -

rescue
redirect_to_booking(“Invalid input.”)
end

You render here

if camp_loc.blank? || nights.blank? || parents.blank?
redirect_to_booking(“Fields with ‘*’ are required fields.”)
elsif (nights.to_i > 2) || ((parents.to_i + children.to_i) > 8)
redirect_to_booking(“Limitation: Maximum stay of 2 nights with group
of maximum 8 people.”)
elsif children.nil? and family_rate_claim == “1”
redirect_to_booking("You are not eligible for claiming family

And also here

Do .

return( redirect_to_booking(“Invalid input.”) )

So your code doesn’t fall through.


#5

On Oct 17, 4:55 am, Andrew P. removed_email_address@domain.invalid wrote:

You render here

Do .

return( redirect_to_booking(“Invalid input.”) )

So your code doesn’t fall through.

I think there’s a relationship between the problem you are
experiencing and the face that you are performing validations in your
controller and not your model. As Rob said above, you should move the
validations:

if camp_loc.blank? || nights.blank? || parents.blank?
elsif (nights.to_i > 2) || ((parents.to_i + children.to_i) > 8)
elsif children.nil? and family_rate_claim == “1”

to your model and use ActiveRecord validations:

http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html

and

callbacks:

http://api.rubyonrails.com/classes/ActiveRecord/Callbacks.html

to implement the validations in your models

Then you could call save (or valid?) and use error_messages_for (vs.
flash) to display your messages. This is all in addition to calling
return with each render.


#6

On Oct 17, 4:55 am, Andrew P. removed_email_address@domain.invalid wrote:

You render here

Do .

return( redirect_to_booking(“Invalid input.”) )

So your code doesn’t fall through.

I think there’s a relationship between the problem you are
experiencing and the face that you are performing validations in your
controller and not your model. As Rob said above, you should move the
validations:

if camp_loc.blank? || nights.blank? || parents.blank?
elsif (nights.to_i > 2) || ((parents.to_i + children.to_i) > 8)
elsif children.nil? and family_rate_claim == “1”

to your model and use ActiveRecord validations:

http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html

and

callbacks:

http://api.rubyonrails.com/classes/ActiveRecord/Callbacks.html

to implement the validations in your models

Then you could call save (or valid?) and use error_messages_for (vs.
flash) to display your messages. This is all in addition to calling
return with each render.


#7

Thanks guys for your suggestions. I have now moved all the validations
to the model class and ended up with couple of question again. I’ve done
like the following:

MODEL CLASS:

class Cart < ActiveRecord::Base
validates_presence_of :campsite, :arrival_date, :nights, :parents,
:total

def validate
errors.add(:nights, “should be equal to or less than 2”) if nights >
2
errors.add(:total, “should be greater than 0”) if total < 0.01
end

end

CONTROLLER:

def add_to_cart
cart=find_cart
if params[:family_claim] != “1”
total = (((params[:parents].to_i + params[:children].to_i) * 4.85)

  • params[:nights].to_i)
    else
    total = (19.4 * params[:nights].to_i)
    end
    cart=Cart.create(:campsite => params[:camp][:id], :arrival_date =>
    params[:arrival_date],
    :nights => params[:nights], :parents =>
    params[:parents],
    :children => params[:children], :family_claim =>
    params[:family_claim],
    :total => total)
    if cart.save
    @cart << cart.id
    @cart_details = find_items_in_session
    else
    render :action => :online_booking
    end
    end

VIEW:

<%=error_messages_for 'cart'%> <%form_tag :action=>:add_to_cart do%>
........... <%end%>
--------------------------------------------------------------------------------

1)Now, when I give 3 or more for the number of nights, online_booking
should be rendered again with the message “should be equal to or less
than 2”, isn’t it? but I don’t get any message just the online_booking
page is redisplayed.

2)In the validation I have to validate that the number of parents and
children together can’t be more than 8 (children can be null so it’s not
checked). How do I do this?

3)One field gets replaced by partial before the form is submitted. So,
if I submit the form before making that partial loaded, id for that
field is passed as params[:campsite] and params[:camp][:id] if the
partial is loaded. How can I check for this? In the controller I’m tried
to do:

if !params[:camp][:id].nil?
camp_loc = params[:camp][:id]
else
camp_loc = params[:campsite]
end

but failed and I think the reason is: params[:camp][:id] is no where to
be found if the partial is not loaded and if I try with
params[:campsite] its the same if the partial is loaded. So, how can I
solve it as it gives me error in the same line where the if clause is?

thanks.