可重复使用的远程模态 Rails

Posted

技术标签:

【中文标题】可重复使用的远程模态 Rails【英文标题】:Reusable remote modal Rails 【发布时间】:2018-06-09 02:16:59 【问题描述】:

我正在尝试创建一个可重用的远程模式。这个想法是创建一个模型容器并将带有yield 的内容渲染到其中并在需要时渲染内容。

注意:所有html 代码都将写入HAML。我正在使用bootstrap-modal-rails gem 来处理我的模态。

我的模态容器布局(不是部分):

%div(class="modal" id="mainModal ajax-modal" tabindex="-1" role="dialog"):'aria-labelledby'=>"mainModalLabel", :'aria-hidden'=>"true"
  %div(class="c-modal__container")
    %div(class="c-modal__layout modal__content") 
      = yield

在我的application.html.haml 中,我有一个 div,它定义了模态位置,如下所示:

-# ...
%div(id="modal-holder")

- unless params[:nojs]
  = javascript_include_tag 'desktop'

-# ...

这就是我的问题所在。我有一个book controller,用户可以在其中添加书籍。我有一个多步骤注册,我的new 操作必须是我的模态。当用户点击New book链接时,我正在加载一个新的模式。

我的New book链接:

= link_to "New book", new_book_path, class: "c-link--navbar", data:  modal: true 

CoffeeScript(用jQuery重写)用于模态(此代码来自this article):

$(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;
  );
);

现在我的new action yield 将被加载到我的远程模式中:

= form_for(@book, remote: remote, html: role: :form, class: "c-form") do |f|
  -# Forms here...
  = f.submit "Add a new book", class: "c-btn"

如果用户的信息正确,我的模式会将用户重定向到 general action 否则我想留在同一页面上并显示错误消息,但问题是我没有使用partial 它会自动将我重定向到带有new action 的新页面。

我的books_controller.rb

class BooksController < 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

模态响应器:

class ModalResponder < 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

我尝试添加类似的东西

respond_to do |format|
  format.html
  format.json  render json: @book 
end

到我的create 方法,但它不起作用,仍然将我重定向到新页面。另外,我已经问过类似的question 并且我注意到我的JavaScript 代码在单独的页面上工作。只要我了解问题出在我的远程模态操作页面上。当用户输入错误的输入并打开我的javascript时,有人可以帮我弄清楚如何留在同一页面上吗?

【问题讨论】:

如果您不希望您的页面被重定向。只需返回不带标题的 ajax 响应: location @plonknimbuzz 我想在ajax:success 上重定向并在ajax:error 时保持在同一页面上......我猜我的ajax 和控制器设置有问题。非常感谢您的回复:) 你好.. 我检查了你的 github 个人资料。这不是开源项目吗?通过调试它可能很容易找到解决方案......如果你让我分叉你的项目,否则我可以更深入地了解 @FabrizioBertoglio 您好,我将在接下来的一两个小时内创建一个新项目,并在 cmets 中通知您!非常感谢您的帮助和时间! 我仍在调查您的 SO 帖子。您从未得到问题答案的原因是您没有正确编写它们。您的问题包含太多信息,并且从某种角度来看,它非常广泛。我的建议是尝试将您的问题分解为不同的部分。例如,您有第 1、2、3、4 步。第 1、2、4 步有效,因为您调试了流程,所以第 3 步是问题所在。然后创建一个简单的项目,如果您以简化的方式重新创建问题(步骤 3)。问题依然存在?然后将其发布在SO上。它不是?这是您可以用来解决问题的线索 【参考方案1】:

TBH 这是一个与您的问题没有直接关系的抽象解决方案,但它可以工作(bootstrap+jq,基于生产代码)

咖啡脚本

$.showModal = (title, body) ->
    $("#modal").find(".modal-title").html(title)
    $("#modal").find(".modal-body").html(body)
    $("#modal").modal("show")
$("#modal").find(".modal-submit").click () ->
    $("#modal").find("form").submit()

Html - 典型的引导模式

<div id="modal" class="modal" tabindex="-1" role="dialog">
  <div class="modal-dialog modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title"></h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="<%= t :close %>" title="<%= t :close %>">
          <span aria-hidden="true"></span>
        </button>
      </div>
      <div class="modal-body">
        <p></p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-danger" data-dismiss="modal"><%= t :close %></button>
        <button type="button" class="btn btn-success modal-submit"><%= t :save %></button>
      </div>
    </div>
  </div>
</div>

new.js.erb 或其他 Rails 视图

$.showModal(
    "<%= escape_javascript t :edit_comment %>",
    "<%= escape_javascript(render 'form', :comment => @comment) %>"
);

打开模式的链接

<%= link_to t(:new), [:new, comment], :remote => true, class: "btn" %>

您可能想使用自己的 ajax 请求 - 如果服务器错误/超时,此请求将无济于事

【讨论】:

非常感谢您的回答!真的很感谢你的时间。将尝试实施您的解决方案。

以上是关于可重复使用的远程模态 Rails的主要内容,如果未能解决你的问题,请参考以下文章

Rails 为重复的 JSON 请求自动更新 CSRF 令牌

提交后禁用Rails中的link_to按钮以防止重复提交

Bootstrap:模态而不是模态[重复]

没有模态的打印页面[重复]

模态文本在其他模态中重复

Semantic-ui 模态与 VueJS 重复