タイトルがややこしいですが、説明させてください。タイムスタンプが異なる複数のデータポイントを持つ Car モデルがあります。ほとんどの場合、最新のステータスの属性に関心があります。そのため、モデルには has_many のステータスがあり、最新のものに簡単にアクセスするための has_one があります。
class Car < ActiveRecord::Base
has_many :statuses, class_name: 'CarStatus', order: "timestamp DESC"
has_one :latest_status, class_name: 'CarStatus', order: "timestamp DESC"
delegate :location, :timestamp, to: 'latest_status', prefix: 'latest', allow_nil: true
# ...
end
ステータスが保持するものを理解するには:
loc = Car.first.latest_location # Location object (id = 1 for example)
loc.name # "Miami, FL"
最新のロケーション ID が 1 のすべての車を検索する (連鎖可能な) スコープが必要だとします。現在、一種の複雑な方法があります。
# car.rb
def self.by_location_id(id)
ids = []
find_each(include: :latest_status) do |car|
ids << car.id if car.latest_status.try(:location_id) == id.to_i
end
where("id in (?)", ids)
end
SQL を使用してこれを行うより迅速な方法があるかもしれませんが、各車の最新のステータスのみを取得する方法はわかりません。location_id が 1 のステータス レコードが多数存在する可能性がありますが、それがその車の最新の場所でない場合は、含めるべきではありません。
さらに難しくするには... 別のレベルを追加して、場所の名前でスコープできるようにしましょう。名前にアクセスできるように、位置オブジェクトとともにステータスをプリロードするこのメソッドがあります。
def by_location_name(loc)
ids = []
find_each(include: {latest_status: :location}) do |car|
ids << car.id if car.latest_location.try(:name) =~ /#{loc}/i
end
where("id in (?)", ids)
end
これは、上記の場所と「miami」、「fl」、「MIA」などと一致します...これをより簡潔/効率的にする方法について何か提案はありますか? アソシエーションを別の方法で定義したほうがよいでしょうか? あるいは、SQL忍者のスキルが必要になるかもしれませんが、それは私には確かにありません.
Postgres 9.1 の使用 (Heroku cedar スタックでホスト)