Как я могу отобразить первую и последнюю дочернюю запись для родительской строки в Rails 3.1? - PullRequest
1 голос
/ 03 января 2012

Я довольно новичок в 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?

Решение: 3 января 2012 г.

Я решил свою проблему, применив логику PitStop к модели Trip. Мои From и To PitStops теперь имеют жестко закодированные значения stop_number. Проработав его, я обнаружил, что решение действительно имеет смысл и для реального мира (двойная победа).

  • Запись From PitStop всегда будет иметь значение stop_number, равное 0.
  • Запись PitStop К всегда будет иметь значение stop_number 99.

Это имеет смысл, потому что первый PitStop на самом деле вовсе не «пит-стоп», это то место, с которого вы начинаете (т. Е. 0). Последний PitStop на самом деле не «пит-стоп», это ваше конечное местоположение (т. Е. 99). Конечно, это предполагает, что ни на одном маршруте не будет более 98 «пит-стопов». :) Безопасное предположение для меня ...

Эти логически определенные «stop_numbers» также решают мою проблему для запроса всех дочерних PitStops для отображения «trips / index», и я могу быстро и эффективно запрашивать эти значения для каждой поездки (больше никаких подзапросов для .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

Как видите, хитрость для ввода 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 за подсказку!

Ответы [ 2 ]

3 голосов
/ 03 января 2012

Добавьте два дополнительных отношения в класс 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

Для начала put_stop вы можете задать условие == 1, для последнего вам понадобится дополнительный столбец в таблице trips, где вы кэшируете последний номер поездки. Вы также можете кэшировать идентификаторы для этих двух pit_stops на родительском. Таким образом, вы можете загружать.

1 голос
/ 03 января 2012

Что ж, если можно сделать это за две поездки, вы можете использовать

first_stop = t.pit_stops.order(:stop_number).first
last_stop = t.pit_stops.order(:stop_number).reverse_order.first
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...