Rails FileSystemResolver - 实现自定义模板继承

时间:2012-08-31 16:03:55

标签: ruby-on-rails-3 template-engine actionpack

如果有人有更好的方法来达到同样的预期效果,结构不同,我很高兴放弃这种设计。

我的动机是创建一个继承的javascript小部件模板系统,以便在Rails 3中使用。我希望用户可以在他们的页面上放置javascript小部件,并拥有各种可供选择的预定义模板。

理想情况下,每个模板都有“基本”javascript代码,任何自定义都可以通过一组子模板进行分层(从而为模板创建外观/新功能)。

这很复杂,因为我想为同一个模板使用多个控制器。

控制器

文件夹树
  • 应用
    • 控制器
      • 小窗口
        • 模块
        • 活动
          • 含量
          • 图像
        • 社区
          • 模块
          • 活动
            • 含量
            • 图像
        • 用户
          • 模块
          • 活动
            • 含量
            • 图像

视图

关于视图的注释,在每个“模板”目录中,我放置了一个名为config.rb的文件。此文件定义模板父模板名称和文件夹位置。我将在模板解析器中显示它是如何加载的。

示例继承配置文件

位于app / views / widgets / communities / modules / template_custom_2 / config.rb


module InheritedTemplateConfig
    def inherited_parent_base_path
        "widgets/communities/modules"
    end

    def inherited_parent_template_name
        "template_custom_1"
    end
end

位于app / views / widgets / communities / modules / template_custom_1 / config.rb


module InheritedTemplateConfig
    def inherited_parent_base_path
        "widgets/communities/modules"
    end

    def inherited_parent_template_name
        "template"
    end
end

位于app / views / widgets / communities / modules / template / config.rb

module InheritedTemplateConfig
    def inherited_parent_base_path
        "widgets/communities"
    end

    def inherited_parent_template_name
        "template"
    end
end
示例模板文件

位于app / views / widgets / communities / modules / template_custom_2 / modules.js.erb

<%= render :partial => "(TEMPLATE)/same_template_test" %>
<%= render :partial => "(PARENT_TEMPLATE)/parent_template_test" %>

文件夹树

  • app
    • views
      • 小部件
        • modules
          • template
          • template_custom_1
          • template_custom_2
        • 活动
          • 模板
          • 含量
            • 模板
          • 图像
            • 模板
        • 社区
          • 模板
          • 模块
            • 模板
            • template_custom_a
            • template_custom_b
          • 活动< UL>
          • 模板
          • 含量
            • 模板
          • 图像
            • 模板
      • 用户
        • 模板
        • 模块
          • 模板
        • 活动
          • 模板
          • 含量
            • 模板
          • 图像
            • 模板
    < / LI>

所以,一些路径示例以及我希望解决文件夹模板链的位置。

  • /widgets/modules.js
    • /部件/模块/模板
  • /widgets/communities/1/modules.js?模板= custom_a
    • /部件/社区/模块/ template_custom_a
    • /部件/社区/模块/模板
    • /部件/模块/模板
    • < / ul>

    我的失败实施

    只想说,这是所以接近工作。不幸的是,我在解析器(PARENT_TEMPLATE)find_template函数的情况下有0运气,它无限地递归。这是因为我无法知道在解析时要跳过哪个模板。

    唯一不起作用的是使用<% render :partial => "(PARENT_TEMPLATE)/my_file" %>

    渲染部分内容
    class Widgets::Communities::ModulesController < ApplicationController
        before_filter do
            @community = Community.find(params[:community_id])
    
            @template = params[:template].to_s
            @template = "_#{@template}" if !@template.empty?
    
            # Path to start searching for template files
            prepend_view_path WidgetResolver.new("widgets/communities/modules", "template#{@template}")
        end
    
        def script
            respond_to do |format|
                format.js { render "modules" }
            end
        end
    end
    
    
    # Walks through from the sub_path to the base_path to find the template file
    # This allows you to base one template on another template
    class WigetResolver < ActionView::FileSystemResolver
        attr_accessor :templates, :base_path
    
        # Loads our current templates config, and any parent templates config
        def load_template_config(base_path, template_name)
            config_path = "#{Rails.root}/app/views/#{base_path}/#{template_name}/config.rb" 
            if File.exists?(config_path)
                self.templates << {:template_name => template_name, :base_path => base_path} # This is a valid template, add it to our search path
                load(config_path)
                extend InheritedTemplateConfig
                if !self.inherited_parent_base_path.nil? && !self.inherited_parent_template_name.nil?
                    self.load_template_config(self.inherited_parent_base_path, self.inherited_parent_template_name)
                end
            end
        end
       def initialize(base_path, template_name)
            self.templates = []
            # From our base config, load our complete config
            self.load_template_config(base_path, template_name)
            super("app/views")
        end
    
        def find_templates(name, prefix, partial, details)
    
            # We want to use our custom template matching
            if prefix.match(/^(TEMPLATE)/)
                self.templates.each_with_index { |template,i|
                    result = super(name, "#{template[:base_path]}/#{template[:template_name]}", partial, details)
    
                    # We found the custom template path
                    return result if result.present?
                }
            # ----------------------------------------------------
            # ERROR HERE - recurses to max depth
            # ----------------------------------------------------
            elsif prefix.match(/^(PARENT_TEMPLATE)/)
                self.templates.each_with_index { |template,i|
    
                    # We need to skip template above the current partials template file path - HOW DO WE DO THIS?!
    
                    result = super(name, "#{template[:base_path]}/#{template[:template_name]}", partial, details)
    
                    # We found the custom template path
                    return result if result.present?
                }
            end
    
            super(name, prefix, partial, details)
        end
    
    end
    

    所以 - 问题。我如何知道find_templates中当前的部分工作目录是什么?如果我知道这一点,我可以跳过它上面的所有模板,永远不会得到无限的递归。

0 个答案:

没有答案