Raise an alert/notice in rails controller WITHOUT

2019-07-31 05:36发布

问题:

I want to flash a notice/error if the email is/isn't saved, without using a redirect. I am using Rails 4 for the project, and here is my code:

layouts/application.html.erb

<!DOCTYPE html>
<html>
<head>
  <title>FarFlung Jobs</title>
  <!-- /.You can include style.css into stylesheet_link_tag too. If you do so, dont forget to add style.css in asset.rb -->
  <%= stylesheet_link_tag    'application', 'jobs', media: 'all' %>
  <%= javascript_include_tag 'application' %>
  <%= javascript_include_tag 'config', 'sharebutton', 'jobsalert', 'modernizr'%>
  <%= render 'payola/transactions/stripe_header' %>
  <%= csrf_meta_tags %>
</head>
<body>
    <%=  render 'shared/navbar' %>

    <div>
      <% flash.each do |name, msg| %>
        <%= content_tag :div, msg, class: 'alert alert-info' %>
      <% end %>
    </div>

<%= yield %>
    <%=  render 'shared/footer' %>
</body>
</html>

users/new.html.erb

<section class="cd-form-wrapper cd-container">
    <div class="column panel panel-default">
      <div class="cd-filter"><h4>SUBSCRIBE FOR JOBS ALERT</h4></div>
      <%= simple_form_for User.new do |f| %>
          <%= f.input :email, label: false, :placeholder => 'Enter your email address...', :input_html => { :class => 'newsletter-form-field-styling' } %>
          <%= f.button :submit, 'SUBMIT', :class => 'btn-block newsletter-form-styling btn-primary submit' %>
      <% end %>
    </div>
</section>

users_controller.rb

class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def create
    @user = User.new(secure_params)
    if @user.valid?
      @user.save
      flash.now[:notice] = "#{@user.email} is signed up for Jobs Alert."
    else
      flash.now[:alert] = 'Error Subscribing!'
    end
  end

private

  def secure_params
    params.require(:user).permit(:email)
  end
end

How do I get the Rails flash message working to appear on my subscription form without redirecting the page?

回答1:

You can submit your form passing remote: true. It'll (as you can expect) remotely submit your form, so you can return an json an render the expected flash. Ex:

Your form:

simple_form_for User.new, remote: true, class: 'your-form' do 
  <your code>

Your controller

def create
@user = User.new(secure_params)
if @user.save
  render json: { status: 'success', message: "#{@user.email} is signed up for Jobs Alert." }
else
  render json: { status: 'failure', message: 'Error Subscribing!' }
end

end

Your JS (perhaps new.js - and be sure to include it in your view)

// you can specify your bind container, here I just used the document
$(document).on('ajax:success', '.your-form', function(e, data) {
  if(data.status == 'success'){
    showSuccessFlash(data);
  }else{
    showErrorFlash(data);
  }
});

Explaining:

Using the remote: true, your page will wait for an ajax answer, which you can get listening to ajax:success (or other bindings).

Then, it will receive the json and will store in the data variable. So you will get the data.status and the data.message, which you can show to your user as a feedback.

More infor about the remote: true http://edgeguides.rubyonrails.org/working_with_javascript_in_rails.html#form-for

More info about the JS callbacks https://github.com/rails/jquery-ujs/wiki/ajax



回答2:

You can use a gem like Gon that will monitor variables and handle all of the Ajax for you automatically.

It's very easy to setup, and you can have it perform the update at whatever time interval you choose. If you're simply transporting a variable, this will save you some Ajax coding. And it will update your page without any kind of redirect, so it does exactly what you're looking for.



回答3:

However, one other tweak I figured out to solve this problem is with/without redirect is using application helper to make your Flash Global and used on any View of your choice.

Move your Flash Message to Partials e.g.

shared/_flash_messages.html.erb

    <div class="text-center">
      <% flash.each do |name, msg| %>
          <%= content_tag :div, msg, class: 'alert alert-info' %>
      <% end %>
    </div>

Define custom helper method for your flash messages using the exact same old rails method use to have. Such that the method renders our partials and the object will be parsed along to your partials.

helpers/application_helper.rb

module ApplicationHelper
   def flash_messages_for(object)
      render(:partial => 'shared/flash_messages', :locals => {:object => object})
   end
end

Inside my View, you can call it with erb tags and call the form object on it such as <%= flash_messages_for(User.new) %> or <%= flash_messages_for(@user) %>. See code below:

users/new.html.erb

<section class="cd-form-wrapper cd-container">
<div class="column panel panel-default">
  <%= flash_messages_for(User.new) %>
  <div class="cd-filter"><h4>SUBSCRIBE FOR JOBS ALERT</h4></div>
  <%= simple_form_for(User.new) do |f| %>
      <%= f.input :email, label: false, :placeholder => 'Enter your email address...', :input_html => { :class => 'newsletter-form-field-styling' } %>
      <%= f.button :submit, 'SUBMIT', :class => 'btn-block newsletter-form-styling btn-primary submit' %>
  <% end %>
</div>

With this, my error messages are flashed on any view or form I call <%= flash_messages_for(User.new) %> on.

You can refer to Kevin Skoglund formerrors Ruby on Rails Tutorials on Lynda.com Click to watch