如何修复此 sort_by in collection_select 在浏览器中有效但在 Capybara 中出现 returns "comparison of String with nil failed" 错误

How to fix this sort_by in collection_select works in the browser but returns "comparison of String with nil failed" error in Capybara

我一直在尝试为在浏览器中手动工作的表单编写系统测试。

我有一个 Speaker 型号 has_one :individual。表单字段如下所示:

<fieldset>
  <%= form.label :speaker, "Who said it?" %>
  <%= form.collection_select :speaker_id, Speaker.all.sort_by(&:full_name), :id, :full_name %>
</fieldset>

Speaker 模型中的自定义 full_name 方法如下所示:

  def full_name
    if individual
      "#{individual.first_name} #{individual.last_name}"
    end
  end

if individual 条件是一种气味,但没有它,我得到这个错误:

Minitest::UnexpectedError: ActionView::Template::Error: undefined method `first_name' for nil:NilClass

如果我添加 if individual 条件,则错误如下所示:

Minitest::UnexpectedError: ActionView::Template::Error: comparison of String with nil failed

我很困惑,因为我在其他模型中使用类似的模式按 full_name 对集合选择进行排序,但这是唯一在系统测试中引发错误的模式。当我在浏览器中手动测试时,一切都按预期工作。

我也可以在控制台中的 Individual 模型中访问 first_name last_namefull_name 方法,没问题。

这也不会导致错误(我可以使用 :full_name 在浏览器中显示名称,但它不是按字母顺序排列的:

<%= form.collection_select :speaker_id, Speaker.all, :id, :full_name %>

如何修复 Capybara 中的这个错误?或者有没有更好的方法让 return Speaker.all 中的 collection_select 按字母顺序排序?


更新: 我通过不通过 Speaker 模型传递 Quote / Individual 关系来简化这一点。现在,我的 Quote 模型 belongs_to :individualIndividual has_many :quotes。这也适用于浏览器,但我的系统测试遇到了同样的错误:

<ActionView::Template::Error: undefined method `full_name' for nil:NilClass>

这是因该错误而失败的测试之一...

require "application_system_test_case"

class QuotesTest < ApplicationSystemTestCase
  setup do
    @contributor = users(:contributor)
    @contributor_quote = quotes(:contributor_quote)
    @category = categories(:rock_and_roll)
    @field = fields(:music)
    @topic_one = topics(:recording)
    @topic_two = topics(:songwriting)
    @individual = individuals(:john_lennon)
    @group      = groups(:the_beatles)
  end

  test "visiting the index should be accessible to all" do
    visit quotes_path
    assert_text @contributor_quote.body
    click_on @contributor_quote.body
    assert_current_path quote_path(@contributor_quote)
  end
end

我的 Individual 模型中有这个方法:

def full_name
  "#{first_name} #{last_name}"
end

这是导致失败的视图部分:

  Speaker: <%= @quote.individual.full_name %>

如果我包含 save_and_open_page 错误看起来像这样...

我尝试按照 Thomas 的回答建议添加 .strip,但这无济于事。

同样,唯一的问题是这个系统测试。它在浏览器中运行良好。

在没有实际看到任何测试代码的情况下,无法确定错误的来源,而且我不知道 Capybara 在何处适用。我猜你拥有的是一个 Speaker 模型,它似乎依赖于与之关联的 individual ,但实际上并没有在任何地方强制执行,所以当你在没有关联个体的情况下在测试中创建扬声器实例时,它是没有被标记为无效。如果 Speaker 应该支持没有关联的 individual 那么你的问题是你的 full_name 方法在需要字符串时返回 nil 。要解决这个问题,您可以这样做

def full_name
  "#{individual&.first_name} #{individual&.last_name}".strip
end

individual 存在时给你全名,不存在时给你一个空字符串