0

问题类 has_many 选项。我需要通过某个属性值(通常是 id)找到一个选择。

澄清:父记录(问题)围绕不同的对象和方法传递,它们使用不同的属性和值搜索子项。

我可以这样做question.choices.find(choice_id),但这每次都会生成一个 SQL 查询。

知道问题通常只有少数选择,并且在一个父记录上会有许多不同的搜索,我怀疑加载整个关联并在 Ruby 中搜索会更便宜:

question.choices.detect{|choice| choice.id == some_choice_id}

Detect 来自 Enumerable 并强制 Rails 在第一次调用时加载关联(并在以后的搜索中使用缓存的数据)。这也与急切加载很好地配合:我可以做 Question.all(include:choice) 并将整个树加载两个查询,然后搜索非常快。虽然它读起来不太好。

如果我想模拟查找,它会变得更加毛茸茸!行为:

question.choices.detect{|choice| choice.id == choice_id} or raise ActiveRecord::RecordNotFound.new

这正是我想要的,我只是在寻找更好的语法。

Rails 是否提供某种以这种方式运行的动态查找器(在第一次查询时强制加载整个关联,然后搜索这个预加载的集合)?

4

2 回答 2

0

我怀疑我错过了在 Rails 中烘焙或在流行的 gem 中可用的东西。如果不是这种情况,我只会推出我自己的助手:

Enumerable.module_eval do
  def select_by(attribute_name, value)
    detect do |item|
      item.send(attribute_name) == value
    end
  end

  def select_by!(attribute_name, value)
    select_by(attribute_name, value) \
      or raise StandardError.new("can't find item with #{attribute_name} equal to #{value} in #{self.inspect}")
  end
end

用法是:

question.choices.select_by(:id, 7)
user.question.select_by(:name, "Is it shiny?")
于 2012-11-19T22:22:15.510 回答
0

我相信您想要的称为“急切加载”,并使用该.includes方法实现。

@questions = Question.includes(:choices).all

将导致执行内部连接的查询,返回问题及其每个选择。这假设您已经在模型中声明了关系。大概你会限定 this will some where 子句而不是.all.

于 2012-11-19T22:23:23.437 回答