如果有人有更好的方法来实现相同的预期效果,但结构不同,我很高兴放弃这个设计。
我在这里的动机是创建一个继承的 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" %>
文件夹树
- 应用程序
- 意见
- 小部件
- 模块
- 模板
- template_custom_1
- template_custom_2
- 活动
- 模板
- 内容
- 模板
- 图片
- 模板
- 社区
- 模板
- 模块
- 模板
- template_custom_a
- template_custom_b
- 活动
- 模板
- 内容
- 模板
- 图片
- 模板
- 用户
- 模板
- 模块
- 模板
- 活动
- 模板
- 内容
- 模板
- 图片
- 模板
- 模块
- 小部件
- 意见
因此,一些路径示例以及我希望文件夹的模板链能够解决的地方。
- /widgets/modules.js
- /小部件/模块/模板
- /widgets/communities/1/modules.js?template=custom_a
- /widgets/communities/modules/template_custom_a
- /widgets/communities/modules/template
- /小部件/模块/模板
我失败的实施
只想说,这离工作太近了。不幸的是,我在解析器(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 中当前的部分工作目录是什么?如果我知道这一点,我可以跳过它上面的所有模板,并且永远不会得到无限递归。