user339344
user339344

Reputation: 61

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!

Upvotes: 5

Views: 5278

Answers (5)

Anton
Anton

Reputation: 927

Here is how I did it still doing the redirect:

Just before you redirect on validation errors in your controller store errors to flash like suggested by @shingara:

if @restaurant_rating.save
  redirect_to @restaurant, :notice => "Successfully added rating to restaurant."
else
  flash[:error] = @restaurant_rating.errors
  redirect_to @restaurant, :alert => "There were errors to add rating to restaurant. " 
end

Then in your form for rating you assign errors back for the rating object just before rendering the form:

- flash[:error].messages.each {|error| @restaurant_rating.errors.add(error[0], error[1][0]) } if flash[:error]
= simple_form_for @restaurant_rating do |f|
  ....

Upvotes: 2

user664833
user664833

Reputation: 19505

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

Upvotes: 4

tommasop
tommasop

Reputation: 18765

After your clarification in the comment, you need to setup your

/app/views/layouts/application.html.erb

with this line

<%- flash.each do |name, msg| -%><%= content_tag :div, msg, :id => "flash_#{name}" %><%- end -%>

Upvotes: 0

fl00r
fl00r

Reputation: 83680

You can use render instead of redirect_to

render :action => "show"

or set flash[:error], flash[:notice] again, because they automatically reseted

Upvotes: 1

shingara
shingara

Reputation: 46914

You can pass your error on flash message

flash[:error] = @restaurant.errors

After you need display it in your redirect

Upvotes: 2

Related Questions