title: Reusable remote modal Rails
body: <p>I am trying to create a reusable remote modal. The idea is to create a model container and render content with <code>yield</code> into it and render content when needed.</p>
  
  <p>Note: all <code>HTML</code> code will be written in <code>HAML</code>. I am using <a href="https://github.com/vicentereig/bootstrap-modal-rails" rel="nofollow noreferrer">bootstrap-modal-rails</a> gem to handle my modals.</p>
  
  <p>My modal container layout (not a partial):</p>
  
  <pre><code>%div(class="modal" id="mainModal ajax-modal" tabindex="-1" role="dialog"){:'aria-labelledby'=&gt;"mainModalLabel", :'aria-hidden'=&gt;"true"}
    %div(class="c-modal__container")
      %div(class="c-modal__layout modal__content") 
        = yield
  </code></pre>
  
  <p>In my <code>application.html.haml</code>, I have a div that defines the modal location as follows:</p>
  
  <pre><code>-# ...
  %div(id="modal-holder")
  
  - unless params[:nojs]
    = javascript_include_tag 'desktop'
  
  -# ...
  </code></pre>
  
  <p>Here is where my problem comes from. I have a <code>book controller</code> where the user can add books. I have a multi-step registration and my <code>new</code> action have to be my modal. When the user clicks <code>New book</code> link, I am loading a new modal.</p>
  
  <p>My <code>New book</code> link:</p>
  
  <pre><code>= link_to "New book", new_book_path, class: "c-link--navbar", data: { modal: true }
  </code></pre>
  
  <p>CoffeeScript(re-written in <code>jQuery</code>) for the modal (this code from <a href="https://jtway.co/5-steps-to-add-remote-modals-to-your-rails-app-8c21213b4d0c" rel="nofollow noreferrer">this article</a>):</p>
  
  <pre><code>$(function() {
    var modal_holder_selector, modal_selector;
        modal_holder_selector = '#modal-holder';
        modal_selector = '.modal';
    $(document).on('click', 'a[data-modal]', function() {
      var location;
      location = $(this).attr('href');
      $.get(location, function(data) {
        return $(modal_holder_selector).html(data).find(modal_selector).modal();
      });
      return false;
    });
    return $(document).on('ajax:success', 'form[data-modal]', 
  
    function(event, data, status, xhr) {
      var url;
      url = xhr.getResponseHeader('Location');
      if (url) {
        window.location = url;
      } else {
        $('.modal-backdrop').remove();
        $(modal_holder_selector).html(data).find(modal_selector).modal();
      }
      return false;
    });
  });
  </code></pre>
  
  <p>And now my <code>new action</code> for the <code>yield</code> that will be loaded inside my remote modal:</p>
  
  <pre><code>= form_for(@book, remote: remote, html: {role: :form}, class: "c-form") do |f|
    -# Forms here...
    = f.submit "Add a new book", class: "c-btn"
  </code></pre>
  
  <p>If the user's information correct, my modal will redirect the user to <code>general action</code> else I want to <strong>stay on the same page</strong> and flash an error message but the problem is that I am not using a <code>partial</code> and it automatically redirects me to a new page with <code>new action</code>. </p>
  
  <p>My <code>books_controller.rb</code>:</p>
  
  <pre><code>class BooksController &lt; ApplicationController
    respond_to :html, :json, :js
    ...
  
    def index
      @books = current_user.books
    end
  
    def new
      @book = current_user.books.build
      respond_modal_with @book
    end
  
    def create
      @book = current_user.books.build(book_params)
  
      if @book.save
        redirect_to general_book_path(@book), notice: "Saved."
      else
        flash.now[:notice] = "Something went wrong."
        render :new
      end
    end
  
    ...
  end
  </code></pre>
  
  <p>Modal Responder:</p>
  
  <pre><code>class ModalResponder &lt; ActionController::Responder
    cattr_accessor :modal_layout
    self.modal_layout = 'modal'
  
    def render(*args)
      options = args.extract_options!
      if request.xhr?
        options.merge! layout: modal_layout
      end
        controller.render *args, options
    end
  
    def default_render(*args)
      render(*args)
    end
  
    def redirect_to(options)
      if request.xhr?
        head :ok, location: controller.url_for(options)
      else
        controller.redirect_to(options)
      end
    end
  end
  </code></pre>
  
  <p>I tried to add something like</p>
  
  <pre><code>respond_to do |format|
    format.html
    format.json { render json: @book }
  end
  </code></pre>
  
  <p>to my <code>create</code> method but it doesn't work and still redirects me to the new page. Also, I've already asked a similar <a href="https://stackoverflow.com/questions/47957120/jquery-ui-autocomplete-in-remote-modal-ror">question</a> and I've noticed that my <code>JavaScript</code> code works on a separate page. As long as I understand the problem is with my remote modal action page. Can someone please help me to figure out how to stay on the same page when the user entered the wrong input and turn on my javascript?</p>