【问题标题】:How do I share a single index page between multiple controllers in Rails 4如何在 Rails 4 中的多个控制器之间共享单个索引页面
【发布时间】:2014-09-23 02:01:37
【问题描述】:

我创建了一个包含可搜索属性和分页的部分,以替换默认的 rails 脚手架索引视图。它在单个模型/控制器上运行良好,现在我的目标是以最干燥的方式与我的其他控制器共享这个部分。我的想法是应该有一种方法可以从控制器中指定要加载的视图,这样我就可以从所有控制器的 index 方法中加载相同的视图.我对其他解决方案持开放态度,只要它们是 DRY 或关于如何以更“轨道方式”更好地实现我的目标的建议。下面是我当前的工作实现,这需要我遍历大约 13 个模型并在每个索引方法中调用 super 并用下面的示例替换 index.html.erb 文件(这会产生 13 个相同的索引文件)。我希望能够在每个索引方法中执行以下操作并称其为好:

理想代码

def index
    super
    load_this_custom_page 'shared/index'  # this is the line I'm looking for
end

当前代码

控制器:

def index
    super
end

应用控制器:

include Modules::TableUI
def index
    results = get_paged_search_results(params)
    params = results[:params]
    @instances = results[:instances]
end

modules.rb

module Modules
    module TableUI
        def get_paged_search_results(params)
            params[:per_page] = 10 if params[:per_page].blank?
            params[:page] = 1 if params[:page].blank?

            unless params[:columns].blank? || params[:controller].blank?
                model = eval(params[:controller].classify)
                where_clause = ""
                params[:columns].each do |name, value|
                    unless value.blank?
                        where_clause << "(#{model.table_name}.#{name} like '%#{value}%') AND "
                    end
                end
                where_clause << " (1=1)"
                result_set = model.where(where_clause)
                instances = model.paginate(page: params[:page] ,:per_page => params[:per_page]).merge(result_set)

                return {instances:instances,params:params}
            end

            # there has got to be a better way to do this... I just can't find it
            instances = eval(self.class.name.gsub("Controller","").singularize).page(params[:page])
            return {instances:instances,params:params}
        end
    end
end

index.html.erb

<%= render  :partial => 'shared/model_table', 
            :locals => {
                :model => @instances.model, 
                :instances => @instances
            } 
%>

_model_table.html.erb

<h1><%= model.model_name.human.pluralize %></h1>

<%= form_tag("/#{model.model_name.route_key}", method: "get") do %>
    Show <%= select_tag :per_page, options_for_select([ 10,25,50,100 ], params[:per_page]) %> entries
    <%= hidden_field_tag(:page, params[:page]) %>
    <%= submit_tag("Update table") %>

    <table>
        <thead>
            <tr>
                <% model.column_names.each do |name| %>
                    <th><%= model.human_attribute_name(name) %></th>
                <% end %>
                <th colspan="3"></th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <% instances.column_names.each_with_index do |attr, i| %>
                    <td><%= text_field_tag("columns[#{attr}]", params[:columns] ? params[:columns][attr] : nil) %></td>
                <% end %>
            </tr>
            <% instances.each do |instance| %>
                <tr>
                    <% instance.attribute_names.each do |attr| %>
                        <td><%= instance[attr.to_sym] %></td>
                    <% end %>
                    <td><%= link_to 'Show', instance %></td>
                    <td><%= link_to 'Edit', "/#{model.model_name.route_key}/#{instance.id}/edit" %></td>
                    <td><%= link_to 'Destroy', instance, method: :delete, data: { confirm: 'Are you sure?' } %></td>
                </tr>
            <% end %>
        </tbody>
    </table>
<% end %>

<%= will_paginate instances %>

<br>

<%= link_to "New #{model.model_name.human}", "/#{model.model_name.route_key}/new" %>

【问题讨论】:

  • 为什么不从控制器调用渲染?
  • 完美的@Mohammad,正是我想要的。我最终将render 'shared/index' 放入controller#index 并删除了我所有的索引页。如果您关心投票,请创建一个答案,我会接受。

标签: ruby-on-rails routing dry templating partials


【解决方案1】:

Rails 中的每个控制器都会尝试使用 app/views/layouts/application.html.erb,除非您另有说明。您可以为您的索引操作创建一个自定义布局,并从该新布局文件呈现您的共享模板。

布局:

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

并在您的索引操作中呈现它。这可以通过将此行添加到您的 ApplicationController 来实现:

layout 'layout_with_table', :only => [:index]

【讨论】:

    【解决方案2】:

    我不知道什么最适合您,但您可以在控制器中完成所有处理并传递给应用程序控制器进行渲染,例如

    class SomeContorller < ApplicationController
      def index
        @x = 'some variable'
        super
      end
    end
    class ApplicationController < ActionController::Base
      def index
        render 'shared/index'
      end
    end
    

    另外说明一下,尽量避免使用eval,因为它容易受到注入攻击,而是使用constantize,替换此行

    model = eval(params[:controller].classify)
    

    有了这个

    model = params[:controller].classify.constantize
    

    还有

    instances = eval(self.class.name.gsub("Controller","").singularize).page(params[:page])
    

    instances = self.class.name.gsub('Controller','').singularize.constantize.page(params[:page])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-30
      • 1970-01-01
      • 1970-01-01
      • 2019-10-02
      • 1970-01-01
      • 2016-02-13
      • 2013-06-19
      • 1970-01-01
      相关资源
      最近更新 更多