答案的简短版本是:
您的服务应将自己作为“演示者”本地传递,并且您的部分应将变量委托回您的服务。
还有一个更长的答案,但首先要清嗓子……
在我进入 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
除此之外还有更多内容,但我认为这会给你一些想法。重要的一点(我们稍后会谈到)是 self 以 presenter 的形式传入。
然后,在我的服务中,我可能会做类似的事情:
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。它只需要自己传递,我只需要确保服务对象响应在部分内部进行的任何调用。