andersr
andersr

Reputation: 1051

How do I display error messages in the same URL as the form URL in Rails forms?

(I've broken out the 2nd question that originally was part of this post into a separate post)

I am creating a product landing page with Rails in which users can enter their email address to be notified when the product launches. (Yes, there are services/gems etc that could do this for me, but I am new to programming and want to build it myself to learn rails.)

On submit of the form, if there are errors, the app currently redirects to '/invites' I would like to instead display error messages on the same page/URL as the original form? (In my case, the form is located at root while the error messages are displaying at '/invites')

I have read the Rails Guide on Routes and numerous stackoverflow posts on handling form errors nothing I've found seems to answer the question I have.

Update: Based on the reply from @rovermicrover I would like to clarify that, while I'm open to an Ajax solution, I'm fine with a page refresh that displays the error message. (I was not able to get the recommendation by @rovermicrover to function as desired - see my response to that solution below for more details.)

What I did:

Invite model:

    class Invite < ActiveRecord::Base
      attr_accessible :email

      validates :email, :presence => {:message => "Please enter an email address."}

    end

My routes file:

SuggestionBoxApp::Application.routes.draw do
  root to: 'invites#new'
  resources :invites
end

This is what I have in the Invites controller (I've only included the actions I'm referencing: new, create, show - it's basically the default of what Rails might generate):

class InvitesController < ApplicationController

      def show
      @invite = Invite.find(params[:id])

        respond_to do |format|
          format.html # show.html.erb
          format.json { render json: @invite }
        end
      end

      def new
        @invite = Invite.new

        respond_to do |format|
          format.html # new.html.erb
          format.json { render json: @invite }
        end
      end

      def create
        @invite = Invite.new(params[:invite])

        respond_to do |format|
          if @invite.save
            format.html { redirect_to @invite }
            format.json { render json: @invite, status: :created, location: @invite }
          else
            format.html { render action: "new" }
            format.json { render json: @invite.errors, status: :unprocessable_entity }
          end
        end
      end
    end

Please let me know if there is any additional info I can provide in helping to answer this question. Thanks!

Upvotes: 0

Views: 1175

Answers (2)

Ananth Krishnan
Ananth Krishnan

Reputation: 21

There is a way to do this without resorting the making the form submit "remote", from a pure Ruby on Rails perspective. However, you can do this only if the browser has enabled cookies.

The idea is to save the form data in the session information in case of an error. Just remember to delete the session data in case of success.

  def new
    @invite = Invite.new(session[:invite])

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @invite }
    end
  end

  def create
    @invite = Invite.new(params[:invite])

    respond_to do |format|
      if @invite.save
        session.delete(:invite)
        format.html { redirect_to @invite }
        format.json { render json: @invite, status: :created, location: @invite }
      else
        session[:invite] = params[:invite]
        format.html { render action: "new" }
        format.json { render json: @invite.errors, status: :unprocessable_entity }
      end
    end
  end

Upvotes: 0

rovermicrover
rovermicrover

Reputation: 1453

Make the form 'remote'

form_for @invite, :remote => true
   ....

Then in the controller

def create
  @invite = Invite.new(params[:invite])
    respond_to do |format|
      if @invite.save
        format.html { redirect_to @invite }
        format.js { render :action => 'create_suc'}
      else
        format.html { render action: "new" }
        format.js { render :action => 'create_fail' }
      end
    end
  end

/invites/create_suc.js.erb

$('#errors').remove()
$('#new_invite').prepend("<div class='Thanks'>Thanks for signing up</div>")
$('#new_invite').hide("")

/invites/create_fail.js.erb

$('#new_invite').html('<%= escape_javascript render("form", :invite => @invite) %>');

Forms is a partial with your.... form in it, and also the handling of all errors on @invite.

Upvotes: 2

Related Questions