質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.91%

ページングがおかしい。表示内容が重複する。数も正しくない。クエリも正しくない?

受付中

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,704

Aihara

score 24

使用している環境は
Rails 4.2.6
ruby 2.3.1p112
psql (PostgreSQL) 9.2.18

今回困っていること
・ページングが何故かうまくいかない
・自分の意図したクエリを回せているのか

使用しているモデルは
Restaurant
Menu
の二つで

Restaurant
has_many Menu

Menu
belongs_to Restaurant
の関係です。

RestaurantImg
も使用してありますが、Menuと同じく
Restaurantと1対多の関係です。

今回、レストランが複数持っているメニューのうち
最安価格を基準にして、レストランの表示順を安い順に設定したいです。
(ここで、自分のしたいように正しくactive recordを使えているのか、定かでない。)
しかし、何故かページングが正しく動作しません。
使用しているgemはkaminariです。
具体的に言うと、
レストランの総数は19個あり、
そのうち1ページにつき10個のレストランを表示するように設定しているのですが
1ページ目には8個しかでない、という状況になっています。

以下のようにレストラン一覧を取得しています

@restaurants = Restaurant.where(:data_status => "active").genre(params[:genre]).area(params[:area]).includes(:restaurant_imgs, :menus).where(restaurant_imgs: {size: "normal"}).sort(params[:sort]).page(@page).per(10)


こういった内容でレストランを取得していました。
各scopeは以下の通りです。

scope :genre, -> (genre) { 
  if genre.present? && genre != "all"
   where("restaurants.genre = ?", genre) 
  end
}
scope :area, -> (area) { 
  if area.present?  && area != "all"
    where("restaurants.area = ?", area) 
  end
}
scope :sort, -> (sort) { 
  if sort.present? && sort == "price"
    order("menus.price asc, restaurants.pickup desc")
  end
}


restaurants.pickupは
数字で管理されていて、各レストランに一意に保存されていてます。

(書き忘れ)
kaminariで表示する検索結果の文言についてです。
page_entries_info
というヘルパーメソッドで検索結果の数について表示をしてくれるのですが
そこで
「19つの全てのレストランを表示しています」と出ているにもかかわらず
1ページあたり10つを表示と設定してあるページに
8つしかレストランが表示されません。
データを取り出す部分と、kaminariと
両方ともにおかしいところがあるのではないかと思っております。

また、1ページあたり100と極端に設定すると
DBに入ってある19つのレストランが全て表示されます。
不可解です。。

(ログを見てみる)

SQL (3.3ms)  SELECT  DISTINCT "restaurants"."id", menus.price AS alias_0 FROM "restaurants" LEFT OUTER JOIN "menus" ON "menus"."restaurant_id" = "restaurants"."id" AND "menus"."data_status" = $1 WHERE "restaurants"."data_status" = $2  ORDER BY menus.price ASC LIMIT 10 OFFSET 0  [["data_status", "active"], ["data_status", "active"]]
   (3.2ms)  SELECT COUNT(DISTINCT "restaurants"."id") FROM "restaurants" LEFT OUTER JOIN "menus" ON "menus"."restaurant_id" = "restaurants"."id" AND "menus"."data_status" = $1 WHERE "restaurants"."data_status" = $2 AND "restaurants"."id" IN (13, 4, 5, 10, 17, 2, 6, 18, 6, 5)  [["data_status", "active"], ["data_status", "active"]]
   (3.1ms)  SELECT COUNT(DISTINCT "restaurants"."id") FROM "restaurants" LEFT OUTER JOIN "menus" ON "menus"."restaurant_id" = "restaurants"."id" AND "menus"."data_status" = $1 WHERE "restaurants"."data_status" = $2  [["data_status", "active"], ["data_status", "active"]]
  CACHE (0.0ms)  SELECT  DISTINCT "restaurants"."id", menus.price AS alias_0 FROM "restaurants" LEFT OUTER JOIN "menus" ON "menus"."restaurant_id" = "restaurants"."id" AND "menus"."data_status" = $1 WHERE "restaurants"."data_status" = $2  ORDER BY menus.price ASC LIMIT 10 OFFSET 0  [["data_status", "active"], ["data_status", "active"]]


以上のようなログが出ているのですが

ORDER BY menus.price


これが入っていると

"restaurants"."id" IN (13, 4, 5, 10, 17, 2, 6, 18, 6, 5) 


これが入るのですが、なぜここで5,6が重複してしまうのでしょうか。
これが原因で、10件表示としているにもかかわらず8件しか出ない、というようになっていると思います。
並び順を指定するだけで重複するようなことになってしまうのが、よく分かりません。。。

宜しくお願い致します。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

0

再現していないのでよくわかりませんが、development.log に出てくるSQL文を見てみると何か気がつくことがあるかもしれません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

十分な情報がないので推測の域をでませんが
おそらく

.where(restaurant_imgs: {size: "normal"})


がいけません。
これですと、せっかくincludesでrestaurant_img を left outer join
しても、size: "normal"で絞り込んでしまうので、inner joinと同じ
restaurant_imgs: {size: "normal"}を持つレストラントしか抽出されません。

こういった場合、例えば、restaurant_imgs: {size: "normal"}がトップ画像とか、で一枚しかないならば

has_many :restaurant_imgs


の他に

has_one :restaurant_img,->{where(restaurant_imgs: {size: "normal"})}


みたいなものを追加して
複数ある場合は(この時点で実装が間違えている気もしますが...)

has_many :normal_size_restaurant_imgs,->{where(restaurant_imgs: {size: "normal"})},class_name: 'RestrantImage'


として

.includes(:normal_size_restaurant_imgs, :menus)


としてみてください

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/05 22:16

    moke様
    ご回答して頂きありがとうございます。
    restauranはrestaurant_imgsを複数枚所有していて
    さらにrestaurant_imgsは横長のものと丸型のものと2種類あります。

    DBに入っている全てのrestaurantは写真を各種とも複数枚所有しているため
    where(restaurant_imgs: {size: "normal"})
    を外してみても、表示結果に変わりはありませんでした。

    has_one, has_manyは重複して設定できることは知りませんでした。。
    なるほどなと思いました!!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.91%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る