Rails:如何仅在 bootstrap 手风琴打开时从数据库动态加载它

Rails: How can I dynamically load from db into a bootstrap accordion only if it opens

我正在使用 Awesome Nested Set gem 现在创建一个层次结构 我想显示这个层次结构。

我有一个包含典型控制器操作的索引页

klasses_controller.rb

def index
   @klasses = Klass.where(depth: 0).order('lft ASC')
end

klasses/index.rb

<div id="accordion" role="tablist" aria-multiselectable="true">
    <% @klasses.each do |klass| %>
        <%= render :partial => "klass", locals: {klass: klass} %>
    <% end %>
</div>

在我的索引操作中,我调用了一个部分

klasses/_klass.html.erb

<div class="klass">
    <div class="klass-header" role="tab" id="heading-<%=klass.id%>">
      <h5 class="mb-0">
        <a data-toggle="collapse" 
           data-parent="#accordion" 
           href="#collapse-<%=klass.id%>" 
           aria-expanded="false" 
           aria-controls="collapse-<%=klass.id%>">

           <%= klass.symbol + " : " + klass.title%>
        </a>
      </h5>
    </div>

    <div id="collapse-<%=klass.id%>" 
        class="collapse" 
        role="tabpanel" 
        aria-labelledby="heading-<%=klass.id%>">

      <div class="klass-block">
         <Here is where I want to render partial for each child>
      </div>
    </div>
</div>

这是标准的手风琴,可以按原样工作。这是我有一个非常大的数据库的问题,我不想渲染任何不必要的东西。我想等到 header 被单击,然后异步检索我单击的 class 的 children,并使用相同的部分渲染每个。

我怎样才能做到这一点?有没有办法使用 route/controller 动作组合,或者我应该开始写 coffee/java-script?我并不是要重新发明轮子,所以如果有人知道一个例子,那将是受欢迎的。

这是一个棘手的问题,只是因为有很多活动部件。这真是一个令人头疼的问题,但事后看来它非常简单。

首先,我想使用自定义控制器操作,因此我为我的 "children" 方法添加了一条路由,该方法设置为接收 ajax 调用。

routes.rb

get 'klasses/:id/children', to: 'klasses#children', as: 'children_of'

klasses_controller.rb

def index
    @klasses = Klass.where(depth: 0).order('lft ASC')
end

def children
  respond_to do |format| 
      format.js {render 'children', :klass => @klass }
  end
end

此响应块需要 children.js.erb 调用。

children.js.erb

$("#collapse-<%=@klass.id%>").html("<%= escape_javascript(render :partial => 'klasses/children',    locals: { :klass => @klass })%>");

这是我们指定要插入新内容的 div 的地方,我们称之为另一个部分。

_children.html.erb

<div class="child-block">
    <% children = @klass.children %>
    <% children.each do |child| %>
         <%= render :partial => 'klasses/klass', locals: { :klass => child } %>
    <% end %>
</div>

最后我重写了我的 _klass.html.erb 部分所以它在标题中有一个 link 将触发 bootstrap 的手风琴 js 并调用我们的新控制器动作。

_klass.html.erb

<div class="klass">
    <div class="klass-header" role="tab" id="heading-<%=klass.id%>">
      <h5 class="mb-0">

    <%= link_to klass.symbol + " : " + klass.title,
                children_of_path(klass.id), 
                remote: true,
                :data => {  :toggle => "collapse", 
                            :parent => "#accordion",
                            :target => "#collapse-#{klass.id}"

                },
                :aria => {  :expanded => "false", 
                            :controls => "collapse-#{klass.id}"
                }%>
      </h5>
    </div>

    <div id="collapse-<%=klass.id%>" 
        class="collapse" 
        role="tabpanel" 
        aria-labelledby="heading-<%=klass.id%>">

    </div>
</div>

差不多就这些了。在 child-block 中添加一些填充,您将拥有一个漂亮的缩进层次结构,可以动态加载内容。

我确实必须为我的控制器中的自定义操作禁用跨站点请求伪造

protect_from_forgery :except => :children

如果有人知道解决方法,请告诉我。