6

我的应用中有很多这样的代码:

if @document.template.name == "Newsletter"
  ...
end

我意识到这是糟糕而丑陋的代码。我不确定这种代码有哪些替代方案。有什么最佳实践吗?但愿如此。干杯!

示例控制器代码

在此控制器代码示例中,如果名称为"Newsletter". 我知道这很混乱,而且很多代码都应该移到模型中。我更关心条件。

if @document.template.name == "Newsletter"
  source = Magick::Image.read(@document.component.image_newsletter.path).first
  overlay = Magick::Image.read(@document.user.logo.path).first.resize_to_fit(source.columns)
  rec = Magick::Draw.new
  rec.stroke = "##{@document.user.colour1}"
  rec.fill = "##{@document.user.colour1}"
  rec.rectangle 0, 0, source.rows, 5
  lank = source.extent(source.columns, source.rows+overlay.rows, 0 ,0)
  combo = lank.composite(overlay, Magick::SouthGravity, 0, 0, Magick::OverCompositeOp)
  rec.draw(combo)
  client.update_with_media("#{@document.title}: #{@document.remove_html(@document.components.first.body[0..100])}...", open(combo.to_blob))
else
  client.update("#{@document.title}: #{@document.remove_html(@document.components.first.body[0..100])}... http://domain.com#{share_path(@document.user.ftp, @document)}")
end
4

2 回答 2

5

演示者模式的救援

app/helpers/application_helper.rb

这将使您可以方便地访问在任何视图中的任何位置实例化演示者。

例如,如果您使用present @document它将实例化一个DocumentPresenter.

module ApplicationHelper
  def present object, klass = nil
    klass ||= "#{object.class}Presenter".constantize
    presenter = klass.new object, self
    yield presenter if block_given?
    presenter
  end
end

要覆盖使用的演示者,您可以执行present @document, MyPresenter


应用程序/演示者/document.rb

您的实际演示者。创建尽可能多的实例方法并将所有视图逻辑保留在此处。您可以通过以下方式访问所有视图辅助方法@template

class DocumentPresenter
  def initialize document, template
    @document = document
    @template = template
  end

  def name
    if @document.template.name == "Newsletter"
      # for example ...
      @template.link_to 'Newsletter', @template.document_index_path
    end
  end

  def description
    @template.content_tag :p, @document.description, class: "description"
  end

end

app/views/document/show.html.erb

<% present @document do |document_presenter| %>
    <div id="document">
      <%= document_presenter.description %>
      <%= document_presenter.name %>
    </div>
<% end %>

结果

<div id="document">
  <p class="description">
    lorem ipsum
  </p>
  <a href="/newsletters">Newsletters</a>
</div>

您可以在 Ryan Bates 的 RailsCast 剧集“Presenters from Scratch”中了解有关演示者模式的更多信息

于 2013-11-08T00:02:30.427 回答
2

目前我能想到的唯一选择是将特定于模板的代码移动到Template模型中,分成遵循特定命名约定的各个方法。

例如,您的方法可以遵循约定process_x,其中x是模板的名称。在这种情况下,您为“时事通讯”发布的代码将位于名为process_newsletter.

我还将创建一个单一的入口点,让我们process在同一个模型中调用它,它负责委托给这些方法之一,如下所示:

class Template < ActiveRecord::Base
    ... other model code

    def process # this is the method to be called from the controller
        method_name = "process_#{self.name}" # the name of the method to be called
        send method_name # call a method by this name
    end

    def process_newsletter
        # your newsletter code already posted
    end

    def process_article # another example for illustration purposes
       # article specific code
    end
end

这不仅消除了对模板名称检查的需要,还有助于进一步分离代码,并将任何特定于模型的东西从控制器中移开。

于 2013-11-08T03:39:59.523 回答