0

質問クラス has_many Choices。いくつかの属性値 (通常は id) で選択肢を見つける必要があります。

明確にするために:親レコード(質問)はさまざまなオブジェクトとメソッドに渡され、さまざまな属性と値を使用して子を検索します。

できますquestion.choices.find(choice_id)が、これは毎回 SQL クエリを生成します。

通常、質問にはほんの一握りの選択肢しかなく、1 つの親レコードに対してさまざまな検索が行われることを知っているので、関連付け全体を読み込んで Ruby で検索する方が安くなると思います。

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

Detect は Enumerable から来ており、Rails が最初の呼び出しで関連付けをロードするように強制します (その後の検索ではキャッシュされたデータを使用します)。これは熱心な読み込みでもうまく機能します。Question.all(include:choices) を実行すると、ツリー全体が 2 つのクエリで読み込まれ、検索が非常に高速になります。とはいえ、よく読めません。

検索をシミュレートしたい場合は、さらに毛むくじゃらになります! 行動:

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

これはまさに私が望んでいることです。より良い構文を探しているだけです。

Rails は、このように動作するある種の動的ファインダーを提供しますか (最初のクエリで関連付け全体を強制的にロードし、次にこのプリロードされたセットを検索します)?

4

2 に答える 2

0

Railsで焼いたものや人気のある宝石で入手できるものが足りないのではないかと思います。そうでない場合は、自分のヘルパーをロールします。

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

内部結合を実行するクエリが生成され、両方の質問とその各選択肢が返されます。これは、モデルで関係を宣言していることを前提としています。おそらく、これは.の代わりにwhere句で修飾されます.all

于 2012-11-19T22:23:23.437 に答える