

Ruby初心者です。以下のようなロジックで、`each do`の中でDBを参照しようとしています。

maxrating変数にUear_Ratingテーブルでratingがmaxとなる値をとって、それと事前にとっておいたbooksテーブルのidを使ってwhere条件でレコードを取得しようとしていますが、どうしても結果が最後に取得したレコードだけとなってしまいます。とても基本的な事だと思いますが、よくわからず困っていますので、解決方法を教えてください。

[code]

    @books.each do |sb|
    　maxrating = User_Rating.where(book_id: sb.id).maximum(:rating)
      @search_result = User_Summary.joins('LEFT OUTER JOIN Books ON user_summaries.book_id = books.id').joins('LEFT OUTER JOIN user_ratings ON user_summaries.id = user_ratings.user_summary_id').where("user_summaries.book_id = #{sb.id}").where("user_ratings.rating = #{maxrating}").select('User_Summaries.comment, User_Ratings.rating')
    end
    
[/code]


CC BY-SA 4.0
2019-06-30T12:06:38.800
56265
2019-06-30T13:52:11.197
2019-06-30T12:14:44.643
32986
34920
question
ruby sinatra
each doの処理の中でDBを参照する場合

[code]

     （1..10).each do |i|
        @result = i
      end
    
[/code]

というコードに置き換えてみれば何が起きているのかわかるのではないでしょうか。取り出されるのは最後の`i`の値(=10)だけで、1～9はループのたびに次の`i`で上書きされ消えてしまっています

すべての値がほしいなら、例えば

[code]

    @result = []
    (1..10).each do |i|
      @result << i #書き方はほかにも
    end
    
[/code]

などとして配列に保存することが考えられます。

* * *

ところで、DBのクエリをループさせるのは一般的にはバッドプラクティスです。`@books`の数が増えていくとそれに従ってクエリも増えることになります。

ちょっと複雑なクエリなので1発ですむ形に書き換えるのはすぐには難しいと思いますが、書き直す必要があることは覚えておいてください。

(もしくは誰かが回答してくれるかもしれません)

* * *

ついでに

[code]

    @search_result = User_Summary.joins('LEFT OUTER JOIN Books ON user_summaries.book_id = books.id').joins('LEFT OUTER JOIN user_ratings ON user_summaries.id = user_ratings.user_summary_id').where("user_summaries.book_id = #{sb.id}").where("user_ratings.rating = #{maxrating}").select('User_Summaries.comment, User_Ratings.rating')
    
[/code]

このなかで、クエリの文字列に変数展開で値を埋め込んでいますが、これはやめましょう。今回の例だと型的に多分問題にならないと思いますが、任意の文字列が含まれてるような変数であれば典型的なセキュリティホールです。

(詳しくはSQLインジェクションで検索)

[code]

    where(["user_summaries.book_id = ?", sb.id])
    
[/code]

こんな感じで、変数の埋め込みはライブラリ側に任せましょう。


CC BY-SA 4.0
2019-06-30T13:52:11.197
56267
2019-06-30T13:52:11.197
5793
56265
answer