关于rails中的演示者模式。这是一个更好的方法吗?

时间:2010-05-12 19:55:24

标签: ruby-on-rails mvp

我的模特中有:

def presenter
   @presenter ||= ProfilePresenter.new(self)
   @presenter
end

ProfilePresenter是一个具有get_link(),get_img_url(size),get_sex(),get_relationship_status()等方法的类,以及与模型无关的其他方法,甚至不是控制器,而是使用多个方法在视图中的时间。

所以现在我通过这样做来使用它们:

Profile.presenter.get_link
# or
Profile.presenter.get_img_url('thumb') # returns the path of the image. is not used to make a db query

我认为我错过了演示者的真实概念..但这就是我试图存档的内容,怎么可以称之为?

1 个答案:

答案 0 :(得分:16)

通常这种事情是通过辅助方法处理的,例如:

def profile_link(profile)
  profile.link ? content_tag(:a, h(profile.name), :href => profile.link) : 'No profile'
end

遗憾的是,您无法在查看时扩展模型的Presenter样式辅助方法中进行分层。它们需要以一种参数,一种反OO的程序方式被调用。

Rails MVC区域并不完全支持Presenter方法,因为它需要绑定到视图才能访问正确呈现内容所需的各种帮助程序方法,以及可能影响表示的会话信息。

更强大的方法可能是做这样的事情:

class ProfilePresenter
  def initialize(view, profile)
    @profile = profile
    @view = view

    yield(self) if (block_given?)
  end

  def link
    @profile.link ? @view.content_tag(:a, @view.h(profile.name), :href => @profile.link) : 'No profile'
  end

  def method_missing(*args)
    @profile.send(*args)
  end
end

这会在您的视图中显示为:

<% ProfilePresenter.new(self, @profile) do |profile| %>
<div><%= profile.link %>
<% end %>

你可以通过制作一个有点疯狂的帮助方法来简化调用:

def presenter_for(model)
  "#{model.class}Presenter".constantize.new(self, model) do |presenter|
    yield(presenter) if (block_given?)
  end
end

这意味着你有一个更简单的电话:

<% presenter_for(@profile) do |profile| %>
<div><%= profile.link %>
<% end %>