【问题标题】:Rendering html template outside of controller/Mailer rails在控制器/Mailer rails 之外渲染 html 模板
【发布时间】:2018-12-01 15:57:19
【问题描述】:

我有一种情况要在控制器之外渲染一个 HTML 模板(service/lib 目录下的一个类),我经历了https://api.rubyonrails.org/classes/ActionController/Renderer.html

@template = ApplicationController.render(
        template: 'template',
        layout: mailer_template,
    )

是否将所有实例变量传递给仅渲染方法选项以访问视图(html 模板)中的实例变量或任何其他可用于访问所有实例变量的配置?

FooController.render :action, locals: { ... }, assigns: { ... }

如果我们确实传递了模板/布局文件中正在使用的所有实例变量,我们需要在添加新变量时一直检查。我已经参考了动作控制器和动作视图的流程并得到了这个How are Rails instance variables passed to views?,我如何为非控制器类提供这个流程?

【问题讨论】:

    标签: ruby-on-rails templates ruby-on-rails-5 renderer


    【解决方案1】:

    答案的简短版本是:

    您的服务应将自己作为“演示者”本地传递,并且您的部分应将变量委托回您的服务。

    还有一个更长的答案,但首先要清嗓子……

    在我进入 Rails 5 之前,我开始做“在任何地方渲染”,所以我的方法看起来和你最终会做的有点不同。但是,也许它会有所帮助。

    然后是一些背景......

    我有一个模块(类似于ActsAs::Rendering),其中包含一个名为render_partial 的实例方法,类似于:

    module ActsAs::Rendering
      def render_partial(file_name)
        file_name = file_name.to_s
        render(partial: file_name, locals: {presenter: self})
      end
    end
    

    除此之外还有更多内容,但我认为这会给你一些想法。重要的一点(我们稍后会谈到)是 selfpresenter 的形式传入。

    然后,在我的服务中,我可能会做类似的事情:

    class BatchMailerService < ApplicationService
    
      def call
        render_partial :my_cool_partial
      end
    
      def tell_method_something_good
        "Tell me that you like it, yeah."
      end
    
    end
    

    我猜在 Rails 5 中,你会使用 FooController.render :action, locals: { ... } 位。但是,就像我说的,我还没有开始做这个 Rails 5,所以我不确定。

    当然,我有一个ApplicationService(在app/services 下),看起来像:

    class ApplicationService
      include ActsAs::Rendering
    
      attr_accessor *%w(
        args
      ).freeze
    
      class << self 
    
        def call(args={})
          new(args).call
        end        
    
      end  # Class Methods
    
      #==============================================================================================
      # Instance Methods
      #==============================================================================================
    
        def initialize(args={})
          @args = args
          assign_args
        end
    
      private
    
        def assign_args
          args.each do |k,v|
            class_eval do 
              attr_accessor k
            end
            send("#{k}=",v)
          end
        end        
    
    end
    

    说了这么多……

    :my_cool_partial 可能类似于:

    "my_cool_partial.html.haml"
    
    - @presenter = local_assigns[:presenter] if local_assigns[:presenter]
    
    #tell-me-something-good-container
      = @presenter.tell_me_something_good
    

    现在,如果我这样做:

    BatchMailerService.call    
    

    我会得到类似的东西:

    <div id="tell-me-something-good-container">
      Tell me that you like it, yeah.
    </div>
    

    这样,服务对象就不必传入一长串locals。它只需要自己传递,我只需要确保服务对象响应在部分内部进行的任何调用。

    【讨论】:

      猜你喜欢
      • 2012-12-31
      • 1970-01-01
      • 2015-01-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-14
      • 2014-11-26
      • 2012-07-27
      相关资源
      最近更新 更多