我对Rails很新,只是喜欢它富有表现力的建模架构。我目前正在构建一个路由系统,在两个表之间有一对多的链接。
考虑以下架构:
class CreateTrips < ActiveRecord::Migration
def self.up
create_table :trips do |t|
t.string :name
end
end
...
end
class CreatePitStop < ActiveRecord::Migration
def self.up
create_table :pit_stops do |t|
t.references :trip
t.integer :stop_number
t.string :location
end
end
...
end
现在考虑一次旅行的以下数据:
t = Trips.create!({ :name => "Christmas Visits Route" })
t.pit_stops.create!({ :stop_number => 1, :location => "Home" })
t.pit_stops.create!({ :stop_number => 2, :location => "Mom and Dads" })
t.pit_stops.create!({ :stop_number => 3, :location => "In-Laws" })
t.pit_stops.create!({ :stop_number => 4, :location => "Grandma's" })
t.pit_stops.create!({ :stop_number => 5, :location => "Time Square" })
我想要做的是在“行程/索引”视图的单个“行程”行中显示所有行程名称的列表以及第一个和最后一个PitStop的位置。我不在乎两者之间的进站,我只是想知道我的起点和结束地点:
--------
My Trips
--------
--------------------------------------------------------
| Route Name | From | To |
--------------------------------------------------------
| Christmas Visits Route | Home | Time Square |
--------------------------------------------------------
我想从查询中删除所有“中间”PitStops,因为每次旅行会有很多。
问题:使用ActiveRecord从数据库中提取此数据的最佳方法是什么?
我通过将PitStop逻辑应用于Trip模型解决了我的问题。我的From和To PitStop现在有硬编码的stop_number值。在完成它之后,我发现解决方案实际上对现实世界也有意义(双赢)。
这是有道理的,因为第一个PitStop根本不是一个“进站点”,它是你从哪里开始的(即0)。最后一个PitStop也不是一个“进站”,它是你的终点(即99)。当然,这假设任何路线都不会超过98次“进站”。 :)对我安全的假设...
这些逻辑定义的“stop_numbers”也解决了我查询所有子PitStops的“行程/索引”显示的问题,我可以快速有效地查询这些值,每次旅行(不再查询.first
或.last
):
class Trip
has_many :pit_stops
has_one :starting_from, :class => 'PitStop',
:conditions => 'pit_stops.stop_number == 0'
has_one :ending_at, :class => 'PitStop',
:conditions => 'pit_stops.stop_number == 99'
def add_pit_stop(location)
stop_num = @pit_stops.count - 1 # accounts for stop_number 99
@pit_stops.create!({ :stop_number => stop_num,
:location => location})
end
end
如您所见,在定义 starting_from 和 ending_at 记录(现在是逻辑业务规则)后,输入stop_numbers
的技巧现在是一个简单的数学方程式)。现在我可以简单地说:
trip = create_trip("Christmas Visits", "Home", "Time Square")
trip.add_pit_stop("Mom and Dads")
trip.add_pit_stop("In-Laws")
trip.add_pit_stop("Grandma's")
我的(订购的)PitStop记录现在看起来像这样:
{ :stop_number => 0, :location => "Home" }
{ :stop_number => 1, :location => "Mom and Dads" }
{ :stop_number => 2, :location => "In-Laws" }
{ :stop_number => 3, :location => "Grandma's" }
{ :stop_number => 99, :location => "Time Square" }
在我看来非常优雅。感谢@clyfe提示!
答案 0 :(得分:3)
在Trip类中添加两个额外的关系:
clss Trip
has_many :pit_stops
has_one :start_pit_stop, :class => 'PitStop',
:conditions => 'pit_stops.order_number == 1'
has_one :end_pit_stop, :class => 'PitStop',
:conditions => 'pit_stops.order_number == trips.last_order_number'
end
对于start put_stop,您可以在== 1上进行条件化,对于最后一个,您需要在trips
表上添加一个额外的列,用于缓存最后一个行程号。您还可以在父级上缓存这两个pit_stops的ID。 通过这种方式,您可以进行急切的加载。
答案 1 :(得分:1)
好吧,如果可以在两次db旅行中完成,你可以使用
first_stop = t.pit_stops.order(:stop_number).first
last_stop = t.pit_stops.order(:stop_number).reverse_order.first