【问题标题】:Failed to get RoR Active Record model id to execute a query获取 RoR Active Record 模型 ID 以执行查询失败
【发布时间】:2016-05-13 22:10:47
【问题描述】:

我正在使用 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'

【问题讨论】:

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


【解决方案1】:

@Pholochtairze 的回答很到位。这个答案是为了删除所有那些调用 map 并有效地获得你需要的所有答案(双关语: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,因为您通常不希望在链中使用它们。所以这里最大的重构是将调用移到where 方法内的map

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))

你有它。

【讨论】:

    【解决方案2】:

    看起来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 []>

    【讨论】:

      【解决方案3】:

      它不起作用,因为你做了 ma​​p 构造了一个数组,它与 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)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-28
        • 1970-01-01
        • 1970-01-01
        • 2012-05-18
        • 1970-01-01
        相关资源
        最近更新 更多