Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
# gem "skylight", "~> 3.1"
gem 'pghero'
gem 'oj'
5 changes: 5 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ GEM
nio4r (2.3.1)
nokogiri (1.10.2)
mini_portile2 (~> 2.4.0)
oj (3.7.11)
pg (1.1.4)
pghero (2.2.0)
activerecord
puma (3.12.1)
rack (2.0.6)
rack-test (1.1.0)
Expand Down Expand Up @@ -137,7 +140,9 @@ DEPENDENCIES
bootsnap (>= 1.1.0)
byebug
listen (>= 3.0.5, < 3.2)
oj
pg (>= 0.18, < 2.0)
pghero
puma (~> 3.11)
rails (~> 5.2.3)
tzinfo-data
Expand Down
4 changes: 3 additions & 1 deletion app/controllers/trips_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ class TripsController < ApplicationController
def index
@from = City.find_by_name!(params[:from])
@to = City.find_by_name!(params[:to])
@trips = Trip.where(from: @from, to: @to).order(:start_time)
@trips = Trip.where(from: @from, to: @to)
.eager_load(bus: :services)
.order(:start_time)
end
end
4 changes: 3 additions & 1 deletion app/views/trips/_services.html.erb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<li>Сервисы в автобусе:</li>
<ul>
<% services.each do |service| %>
<%= render "service", service: service %>
<% cache(service) do %>
<%= render "service", service: service %>
<% end %>
<% end %>
</ul>
18 changes: 13 additions & 5 deletions app/views/trips/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,18 @@

<% @trips.each do |trip| %>
<ul>
<%= render "trip", trip: trip %>
<% if trip.bus.services.present? %>
<%= render "services", services: trip.bus.services %>
<% end %>
<li><%= "Отправление: #{trip.start_time}" %></li>
<li><%= "Прибытие: #{(Time.parse(trip.start_time) + trip.duration_minutes.minutes).strftime('%H:%M')}" %></li>
<li><%= "В пути: #{trip.duration_minutes / 60}ч. #{trip.duration_minutes % 60}мин." %></li>
<li><%= "Цена: #{trip.price_cents / 100}р. #{trip.price_cents % 100}коп." %></li>
<li><%= "Автобус: #{trip.bus.model} №#{trip.bus.number}" %></li>
<% next unless trip.bus.services.present? %>
<li>Сервисы в автобусе:</li>
<ul>
<% trip.bus.services.each do |service| %>
<li><%= "#{service.name}" %></li>
<% end %>
</ul>
</ul>
<%= render "delimiter" %>
====================================================
<% end %>
28 changes: 28 additions & 0 deletions bin/feedback-loop.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env ruby
require 'benchmark'
require 'fileutils'
include FileUtils

FILES = %w[
example.json
small.json
medium.json
large.json
].freeze

APP_ROOT = File.expand_path('..', __dir__)

def system!(*args)
system(*args) || abort("\n== Command #{args} failed ==")
end

chdir APP_ROOT do
FILES.each do |file|
result = Benchmark.measure do
puts "\n== Loading data from fixtures/#{file} =="
system! "bin/rake reload_json[fixtures/#{file}]"
end

puts result
end
end
2 changes: 2 additions & 0 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ class Application < Rails::Application
# Application configuration can go into files in config/initializers
# -- all .rb files in that directory are automatically loaded after loading
# the framework and any gems in your application.

# config.skylight.environments += ["development"]
end
end
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
Rails.application.routes.draw do
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
mount PgHero::Engine, at: "pghero"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

get "/" => "statistics#index"
get "автобусы/:from/:to" => "trips#index"
end
3 changes: 3 additions & 0 deletions config/skylight.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
# The authentication token for the application.
# authentication: DcUn7LxoVTsGHsGvnPXXA8yjoujr8NC-P0IW3m5LruA
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Упс, токены лучше не коммитить!

10 changes: 10 additions & 0 deletions db/migrate/20190402073803_add_indexes.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class AddIndexes < ActiveRecord::Migration[5.2]
def change

add_index :cities, %i[id name]
add_index :trips, %i[id from_id to_id]
add_index :buses, %i[id number model]
add_index :buses_services, %i[id bus_id service_id]
add_index :services, %i[id name]
end
end
8 changes: 7 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,32 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 2019_03_30_193044) do
ActiveRecord::Schema.define(version: 2019_04_02_073803) do

# These are extensions that must be enabled in order to support this database
enable_extension "pg_stat_statements"
enable_extension "plpgsql"

create_table "buses", force: :cascade do |t|
t.string "number"
t.string "model"
t.index ["id", "number", "model"], name: "index_buses_on_id_and_number_and_model"
end

create_table "buses_services", force: :cascade do |t|
t.integer "bus_id"
t.integer "service_id"
t.index ["id", "bus_id", "service_id"], name: "index_buses_services_on_id_and_bus_id_and_service_id"
end

create_table "cities", force: :cascade do |t|
t.string "name"
t.index ["id", "name"], name: "index_cities_on_id_and_name"
end

create_table "services", force: :cascade do |t|
t.string "name"
t.index ["id", "name"], name: "index_services_on_id_and_name"
end

create_table "trips", force: :cascade do |t|
Expand All @@ -40,6 +45,7 @@
t.integer "duration_minutes"
t.integer "price_cents"
t.integer "bus_id"
t.index ["id", "from_id", "to_id"], name: "index_trips_on_id_and_from_id_and_to_id"
end

end
80 changes: 61 additions & 19 deletions lib/tasks/utils.rake
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Наивная загрузка данных из json-файла в БД
# rake reload_json[fixtures/small.json]
require 'oj'

task :reload_json, [:file_name] => :environment do |_task, args|
json = JSON.parse(File.read(args.file_name))
json = Oj.load(File.read(args.file_name))

ActiveRecord::Base.transaction do
City.delete_all
Expand All @@ -10,25 +10,67 @@ task :reload_json, [:file_name] => :environment do |_task, args|
Trip.delete_all
ActiveRecord::Base.connection.execute('delete from buses_services;')

ActiveRecord::Base.connection.tables.each do |t|
ActiveRecord::Base.connection.reset_pk_sequence!(t)
end

cities = []
bus_array = []

json.each do |trip|
from = City.find_or_create_by(name: trip['from'])
to = City.find_or_create_by(name: trip['to'])
services = []
trip['bus']['services'].each do |service|
s = Service.find_or_create_by(name: service)
services << s
cities.push("('#{trip['from']}')")
cities.push("('#{trip['to']}')")
bus_array.push(trip['bus'])
end

sql = "INSERT INTO cities (name) VALUES #{cities.uniq.join(', ')}"
ActiveRecord::Base.connection.execute(sql)
cities = City.pluck(:name, :id).to_h

buses = []
services = []

bus_array.each do |obj|
buses.push("(#{obj['number']}, '#{obj['model']}')")
obj['services'].each { |service| services.push("('#{service}')") }
end

sql = "INSERT INTO buses (number, model) VALUES #{buses.uniq.join(', ')}"
ActiveRecord::Base.connection.execute(sql)
buses = Bus.pluck(:id, :number, :model)

sql = "INSERT INTO services (name) VALUES #{services.uniq.join(', ')}"
ActiveRecord::Base.connection.execute(sql)

list_services = Service.pluck(:name, :id).to_h
buses_services = []
trips = []

json.each do |trip|
bus = buses.detect do |obj|
obj[1] == trip['bus']['number'] &&
obj[2] == trip['bus']['model']
end
list_services.slice(*trip['bus']['services'])
.each_value do |service_id|
buses_services.push("(#{bus[0]}, #{service_id})")
end
bus = Bus.find_or_create_by(number: trip['bus']['number'])
bus.update(model: trip['bus']['model'], services: services)

Trip.create!(
from: from,
to: to,
bus: bus,
start_time: trip['start_time'],
duration_minutes: trip['duration_minutes'],
price_cents: trip['price_cents'],
trips.push(
"(
#{cities[trip['from']]},
#{cities[trip['to']]},
#{bus[0]},
'#{trip['start_time']}',
#{trip['duration_minutes']},
#{trip['price_cents']}
)"
)
end

sql = "INSERT INTO buses_services (bus_id, service_id) VALUES #{buses_services.uniq.join(', ')}"
ActiveRecord::Base.connection.execute(sql)

sql = "INSERT INTO trips (from_id, to_id, bus_id, start_time, duration_minutes, price_cents) VALUES #{trips.join(', ')}"
ActiveRecord::Base.connection.execute(sql)
end
end