Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Validation messages after redirect

We have a form to submit ratings for a certain restaurant in a in our views/restaurants/show.html.erb. If there is a validation error we get redirected back to views/restaurants/show.html.erb but the validation messages do not appear. We figured out that this happens because we lose the messages using redirect_to(@restaurant) in our RatingController create action. But how can we get back without redirection?

Thanks!

like image 262
user339344 Avatar asked May 12 '10 13:05

user339344


1 Answers

Here is how I solved this. (Note that in what follows I'm obviously just including just the most relevant lines.)

In the model there may be multiple validations and even methods that potentially report on multiple errors.

class Order < ActiveRecord::Base
  validates :name, :phone, :email, :presence => true
  def some_method(arg)
    errors.add(:base, "An error message.")
    errors.add(:base, "Another error message.")
  end
end

As well, the controller action may set flash messages. Finally, the user may have entered data into the input fields, and we want it to persist through the redirect_to too.

class OrdersController < ApplicationController
  def create
    @order = Order.new(params[:order])
    respond_to do |format|
      if @order.save
        session.delete(:order) # Since it has just been saved.
      else
        session[:order] = params[:order]  # Persisting the order data.

        flash[:notice] = "Woohoo notice!" # You may have a few flash messages
        flash[:alert] = "Woohoo alert!"   # as long as they are unique,
        flash[:foobar] = "Woohoo foobar!" # since flash works like a hash.

        flash[:error] = @order.errors.to_a # <-- note this line

        format.html { redirect_to some_path }
      end
    end
  end
end

Depending on your setup, you may or may not need to save the model data, such as order, to the session. I did this for the purpose of passing the data back to the original controller, and thereby being able to setup the order there again.

In any case, to display the actual error and flash messages, I did the following (in views/shared/_flash_messages.html.erb, but you could do it in application.html.erb or wherever else makes sense for your app). And this is thanks to that line flash[:error] = @order.errors.to_a

<div id="flash_messages">
  <% flash.each do |key, value|

    # examples of value: 
    # Woohoo notice!
    # ["The server is on fire."]
    # ["An error message.", "Another error message."]
    # ["Name can't be blank", "Phone can't be blank", "Email can't be blank"]

    if value.class == String # regular flash notices, alerts, etc. will be strings
      value = [value]
    end

    value.each do |value| %>
      <%= content_tag(:p, value, :class => "flash #{key}") unless value.empty? %>
    <% end %>
  <% end %>
</div><!-- flash_messages -->

To be clear, regular flash messages such as notices, alerts, etc. will be strings, however errors will be arrays since the above call was errors.to_a

like image 160
user664833 Avatar answered Sep 30 '22 07:09

user664833