无法获得RoR Active Record模型ID来执行查询

时间:2016-05-13 22:10:47

标签: ruby-on-rails ruby database activerecord orm

我正在使用ActiveRecord开发rails项目。我正在做一些逐步的查询,似乎我缺少关键概念,因为我是Activerecord的新手。我无法在模型上获取id并因此执行查询。这是我的代码:

questions = JSON.parse(q)
selected_answers = questions.map do |ques|
  ques['options'].map do |opt|
     Answer.where(value: opt['title'])
  end
end

participants = selected_answers.flatten!.map do |sa|
  Participant.where(answers: sa.id)
end

stats[:answers] = participants.map do |p|
  Answer.where(participants: p.id) #this line causes an error
end

我收到错误

NoMethodError (undefined method `id' for #<Participant::ActiveRecord_Relation:0x007fc478423bc0>):
  app/services/survey_statistics.rb:143:in `block in get_question'
  app/services/survey_statistics.rb:142:in `map'
  app/services/survey_statistics.rb:142:in `get_question'
  app/services/survey_statistics.rb:25:in `block in questions'
  app/services/survey_statistics.rb:22:in `questions'
  app/controllers/api/v1/reports_controller.rb:13:in `questions'

3 个答案:

答案 0 :(得分:0)

看起来participants是集合的集合。您正在使用map,因此您的变量p现在是一个集合(实际上Participant::ActiveRecord_Relation告诉您它是一个集合),这就是它没有id的原因。我会尝试再循环遍历集合(这次是p),如下所示:

stats[:answers] = participants.map do |p|
  p.map do |p1|
    Answer.where(participants: p1.id)
  end
end

您可以在此处找到相关问题:undefined method `id' for #<ActiveRecord::Relation []>

答案 1 :(得分:0)

它不起作用,因为你做了 map ,它构造了一个与 where 结合的数组,它还返回一个数组,所以你有数组数组:

stats[:answers] = participants.map do |p|
  Answer.where(participants: p.id) #this line causes an error
end

您可以更简单地实现目标,据我所知,您可以使用此代码替换所有代码:

questions = JSON.parse(q)
titles = questions.each_with_object([]) do |q, a| 
  q["options"].each { |option| a << option["title"] }
end

participants_ids = Answer.where(value: titles).pluck(:participant_id)
stats[:answers] = Answer.where(participant_id: participant_ids)

答案 2 :(得分:0)

@ Pholochtairze的回答很明显。这个答案是删除所有这些调用地图并有效地获得所需的所有答案(双关语意图:p)

首先,您将获得所选答案的列表。我们要将所有标题保存到不同的变量中并使用它来获取所有答案。我们还将flat_map用于最外层循环。

questions = JSON.parse(q)

titles = questions.flat_map do |ques|
  ques['options'].map { |opt| opt['title'] }
end

selected_answers = Answer.where(value: titles)

flatten!和其他!方法的一个问题是,如果没有进行任何更改,它们会返回nil,因为您通常不想在链中使用它们。所以这里的重构是将调用移到map方法中的where

participants = Participant.where(answers: selected_answers.map(&:id))

更好的重构是使用pluck而不是map,因为selected_answers现在是ActiveRecord::Relation对象。这将阻止Rails不必要地创建记录。

participants = Participant.where(answers: selected_answers.pluck(:id))

对于最后一部分,我们希望得到我们之前获得的参与者的答案。您仍然可以使用map但我们再次使用pluck来提高效率。

stats[:answers] = Answer.where(participants: participants.pluck(:id))

你有它。