从Model内部访问ActionView帮助程序

我有一个简单的模板系统,它在渲染模板时调用在我的模型的不同类(有点小部件)中定义的show_me方法。 这些小部件最初将html作为字符串返回。 所以在我的erb中我有这样的想法。

    

随着小部件的视图变得更加复杂,我开始使用partials来渲染它们,从我的小部件内部调用ActionView::Base渲染方法(请不要呕吐:)

 def show_me # ... specific calculations and other magic. ActionView::Base.new(MyApp::Application.config.view_path).render(:partial => "widgets/weather_widget", :locals => {:data => data, :settings => settings}) end 

所以,这就像一个魅力(真的……),但是当我想在小部件特定部分内部使用帮助器(例如widgets/_weater_widget.html.erb )时,它们不起作用。 例如。 javascript_tag加注

 can't convert nil into String actionpack (3.0.0) lib/action_view/helpers/asset_tag_helper.rb:790:in `join' actionpack (3.0.0) lib/action_view/helpers/asset_tag_helper.rb:790:in `rails_asset_id' actionpack (3.0.0) lib/action_view/helpers/asset_tag_helper.rb:813:in `rewrite_asset_path' actionpack (3.0.0) lib/action_view/helpers/asset_tag_helper.rb:742:in `compute_public_path' actionpack (3.0.0) lib/action_view/helpers/asset_tag_helper.rb:256:in `javascript_path' actionpack (3.0.0) lib/action_view/helpers/asset_tag_helper.rb:822:in `javascript_src_tag' actionpack (3.0.0) lib/action_view/helpers/asset_tag_helper.rb:362:in `block in javascript_include_tag' actionpack (3.0.0) lib/action_view/helpers/asset_tag_helper.rb:362:in `collect' actionpack (3.0.0) lib/action_view/helpers/asset_tag_helper.rb:362:in `javascript_include_tag' 

我想在创建ActionView :: Base时我遗漏了一些东西。

有什么想法如何解决这个问题? 此外,欢迎任何有关整体设计的建议:)

请关注所有事情,MVC不会从模型中呈现视图代码。 :(总有一种更好的方法来做到这一点。

例:

模型

 class Widget < ActiveRecord::Base def name "weather_widget" end def settings ## something here end def data ## calculations here end end 

帮手

 module WidgetHelper def render_widget(widget) render(:partial => "widgets/_#{widget.name}", :locals => {:data => widget.data, :settings => widget.settings}) end end 

视图

 <% @template.widgets.each do |widget| %> <%= render_widget(widget) %> <% end %> 

显然,这可能不是您的情况的确切解决方案,但只是向您展示可以保持您的代码清洁的一些指南。 🙂

您可以通过模型调用视图帮助程序,但Rails会在每一步都为您提供帮助。 Rails不希望你做这样的事情。

考虑引入一个小部件演示者类。 它可以生活在app/helpers,比如

 module WidgetHelper class WidgetPresenter < Struct.new(:widget) def show_me render(:partial => "widgets/#{widget.class}/show", :locals => {:widget => widget }) end end def show_widgets(template) @template.widgets.map do |widget| WidgetPresenter.new(widget).show_me end.join end end 

这样,您可以使用OO技术在窗口小部件演示者之间共享表示逻辑,并且您可以通过将信息与其演示文稿隔离来保持Rails的快乐(以及未来的开发人员)。

Interesting Posts