包含两个表记录的循环数组

时间:2014-05-22 19:57:21

标签: ruby-on-rails ruby ruby-on-rails-4

当我尝试遍历一个包含来自两个表的记录的数组时,如果它无法从另一个记录中找到该属性,则会出错。

该数组有两种不同类型的元素。一个开头是:#<Question id: 1,,另一个以#<Answer id: 1,开头。如果没有它在另一个中寻找它,你如何得到一个的价值?

错误:

undefined method `option' for #<Question:0x007fcc2c6610e8>

如何在需要时绕过或遍历此数组以显示属性值?

控制器:

@pdf = []
@test = Test.find(params[:id])
@test_questions = @test.questions
answers = Answer.all
@all_answers = answers.group_by(&:question_id)
@test_questions.each do |q|
  @pdf << q
  @pdf += @all_answers[q.id]
end

我试图仅显示内容属性值的html,然后是所有选项属性值

<tbody> 
<% @pdf.each do |test| %>
  <tr>
    <td><%= test.id %></td>
    <% if test.content %>
    <td><%= test.content %></td>
    <% end %>
    <% if test.option %>
    <td><%= test.option %></td>
    <% end %>
  </tr>
<% end %>
</tbody>

这就是数组的样子:

[#<Question id: 1, content: "How did the chicken cross the road?", question_type: "MC", category: "ip_voice", product_id: 8, active: true, created_at: "2014-05-07 17:10:14", updated_at: "2014-05-07 17:10:14", user_id: 1>, #<Answer id: 1, option: "It walked", question_id: 1, correct: false, created_at: "2014-05-07 17:10:14", updated_at: "2014-05-07 17:10:14">, #<Answer id: 2, option: "It was thrown", question_id: 1, correct: true, created_at: "2014-05-07 17:10:14", updated_at: "2014-05-07 17:10:14">, #<Answer id: 3, option: "It got run over and pushed", question_id: 1, correct: false, created_at: "2014-05-07 17:10:14", updated_at: "2014-05-07 17:10:14">, #<Question id: 2, content: "Is this working?", question_type: "TF", category: "ip_voice", product_id: 6, active: true, reated_at: "2014-05-13 16:10:53", updated_at: "2014-05-13 16:10:53", user_id: 1>, #<Answer id: 4, option: "False", question_id: 2, correct: true, created_at: "2014-05-13 16:10:53", updated_at: "2014-05-13 16:10:53">, #<Answer id: 5, option: "True", question_id: 2, correct: false, created_at: "2014-05-13 16:10:53", updated_at: "2014-05-13 16:10:53">]

尝试使用SimonW

<% @options = [] %>
<% @test_questions.each do |q| %>
  <tr>
    <td width="40px;">1.</td>
    <td><%= q.content %></td>
    <% @all_answers.each do |a| %>
      <% @options << a.find(q.id) %>
    <% end %>
  </tr>
  <% @options.each do |o| %>
  <tr>
    <%= o.option %>
  </tr>
  <% end %>
<% end %>

错误:

undefined method `option' for #<Enumerator:0x007fcc4181e678>

3 个答案:

答案 0 :(得分:2)

尝试改为:

@test = Test.find(params[:id])
@test_questions = @test.questions
answers = Answer.all
@all_answers = answers.group_by(&:question_id)
@pdf = @test_questions.map { |q| [q, @all_answers[q.id]] }

然后在视图中:

<tbody> 
<% @pdf.each do |question, answers| %>
  <tr>
    <td><%= question.id %></td>
    <td><%= question.content %></td>
    <% answers.each do |answer|
      <td><%= answer.option %></td>
    <% end %>
  </tr>
<% end %>
</tbody>

更新 - 清洁解决方案

控制器:

@test_questions = @test.questions.includes(:answers)

查看:

<tbody> 
<% @test_questions.each do |question| %>
  <tr>
    <td><%= question.id %></td>
    <td><%= question.content %></td>
    <% question.answers.each do |answer|
      <td><%= answer.option %></td>
    <% end %>
  </tr>
<% end %>
</tbody>

答案 1 :(得分:1)

您可以使用respond_to?来避免该错误,并确保您不会在不知道如何处理它的对象上调用option方法:

<% if test.respond_to?(:option) && test.option %>

答案 2 :(得分:0)

如何通过对选项方法(鸭子打字)的响应迭代对象,无论如何我同意SimonW认为这是一个糟糕的设计:

  <% @options.select{|i| i.respond_to?(:option)}.each do |o| %>
    <tr>
      <%= o.option %>
    </tr>
  <% end %>