CHawk
CHawk

Reputation: 1356

Rails - Trouble with AJAX Create Method and Response

New to rails, so please excuse the noob question. Having some trouble with capturing e-mails via AJAX.

Desired Functionality: I'm creating a landing page for my site where we capture e-mails ("Leads" = object/model). I want to capture the e-mails asynchronously, then display a thank you message to the user. If user enters an invalid e-mail, I want to ask them to input a correct e-mail.

What I've Got Working I can correctly capture the e-mail and perform validation via AJAX. If I enter an invalid e-mail then click "submit", it is not shown on /leads/index. If I enter an invalid e-mail, it is shown on /leads/index.

What I Don't Have Working I have not figured out how to get any sort of response back to the user. All I want to do is change the text of an h3 (class="results") element if the save was successful.

My Code

landing.html.erb:

        <h3 class="results">Give us your e-mail and we'll send you an invite to beta when it's ready.</h3>

        <%= form_for(:lead, remote: true, :url => {:controller => 'leads', :action => 'create'}, :html => {:class => 'form-inline emailForm'}) do |f| %>
          <div class="form-group">
            <%= f.label(:email, 'E-mail', class: 'sr-only') %>
            <%= f.text_field(:email, {:id => 'submitEmail2', :class=> 'form-lg', :placeHolder => 'E-mail Address'}) %>
          </div>
          <%= submit_tag("Sounds Good", {:id => 'submitEmail2', :class => 'btn btn-success btn-lg'}) %>
        <% end %>

leads_controller.rb

 class LeadsController < ApplicationController

  layout false
  #respond_to :html, :js

  def index
    @leads = Lead.order("created_at ASC")
  end

  def show
  end

  def new

  end

  def create
    @lead = Lead.new(lead_params) #Create a new object without form parameters

  end

  def edit
  end

  def delete
  end


  private
    def lead_params
      params.require(:lead).permit(:email)
    end
end

create.js.erb

$('h3.results').html("");

//If I remove this code, it works
<% if @lead.save? %>
    $("h3.results").html("Thank you! We'll let you know when it's ready."));
    $('.emailForm').hide();
<% else %>
    $("h3.results").html("Invalid E-mail. Please try again!"));
<% end %>

If I remove the last bit of code in create.js.erb, everything works and the text in the h3 gets removed. What is wrong with the save statement? Am I doing the save in the correct section of my code, or should it be in the controller?

All help is appreciated!

Upvotes: 1

Views: 49

Answers (3)

Richard Peck
Richard Peck

Reputation: 76774

New to rails

Welcome!


I have not figured out how to get any sort of response back to the user

Ajax responses are always sent back on completion of the request.

How you handle it is up to you.

You'll be able to see the responses by looking at the network tab of your devloper console in your browser. In chrome, you'll be able to right-click > Inspect Element > Network:

enter image description here

You'll be able to see the request being sent when you submit your form.


it is not shown on /leads/index

The problem you have is your save functionality.

As mentioned by cweston, you're best saving the record in the controller action itself (this has direct access to the model):

def create
  @lead = Lead.new lead_params
  @lead.save
  respond_to do |format|
     format.js #-> app/views/leads/create.js.erb
  end
end

This will allow you to use the following (new_record?):

  #app/views/leads/create.js.erb
  <% message = @lead.new_record? "Invalid Email. Please try again!" : "Thank you! We'll let you know when it's ready" %>
  $("h3.results").html("<%=j message %>");

  <% unless @lead.new_record? %>
    $('.emailForm').fadeOut(500, function(){
       $(this).remove();
    });
  <% end %>

This should give you the ability to manage your HTML elements in the DOM.


Response

In terms of your response, the fact you're using the inbuilt server-side JS is great; I applaud that.

The other way you could handle your response would be to use client-side Ajax. You don't need to do this, as you're using the Rails UJS driver, but here's how you'd do it anyway:

#app/assets/javascripts/application.js
$(document).on("submit", "form#new_lead", function(e) {
   $.ajax({
      url: $(this).attr("action"),
      data: $(this).serialize(),
      success: function(data) {
          // stuff here
      },
      error: function(data) {
         // stuff here
      }
   }); 
});

Upvotes: 1

CHawk
CHawk

Reputation: 1356

Answer I'm an idiot. The error was because of the double parenthesis at the end of my $('h3.results') calls.

Upvotes: 0

cweston
cweston

Reputation: 11637

I believe you are getting an error on the line:

<% if @lead.save? %>

You should be performing the save in the controller:

def create
  lead = Lead.new(lead_params)
  @saved = lead.save
end

Note the use of save not save?

You can then test if @lead.save was successful in your view with @saved:

$('h3.results').html("");

<% if @saved %>
  $("h3.results").html("Thank you! We'll let you know when it's ready."));
  $('.emailForm').hide();
<% else %>
  $("h3.results").html("Invalid E-mail. Please try again!"));
<% end %>

Upvotes: 1

Related Questions