Forum: Ruby on Rails best way to validate input values..

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Jay P. (Guest)
on 2008-10-17 15:40
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..
Rob L. (Guest)
on 2008-10-17 15:46
(Received via mailing list)
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
Rob L. (Guest)
on 2008-10-17 15:50
(Received via mailing list)
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
Andrew P. (Guest)
on 2008-10-17 16:02
(Received via mailing list)
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.
athem (Guest)
on 2008-10-17 18:06
(Received via mailing list)
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/Va...

and

callbacks:

http://api.rubyonrails.com/classes/ActiveRecord/Ca...

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.
athem (Guest)
on 2008-10-17 18:06
(Received via mailing list)
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/Va...

and

callbacks:

http://api.rubyonrails.com/classes/ActiveRecord/Ca...

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.
Jay P. (Guest)
on 2008-10-18 04:32
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:
--------------------------------------------------------------------------------
<div>
<%=error_messages_for 'cart'%>
 <%form_tag :action=>:add_to_cart do%>
  <div id="this part gets replaced by partial>
   <%=select_tag "campsite", %w{---}%>
  </div>
   ...........
 <%end%>
</div>
--------------------------------------------------------------------------------

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.
This topic is locked and can not be replied to.