【问题标题】:How do I make this nested iterator check be much more DRY and efficient?如何使这个嵌套迭代器检查更加干燥和高效?
【发布时间】:2017-03-10 23:34:12
【问题描述】:

我有一个@commit 那个has_many :diffs,所以我有一个@diffs = @commit.diffs

每个diff 都有一个.body,其中包含一个字符串。

我遇到的问题是我需要能够快速检查属于 commit 的每个 diffbody 以查看它是否满足某些条件(即 body.include? (line_count - 3).to_s)。如果是这样,我想保存/使用那个diff

我实现它的方式是这样做:

<% @diffs.each do |diff| %>
    <% if diff.body.include? (line_count - 3).to_s %>
      <% diff.body.lines.each do |dl| %>

      <% end %>
    <% end %>
  <% end %>

这似乎不优雅。我怎样才能让它更干燥、更高效、更清洁?

我也想把这个从我的视野中移开,并进入一个助手/装饰器之类的东西。

【问题讨论】:

  • 在某些事情上调用to_s 几乎可以保证您得到一个字符串,并且任何字符串在逻辑上总是正确的。该条件永远不会触发。

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


【解决方案1】:

一般来说,这种逻辑不应该出现在视图中是正确的。我建议为此使用装饰器。看看Draper gem 来帮助解决这个问题。以下是您如何使用 Draper 执行此操作的示例。

# In you controller
class YourController < ApplicationController
  # ...
  @diffs = @commit.diffs.decorate # after adding draper, add `.decorate` to this line in the controller
  # ...
end

# In a Draper decorator
class DiffDecorator < Draper::CollectionDecorator
  def get_some_subset_of_the_diffs
    decorated_collection.select { |diff| diff.body.include? (line_count - 3).to_s }
  end
end

# Your view
<% @diffs.get_some_subset_of_the_diffs.each do |diff| %>
  <% diff.body.lines.each do |dl| %>

  <% end %>
<% end %>

另外,你想用diff.body.include? (line_count - 3).to_s 完成什么?在某些情况下,这可能会运行,但这可能不会执行您想要的逻辑。是否应该检测更改少于 3 行的差异?

【讨论】:

  • 回复:你的问题,不......逻辑是检查diff.body的字符串值,看看它是否包含line_count - 3的值,它返回一个整数,然后我需要将其转换为字符串——这就是 .to_s 所做的。
  • 在这种情况下,您可以使用select 实现此目的。更新了我的答案以反映这一点。
【解决方案2】:

为什么不将大部分逻辑转移到您的模型中?假设您有 CommitDiff 模型,您可以:

# NOTE: you'll want to change the name "affected" to something that is more meaningful. I don't quite understand what matching on the line count is meant to do here.

class Commit
  def affected_diffs(line_count)
    # the `@diffs ||=` part is optional memoization (read more here: http://gavinmiller.io/2013/basics-of-ruby-memoization/)
    # it can be helpful for performance if you call this method multiple times in your view
    @diffs ||= diffs.select { |diff| diff.affected?(line_count) }
  end
end

class Diff
  # no need to rewrite this logic if you also choose to use it elsewhere
  def affected?(line_count)
    body.include? (line_count - 3).to_s
  end
end

# then in your view
<% @commit.affected_diffs(line_count).each do |diff| %>
  <%# work with each diff %>
<% end %>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-16
    • 1970-01-01
    • 1970-01-01
    • 2015-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多