gtfs-engine 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +37 -0
  3. data/app/controllers/gtfs_engine/agencies_controller.rb +24 -0
  4. data/app/controllers/gtfs_engine/application_controller.rb +21 -0
  5. data/app/controllers/gtfs_engine/calendar_dates_controller.rb +22 -0
  6. data/app/controllers/gtfs_engine/calendars_controller.rb +51 -0
  7. data/app/controllers/gtfs_engine/data_sets_controller.rb +47 -0
  8. data/app/controllers/gtfs_engine/fare_attributes_controller.rb +27 -0
  9. data/app/controllers/gtfs_engine/fare_rules_controller.rb +26 -0
  10. data/app/controllers/gtfs_engine/feed_infos_controller.rb +26 -0
  11. data/app/controllers/gtfs_engine/frequencies_controller.rb +26 -0
  12. data/app/controllers/gtfs_engine/routes_controller.rb +25 -0
  13. data/app/controllers/gtfs_engine/shapes_controller.rb +23 -0
  14. data/app/controllers/gtfs_engine/stop_times_controller.rb +28 -0
  15. data/app/controllers/gtfs_engine/stops_controller.rb +30 -0
  16. data/app/controllers/gtfs_engine/transfers_controller.rb +38 -0
  17. data/app/controllers/gtfs_engine/trips_controller.rb +34 -0
  18. data/app/helpers/gtfs_engine/default_views_helper.rb +42 -0
  19. data/app/helpers/gtfs_engine/fields_helper.rb +32 -0
  20. data/app/models/gtfs_engine/agency.rb +19 -0
  21. data/app/models/gtfs_engine/calendar.rb +78 -0
  22. data/app/models/gtfs_engine/calendar_date.rb +20 -0
  23. data/app/models/gtfs_engine/data_set.rb +73 -0
  24. data/app/models/gtfs_engine/fare_attribute.rb +19 -0
  25. data/app/models/gtfs_engine/fare_rule.rb +28 -0
  26. data/app/models/gtfs_engine/feed_info.rb +19 -0
  27. data/app/models/gtfs_engine/frequency.rb +20 -0
  28. data/app/models/gtfs_engine/route.rb +24 -0
  29. data/app/models/gtfs_engine/shape.rb +20 -0
  30. data/app/models/gtfs_engine/stop.rb +26 -0
  31. data/app/models/gtfs_engine/stop_time.rb +21 -0
  32. data/app/models/gtfs_engine/transfer.rb +23 -0
  33. data/app/models/gtfs_engine/trip.rb +27 -0
  34. data/app/views/gtfs_engine/calendars/dates.json.jbuilder +18 -0
  35. data/app/views/gtfs_engine/data_sets/index.json.jbuilder +28 -0
  36. data/app/views/gtfs_engine/data_sets/show.json.jbuilder +21 -0
  37. data/app/views/gtfs_engine/gtfs/index.json.jbuilder +15 -0
  38. data/app/views/gtfs_engine/gtfs/show.json.jbuilder +15 -0
  39. data/app/views/gtfs_engine/transfers/from.json.jbuilder +15 -0
  40. data/app/views/gtfs_engine/transfers/from_to.json.jbuilder +15 -0
  41. data/app/views/gtfs_engine/transfers/to.json.jbuilder +15 -0
  42. data/app/views/gtfs_engine/trips/block.json.jbuilder +15 -0
  43. data/bin/rails +8 -0
  44. data/config/initializers/extensions_loader.rb +15 -0
  45. data/config/routes.rb +45 -0
  46. data/db/migrate/20140320045108_create_gtfs_engine_data_sets.rb +17 -0
  47. data/db/migrate/20140320045232_create_gtfs_engine_calendars.rb +24 -0
  48. data/db/migrate/20140320045751_create_gtfs_engine_calendar_dates.rb +16 -0
  49. data/db/migrate/20140320050100_create_gtfs_engine_shapes.rb +20 -0
  50. data/db/migrate/20140320051140_create_gtfs_engine_routes.rb +22 -0
  51. data/db/migrate/20140320052005_create_gtfs_engine_stops.rb +28 -0
  52. data/db/migrate/20140320052508_create_gtfs_engine_trips.rb +26 -0
  53. data/db/migrate/20140320052907_create_gtfs_engine_stop_times.rb +24 -0
  54. data/db/migrate/20140401032609_create_gtfs_engine_agencies.rb +19 -0
  55. data/db/migrate/20140405235947_create_gtfs_engine_fare_attributes.rb +18 -0
  56. data/db/migrate/20140406063500_create_gtfs_engine_fare_rules.rb +17 -0
  57. data/db/migrate/20140406071922_create_gtfs_engine_frequencies.rb +17 -0
  58. data/db/migrate/20140406072309_create_gtfs_engine_transfers.rb +17 -0
  59. data/db/migrate/20140406073548_create_gtfs_engine_feed_infos.rb +16 -0
  60. data/lib/ext.rb +19 -0
  61. data/lib/ext/active_record/associations/association.rb +41 -0
  62. data/lib/gtfs_engine.rb +33 -0
  63. data/lib/gtfs_engine/concerns.rb +19 -0
  64. data/lib/gtfs_engine/concerns/controllers.rb +20 -0
  65. data/lib/gtfs_engine/concerns/controllers/data_access.rb +31 -0
  66. data/lib/gtfs_engine/concerns/controllers/gtfs.rb +158 -0
  67. data/lib/gtfs_engine/engine.rb +28 -0
  68. data/lib/gtfs_engine/exceptions.rb +35 -0
  69. data/lib/gtfs_engine/json_responder.rb +31 -0
  70. data/lib/gtfs_engine/sources.rb +86 -0
  71. data/lib/gtfs_engine/version.rb +84 -0
  72. data/lib/tasks/gtfs_engine_tasks.rake +89 -0
  73. metadata +242 -0
@@ -0,0 +1,38 @@
1
+ # This file is part of the KNOWtime server.
2
+ #
3
+ # The KNOWtime server is free software: you can redistribute it and/or modify it
4
+ # under the terms of the GNU General Public License as published by the Free
5
+ # Software Foundation, either version 3 of the License, or (at your option) any
6
+ # later version.
7
+ #
8
+ # The KNOWtime server is distributed in the hope that it will be useful, but
9
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11
+ # details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with the KNOWtime server. If not, see <http://www.gnu.org/licenses/>.
15
+ module GtfsEngine
16
+ class TransfersController < ApplicationController
17
+ include Concerns::Controllers::Gtfs
18
+
19
+ filters :transfer_type,
20
+ :min_transfer_time
21
+
22
+ def from
23
+ @transfers = collection.where from_stop_id: params[:stop_id]
24
+ respond_with @transfers
25
+ end
26
+
27
+ def to
28
+ @transfers = collection.where to_stop_id: params[:stop_id]
29
+ respond_with @transfers
30
+ end
31
+
32
+ def from_to
33
+ @transfer = collection.find_by from_stop_id: params[:from_id],
34
+ to_stop_id: params[:to_id]
35
+ respond_with @transfer
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,34 @@
1
+ # This file is part of the KNOWtime server.
2
+ #
3
+ # The KNOWtime server is free software: you can redistribute it and/or modify it
4
+ # under the terms of the GNU General Public License as published by the Free
5
+ # Software Foundation, either version 3 of the License, or (at your option) any
6
+ # later version.
7
+ #
8
+ # The KNOWtime server is distributed in the hope that it will be useful, but
9
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11
+ # details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with the KNOWtime server. If not, see <http://www.gnu.org/licenses/>.
15
+ module GtfsEngine
16
+ class TripsController < ApplicationController
17
+ include Concerns::Controllers::Gtfs
18
+
19
+ filters :service_id,
20
+ :headsign,
21
+ :short_name,
22
+ :direction_id,
23
+ :block_id,
24
+ :route_id,
25
+ :shape_id,
26
+ :wheelchair_accessible,
27
+ :bikes_allowed
28
+
29
+ def block
30
+ @trips = collection.where block_id: params[:id]
31
+ respond_with @trips
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,42 @@
1
+ # This file is part of the KNOWtime server.
2
+ #
3
+ # The KNOWtime server is free software: you can redistribute it and/or modify it
4
+ # under the terms of the GNU General Public License as published by the Free
5
+ # Software Foundation, either version 3 of the License, or (at your option) any
6
+ # later version.
7
+ #
8
+ # The KNOWtime server is distributed in the hope that it will be useful, but
9
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11
+ # details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with the KNOWtime server. If not, see <http://www.gnu.org/licenses/>.
15
+ module GtfsEngine
16
+ module DefaultViewsHelper
17
+ def index(json, records)
18
+ json.cache! [controller_name, filter] do
19
+ json.ignore_nil! true
20
+
21
+ json.status 'success'
22
+ json.data do
23
+ json.set! controller_name do
24
+ json.array!(records) {|record| json.extract! record, *fields }
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ def show(json, record)
31
+ json.cache! record do
32
+ json.ignore_nil! true
33
+ json.status 'success'
34
+ json.data do
35
+ json.set! controller_name.singularize do
36
+ json.extract! record, *fields
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,32 @@
1
+ # This file is part of the KNOWtime server.
2
+ #
3
+ # The KNOWtime server is free software: you can redistribute it and/or modify it
4
+ # under the terms of the GNU General Public License as published by the Free
5
+ # Software Foundation, either version 3 of the License, or (at your option) any
6
+ # later version.
7
+ #
8
+ # The KNOWtime server is distributed in the hope that it will be useful, but
9
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11
+ # details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with the KNOWtime server. If not, see <http://www.gnu.org/licenses/>.
15
+ module GtfsEngine
16
+ module FieldsHelper
17
+ def fields
18
+ (@fields ||= {})[model] ||= create_fields
19
+ end
20
+
21
+ private
22
+
23
+ def model
24
+ @model ||= controller_name.classify
25
+ end
26
+
27
+ def create_fields
28
+ attributes = GtfsEngine.const_get(model).attribute_names
29
+ attributes - %w(id data_set_id)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,19 @@
1
+ # This file is part of the KNOWtime server.
2
+ #
3
+ # The KNOWtime server is free software: you can redistribute it and/or modify it
4
+ # under the terms of the GNU General Public License as published by the Free
5
+ # Software Foundation, either version 3 of the License, or (at your option) any
6
+ # later version.
7
+ #
8
+ # The KNOWtime server is distributed in the hope that it will be useful, but
9
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11
+ # details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with the KNOWtime server. If not, see <http://www.gnu.org/licenses/>.
15
+ module GtfsEngine
16
+ class Agency < ActiveRecord::Base
17
+ belongs_to :data_set, inverse_of: :agencies
18
+ end
19
+ end
@@ -0,0 +1,78 @@
1
+ # This file is part of the KNOWtime server.
2
+ #
3
+ # The KNOWtime server is free software: you can redistribute it and/or modify it
4
+ # under the terms of the GNU General Public License as published by the Free
5
+ # Software Foundation, either version 3 of the License, or (at your option) any
6
+ # later version.
7
+ #
8
+ # The KNOWtime server is distributed in the hope that it will be useful, but
9
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11
+ # details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with the KNOWtime server. If not, see <http://www.gnu.org/licenses/>.
15
+ module GtfsEngine
16
+ class Calendar < ActiveRecord::Base
17
+ belongs_to :data_set, inverse_of: :calendars
18
+
19
+ has_many :calendar_dates, inverse_of: :calendar, shared_key: :service_id
20
+ has_many :trips, inverse_of: :calendar, shared_key: :service_id
21
+
22
+ has_many :routes, through: :trips
23
+ has_many :shapes, through: :trips
24
+
25
+ alias_attribute :dates, :calendar_dates
26
+
27
+
28
+ class << self
29
+ # @return <ActiveRecord_Relation> the set of Calendars that include the
30
+ # given date.
31
+ # This method will add/remove entries listed in CalendarDate and will also
32
+ # filter out entries which don't match the correct day-of-week.
33
+ #
34
+ # TODO: Currently, this method does 3 SQL queries. Try to lower this.
35
+ def from_date_string(date)
36
+ dates = GtfsEngine::CalendarDate.where date: date
37
+
38
+ add = dates.where(exception_type: 1).pluck :service_id
39
+ query =
40
+ if add.any?
41
+ where '((start_date <= :date AND end_date >= :date)
42
+ OR service_id IN (:ids)', date: date, ids: add
43
+ else
44
+ where '(start_date <= :date AND end_date >= :date)', date: date
45
+ end
46
+
47
+ query = where_day_of_week query, date
48
+
49
+ rem = dates.where(exception_type: 2).pluck :service_id
50
+ if rem.any?
51
+ query.where '(service_id NOT IN (?))', rem
52
+ else
53
+ query
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ # Modifies the given query to only matches the day of the week represented
60
+ # by the given date (format: YYYY-MM-DD)
61
+ def where_day_of_week(query, date_str)
62
+ case Date.new( *date_str.split('-').map(&:to_i) ).cwday
63
+ when 1 then query.where monday: true
64
+ when 2 then query.where tuesday: true
65
+ when 3 then query.where wednesday: true
66
+ when 4 then query.where thursday: true
67
+ when 5 then query.where friday: true
68
+ when 6 then query.where saturday: true
69
+ else query.where sunday: true
70
+ end
71
+ end
72
+
73
+ end
74
+
75
+ end
76
+
77
+ DateFormatError = Class.new StandardError
78
+ end
@@ -0,0 +1,20 @@
1
+ # This file is part of the KNOWtime server.
2
+ #
3
+ # The KNOWtime server is free software: you can redistribute it and/or modify it
4
+ # under the terms of the GNU General Public License as published by the Free
5
+ # Software Foundation, either version 3 of the License, or (at your option) any
6
+ # later version.
7
+ #
8
+ # The KNOWtime server is distributed in the hope that it will be useful, but
9
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11
+ # details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with the KNOWtime server. If not, see <http://www.gnu.org/licenses/>.
15
+ module GtfsEngine
16
+ class CalendarDate < ActiveRecord::Base
17
+ belongs_to :data_set, inverse_of: :calendar_dates
18
+ belongs_to :calendar, inverse_of: :calendar_dates, shared_key: :service_id
19
+ end
20
+ end
@@ -0,0 +1,73 @@
1
+ # This file is part of the KNOWtime server.
2
+ #
3
+ # The KNOWtime server is free software: you can redistribute it and/or modify it
4
+ # under the terms of the GNU General Public License as published by the Free
5
+ # Software Foundation, either version 3 of the License, or (at your option) any
6
+ # later version.
7
+ #
8
+ # The KNOWtime server is distributed in the hope that it will be useful, but
9
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11
+ # details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with the KNOWtime server. If not, see <http://www.gnu.org/licenses/>.
15
+ module GtfsEngine
16
+ class DataSet < ActiveRecord::Base
17
+ with_options inverse_of: :data_set, dependent: :delete_all do |set|
18
+ set.has_many :agencies
19
+ set.has_many :calendars
20
+ set.has_many :calendar_dates
21
+ set.has_many :fare_attributes
22
+ set.has_many :fare_rules
23
+ set.has_many :feed_infos
24
+ set.has_many :frequencies
25
+ set.has_many :routes
26
+ set.has_many :shapes
27
+ set.has_many :stops
28
+ set.has_many :stop_times
29
+ set.has_many :transfers
30
+ set.has_many :trips
31
+ end
32
+
33
+ scope :newest, -> { order(created_at: :desc).first }
34
+
35
+ #@return [Hash] a hash of each record type and the number of records in
36
+ # this data set
37
+ def details
38
+ Rails.cache.fetch("gtfs_data_set_details_#{id}") { create_details }
39
+ end
40
+
41
+ def calendars_for_date(date_string)
42
+ Rails.cache.fetch "data[#{id}]_calendars[#{date_string}]" do
43
+ Calendar.from_date_string(date_string).where(data_set_id: id).to_a
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def create_details
50
+ self.class.reflections.select do |name, assoc|
51
+ assoc.macro == :has_many && assoc.options[:inverse_of] == :data_set
52
+ end.each_with_object({}) do |(name, _), hash|
53
+ controller_class = association_controller_class name
54
+ hash[name] = {
55
+ count: send(name).count,
56
+ filters: controller_class.filters
57
+ }
58
+ end
59
+ end
60
+
61
+ def association_controller_class(name)
62
+ mod = self.class.name.deconstantize
63
+ controller = "#{name}_controller".classify
64
+ "#{mod}::#{controller}".constantize
65
+ end
66
+
67
+ def association_model_class(name)
68
+ mod = self.class.name.deconstantize
69
+ model = name.to_s.classify
70
+ "#{mod}::#{model}".constantize
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,19 @@
1
+ # This file is part of the KNOWtime server.
2
+ #
3
+ # The KNOWtime server is free software: you can redistribute it and/or modify it
4
+ # under the terms of the GNU General Public License as published by the Free
5
+ # Software Foundation, either version 3 of the License, or (at your option) any
6
+ # later version.
7
+ #
8
+ # The KNOWtime server is distributed in the hope that it will be useful, but
9
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11
+ # details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with the KNOWtime server. If not, see <http://www.gnu.org/licenses/>.
15
+ module GtfsEngine
16
+ class FareAttribute < ActiveRecord::Base
17
+ belongs_to :data_set, inverse_of: :fare_attributes
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ # This file is part of the KNOWtime server.
2
+ #
3
+ # The KNOWtime server is free software: you can redistribute it and/or modify it
4
+ # under the terms of the GNU General Public License as published by the Free
5
+ # Software Foundation, either version 3 of the License, or (at your option) any
6
+ # later version.
7
+ #
8
+ # The KNOWtime server is distributed in the hope that it will be useful, but
9
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11
+ # details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with the KNOWtime server. If not, see <http://www.gnu.org/licenses/>.
15
+ module GtfsEngine
16
+ class FareRule < ActiveRecord::Base
17
+ belongs_to :data_set, inverse_of: :trips
18
+ belongs_to :fare_attribute, inverse_of: :fare_rules, shared_key: :fare_id
19
+ belongs_to :route, inverse_of: :fare_rules, shared_key: :route_id
20
+
21
+ with_options class_name: 'Stop', primary_key: :zone_id do |rule|
22
+ rule.belongs_to :origin, inverse_of: :origin_rules,
23
+ foreign_key: :origin_id
24
+ rule.belongs_to :destination, inverse_of: :destination_rules,
25
+ foreign_key: :destination_id
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,19 @@
1
+ # This file is part of the KNOWtime server.
2
+ #
3
+ # The KNOWtime server is free software: you can redistribute it and/or modify it
4
+ # under the terms of the GNU General Public License as published by the Free
5
+ # Software Foundation, either version 3 of the License, or (at your option) any
6
+ # later version.
7
+ #
8
+ # The KNOWtime server is distributed in the hope that it will be useful, but
9
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11
+ # details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with the KNOWtime server. If not, see <http://www.gnu.org/licenses/>.
15
+ module GtfsEngine
16
+ class FeedInfo < ActiveRecord::Base
17
+ belongs_to :data_set, inverse_of: :feed_infos
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ # This file is part of the KNOWtime server.
2
+ #
3
+ # The KNOWtime server is free software: you can redistribute it and/or modify it
4
+ # under the terms of the GNU General Public License as published by the Free
5
+ # Software Foundation, either version 3 of the License, or (at your option) any
6
+ # later version.
7
+ #
8
+ # The KNOWtime server is distributed in the hope that it will be useful, but
9
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11
+ # details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with the KNOWtime server. If not, see <http://www.gnu.org/licenses/>.
15
+ module GtfsEngine
16
+ class Frequency < ActiveRecord::Base
17
+ belongs_to :data_set, inverse_of: :frequencies
18
+ belongs_to :trip, inverse_of: :frequencies, shared_key: :trip_id
19
+ end
20
+ end
@@ -0,0 +1,24 @@
1
+ # This file is part of the KNOWtime server.
2
+ #
3
+ # The KNOWtime server is free software: you can redistribute it and/or modify it
4
+ # under the terms of the GNU General Public License as published by the Free
5
+ # Software Foundation, either version 3 of the License, or (at your option) any
6
+ # later version.
7
+ #
8
+ # The KNOWtime server is distributed in the hope that it will be useful, but
9
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11
+ # details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with the KNOWtime server. If not, see <http://www.gnu.org/licenses/>.
15
+ module GtfsEngine
16
+ class Route < ActiveRecord::Base
17
+ belongs_to :data_set, inverse_of: :routes
18
+
19
+ has_many :trips, inverse_of: :route, shared_key: :route_id
20
+
21
+ has_many :calendars, through: :trips
22
+ has_many :shapes, through: :trips
23
+ end
24
+ end