编辑:
我有很多回答用不同的方法解决问题,非常感谢!
可悲的是,直到现在他们都没有工作过。为了便于理解和重现失败,我使用Rspec套件在 GitHub 上创建了一个小型Rails回购。
其中一个规格是传递(在视图中初始化演示者)。 其中一个规格是失败的(演示者在控制器中初始化)。
如何使它们都通过?
下面的原始问题:
这是我的演示者:
class UserPresenter
def initialize(user, vc)
@user = user
@vc = vc
end
def linkify()
#
# HERE IS THE PROBLEM
#
vc.link_to("foo") do
yield
end
end
end
这是我的控制器:
我在控制器中初始化我的Presenter,使用提供的模型传递控制器的视图上下文。
class UserController
def show
@user = User.find(#.....
@presenter = UserPresenter.new(@user, view_context)
end
end
在我的Slim模板中,我调用我的Presenter将内容放在链接中:
=@presenter.linkify do
p "123"
我的问题是,我无法将视图中的块传递给我的linkify
方法。
在带有上述代码的注释中,传递的块是整个视图内容,而不是p 123
。
当我在视图中通过@presenter = UserPresenter.new(@user, self)
初始化我的Presenter时,它会按预期工作。
如何使linkify方法使用提供的块,而不在视图中初始化演示者?
答案 0 :(得分:2)
因为如果要使用yield命令,则不能指定&块,因为现在您使用常规参数语法有效地接收块作为参数。
class UserPresenter
def initialize(user, vc)
@user = user
@vc = vc
end
def linkify() # <-- Remove &block
vc.link_to("foo") do
yield
end
end
end
# ...
# Somewhere else, assuming you have access to @presenter which is an instance of
# UserPresenter
# ...
def show
@presenter.linkify do
# ...
# do my view stuff here
# ...
end
end
show()
# Now, if your "View" is nothing but a block that needs to get passed in
# then you'd do this...
def show(&block)
@presenter.linkify do
block.call()
end
end
# This would be used this way:
show(lambda {
# ...
# View stuff here
# ..
})
答案 1 :(得分:2)
如长曲棍球的回答所述。错误的视图上下文是此原因的根源。我试图为你的情况做一个解决方案。而且,这就是结束这样做的原因:
我在ApplicationHelper
中创建了一个帮助方法:
module ApplicationHelper
def link(presenter)
presenter.linkify(self) do
yield
end
end
end
将linkify()更改为:
def linkify(vc)
vc.link_to("foo") do
yield
end
end
这意味着,无需在演示者的类构造函数中使用 vc ,或者您可以更新帮助程序中定义的link
方法中的 vc (您的选择) )。
视图现在看起来像这样:
<强> presenter_from_view.html.slim 强>:
-@presenter = UserPresenter.new(@user, self)
=link @presenter do
p 123
<强> presenter_from_controller.html.slim 强>:
=link @presenter do
p 123
我同意,也许这不是您希望解决方案的完成方式。但是,我无法为此做任何更清洁的工作。但是,在这里不必须担心关于在self
的任何地方传递link @presenter do..
(这对于编写代码可能会变得过多)当你在多个视图中使用linkify时,我想)。
P.S。:你的所有规格现在都过去了。而且,如果您需要修改后的代码,那么我可以将其推送到您的存储库中的单独分支。让我知道。
答案 2 :(得分:2)
来自助手和捕获的Slim's documentation:
module Helpers
def headline(&block)
if defined?(::Rails)
# In Rails we have to use capture!
"<h1>#{capture(&block)}</h1>"
else
# If we are using Slim without a framework (Plain Tilt),
# this works directly.
"<h1>#{yield}</h1>"
end
end
end
您可以尝试按如下方式使用捕获吗?
def linkify(&block)
result = capture(&block)
vc.link_to("foo") do
result
end
end
答案 3 :(得分:1)
错误的视图上下文导致此问题。只需将UserPresenter#initialize
更改为不接受视图上下文,在控制器中初始化演示者并从视图中传递正确的视图上下文,如下所示:
= @presenter.linkify(self) do
p "123"
答案 4 :(得分:1)
你得到什么错误?只看代码......
在这个方法中
def linkify()
#
# HERE IS THE PROBLEM
#
vc.link_to("foo") do
yield
end
end
vc 定义在哪里?
我认为你的意思是 @vc ,这是你正在初始化的实例变量。
另外作为旁注...在没有变量的ruby方法中,linkify()中的empty()是多余的。你可以消除它们。
另外,您可能需要查看cells gem。因为您基本上在演示者和IMO单元格中镜像这种行为是一种更简洁的方式来实现这一功能。
答案 5 :(得分:1)
我想我知道为什么它不起作用。当您传入控制器中的view_context时,它会在您将view_context传递给演示者时呈现一次,然后在您实际渲染视图时再次呈现。
def initialize(user, vc)
@user = user
@vc = vc
end
# When called from the view:
@presenter = UserPresenter.new(@user, self)
# You're passing the view directly in "as is" and renders as expected.
# However, when you pass it in from the controller:
@presenter = UserPresent.new(@user, view_context)
# you're essentially rendering the view_context in the controller, and then again
# once it renders at the end of your action. That's why you're getting this:
# "<p>123</p><a href="foo"><p>123</p></a>"
每次调用linkify时,您都需要从视图中发送自身,或者您可以使用始终具有视图上下文的应用程序帮助方法。