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

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

新規登録して質問してみよう
ただいま回答率
85.48%
DateTime

多くのプログラミング言語におけるDateTimeオブジェクトは、日付と時間に関する演算と出力を行います。

Ruby on Rails 4

Ruby on Rails4はRubyによって書かれたオープンソースのウェブフレームワークです。 Ruby on Railsは「設定より規約」の原則に従っており、効率的に作業を行うために再開発を行う必要をなくしてくれます。

Q&A

解決済

1回答

1534閲覧

ruby eachメソッドの処理漏れ

ymatt

総合スコア20

DateTime

多くのプログラミング言語におけるDateTimeオブジェクトは、日付と時間に関する演算と出力を行います。

Ruby on Rails 4

Ruby on Rails4はRubyによって書かれたオープンソースのウェブフレームワークです。 Ruby on Railsは「設定より規約」の原則に従っており、効率的に作業を行うために再開発を行う必要をなくしてくれます。

0グッド

0クリップ

投稿2017/08/12 16:51

###前提・実現したいこと
airbnbのような物件の予約サイトを作成しており、物件をの検索機能を実装中です。予約したい日にち(チェックイン〜チェックアウト)で検索した際、すでにその日にちで予約が入っている物件を検索結果から除外するコードを書いています。

###発生している問題
以下のようなコードを書いたのですが、予約が入っているのに表示されたり、予約が入っていないのに表示されなかったりします。エラーメッセージはありません。その現象に規則性があるかどうか、現時点では突き止められていません。ただし、検索するチェックイン日とチェックアウト日の組み合わせが同一の場合は、問題があるかないかにかかわらず、必ず同一の検索結果隣ます。

binding.pryで検証したところ、コードの最後のセクションにあるeachメソッドに処理漏れが発生しているようです。DB上にはlistingが5件あり、@listingsにはそのすべてがちゃんと入っていることは確認済みです。ところが、5件に対して3件のみにeachの処理をしている(時にlisting_idの1,3,5のみ、時に1,2,4のみ、時に5件全て処理している、など)、というような謎の現象が発生しており、これ以上の究明はお手上げ状態です。何卒お力添えをお願いいたします。

###該当のソースコード
controllerです。なお、日付以外の条件でソートするransackも機能していませんが、先に上記の問題を解決したく、ransackについては未追究です。

def search if params[:search].present? session[:address] = params[:search] if params["lat"].present? & params["lng"].present? @latitude = params["lat"] @longitude = params["lng"] geolocation = [@latitude,@longitude] else geolocation = Geocoder.coordinates(params[:search]) @latitude = geolocation[0] @longitude = geolocation[1] end @listings = Listing.where(active: true).near(geolocation, 20, order: 'distance') # 検索欄が空欄の場合 else @listings = Listing.where(active: true).all @latitude = @listings.to_a[0].latitude @longitude = @listings.to_a[0].longitude end # Ransack q のチェックボックス一覧 if params[:q].present? if params[:q][:price_pernight_gteq].present? session[:price_pernight_gteq] = params[:q][:price_pernight_gteq] else session[:price_pernight_gteq] = nil end if params[:q][:price_pernight_lteq].present? session[:price_pernight_lteq] = params[:q][:price_pernight_lteq] else session[:price_pernight_lteq] = nil end if params[:q][:home_type_eq_any].present? session[:home_type_eq_any] = params[:q][:home_type_eq_any] session[:House] = session[:home_type_eq_any].include?("House") session[:Apartment] = session[:home_type_eq_any].include?("Apartment") session[:Studio] = session[:home_type_eq_any].include?("Studio") else session[:home_type_eq_any] = "" session[:House] = false session[:Apartment] = false session[:Studio] = false end if params[:q][:pet_type_eq].present? session[:pet_type_eq] = params[:q][:pet_type_eq] else session[:pet_type_eq] = nil end if params[:q][:breeding_years_gteq].present? session[:breeding_years_gteq] = params[:q][:breeding_years_gteq] else session[:breeding_years_gteq] = nil end end # Q条件をまとめたものをセッションQに入れる session[:q] = {"price_pernight_gteq"=>session[:price_pernight_gteq], "price_pernight_lteq"=>session[:price_pernight_lteq], "home_type_eq_any"=>session[:home_type_eq_any], "pet_type_eq"=>session[:pet_type_eq], "breeding_years_gteq"=>session[:breeding_years_gteq]} # ransack検索 @search = @listings.ransack(session[:q]) @result = @search.result(distinct: true) #リスティングデータを配列にしてまとめる @arrlistings = @listings.to_a # start_date end_dateの間に予約がないことを確認.あれば削除 if ( !params[:start_date].blank? && !params[:end_date].blank? ) session[:start_date] = params[:start_date] session[:end_date] = params[:end_date] start_date = DateTime.parse(session[:start_date]) end_date = DateTime.parse(session[:end_date]) @listings.each do |listing| # check the listing is availble between start_date to end_date unavailable = listing.reservations.where("(start_date < ? AND ? < end_date) OR (start_date < ? AND ? < end_date) OR (? < start_date AND end_date < ?)", start_date, start_date, end_date, end_date, start_date, end_date).limit(1) binding.pry # delete unavailable room from @listings if unavailable.length > 0 @arrlistings.delete(listing) end end end end

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

each でぶん回しながら、その中で該当データを削除してはいけません。
イメージ的にはインデックスでぶん回している状態を考えてください。

今、リストに A B C D E と5つのデータがあるとします。インデックスを 1~5 と変化させ、2 の時に該当データを削除(Bが消える)と、
A B C D E が
A C D E に変わります。
太字でしめしたインデックスは補正されませんから、次の each で取られるのは「インデックスで3番目」、すなわち D になってしまい、C がスキップされたように見えます。

投稿2017/08/12 23:13

tacsheaven

総合スコア13703

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ymatt

2017/08/13 04:03

なななんと!目からウロコでした。配列 要素 削除 で検索したら同様の事象が紹介されていました。以下で解決しました。ありがとうございます! if ( !params[:start_date].blank? && !params[:end_date].blank? ) session[:start_date] = params[:start_date] session[:end_date] = params[:end_date] start_date = DateTime.parse(session[:start_date]) end_date = DateTime.parse(session[:end_date]) unavailables = [] @listings.each do |listing| # check the listing is availble between start_date to end_date unavailable = listing.reservations.where("(start_date < ? AND ? < end_date) OR (start_date < ? AND ? < end_date) OR (? <= start_date AND end_date <= ?)", start_date, start_date, end_date, end_date, start_date, end_date).limit(1) if unavailable.length > 0 unavailables << listing end end # delete unavailable room from @listings @arrlistings = @arrlistings - unavailables end
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問