diff options
| author | Bruno Perles | 2015-12-16 10:02:29 +0100 |
|---|---|---|
| committer | Bruno Perles | 2015-12-16 10:02:29 +0100 |
| commit | 013f4fa8fe9bb08f3ed1d15f905ca2a8437d6aa7 (patch) | |
| tree | 426b9c17167c10547da2222517cbd4433ae554fe | |
| parent | 2590606c5912a85b8cb1aaa40c57dab67d75e7f7 (diff) | |
| download | chouette-core-013f4fa8fe9bb08f3ed1d15f905ca2a8437d6aa7.tar.bz2 | |
Add route_sections for traces
50 files changed, 1339 insertions, 93 deletions
@@ -52,6 +52,9 @@ platforms :ruby do gem 'sqlite3' end +gem 'activerecord-postgis-adapter' +gem 'polylines' + # Authentication gem 'devise', '~> 3.4.0' gem 'devise-encryptable' @@ -112,7 +115,8 @@ group :development do gem 'guard' gem 'guard-rspec' gem 'rails-erd' - gem 'meta_request' + # MetaRequest is incompatible with rgeo-activerecord + # gem 'meta_request' gem 'letter_opener' gem 'quiet_assets', '~> 1.0' gem 'simplecov', '~> 0.10.0' diff --git a/Gemfile.lock b/Gemfile.lock index d439cef61..175b2e760 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -44,6 +44,9 @@ GEM activerecord-jdbcpostgresql-adapter (1.3.15) activerecord-jdbc-adapter (~> 1.3.15) jdbc-postgres (>= 9.1) + activerecord-postgis-adapter (2.2.2) + activerecord (>= 4.0.0, < 4.2.0) + rgeo-activerecord (~> 1.2) activesupport (4.1.10) i18n (~> 0.6, >= 0.6.9) json (~> 1.7, >= 1.7.7) @@ -76,7 +79,6 @@ GEM builder (3.2.2) calendar_helper (0.2.5) open4 - callsite (0.0.11) capistrano (2.13.5) highline net-scp (>= 1.0.0) @@ -106,7 +108,7 @@ GEM coffee-script-source (1.9.1) daemons (1.1.9) database_cleaner (1.4.1) - dbf (3.0.1) + dbf (3.0.0) debug_inspector (0.0.2) deep_cloneable (2.0.2) activerecord (>= 3.1.0, < 5.0.0) @@ -219,9 +221,9 @@ GEM launchy (2.4.3-java) addressable (~> 2.3) spoon (~> 0.0.1) - letter_opener (1.3.0) + letter_opener (1.4.1) launchy (~> 2.2) - libv8 (3.16.14.7) + libv8 (3.16.14.11) listen (2.8.6) celluloid (>= 0.15.2) rb-fsevent (>= 0.9.3) @@ -230,10 +232,6 @@ GEM mail (2.6.3) mime-types (>= 1.16, < 3) map_layers (0.0.4) - meta_request (0.3.4) - callsite (~> 0.0, >= 0.0.11) - rack-contrib (~> 1.1) - railties (>= 3.0.0, < 5.0.0) method_source (0.8.2) mime-types (2.4.3) mimemagic (0.3.0) @@ -268,6 +266,7 @@ GEM websocket-driver (>= 0.2.0) polyamorous (1.1.0) activerecord (>= 3.0) + polylines (0.3.0) pry (0.10.1) coderay (~> 1.1.0) method_source (~> 0.8.1) @@ -277,15 +276,13 @@ GEM method_source (~> 0.8.1) slop (~> 3.4) spoon (~> 0.0) - pry-rails (0.3.3) + pry-rails (0.3.4) pry (>= 0.9.10) quiet_assets (1.1.0) railties (>= 3.1, < 5.0) rabl (0.11.6) activesupport (>= 2.3.14) - rack (1.5.5) - rack-contrib (1.2.0) - rack (>= 0.9.1) + rack (1.5.3) rack-test (0.6.3) rack (>= 1.0) rails (4.1.10) @@ -355,10 +352,13 @@ GEM ffi (>= 0.5.0) rdoc (4.2.0) json (~> 1.4) - ref (1.0.5) + ref (2.0.0) responders (1.1.2) railties (>= 3.2, < 4.2) rgeo (0.4.0) + rgeo-activerecord (1.2.0) + activerecord (~> 4.0) + rgeo (~> 0.3) roo (1.13.2) nokogiri rubyzip @@ -481,6 +481,7 @@ DEPENDENCIES RedCloth SyslogLogger activerecord-jdbcpostgresql-adapter (~> 1.3.3) + activerecord-postgis-adapter acts_as_list (~> 0.6.0) acts_as_tree (~> 2.1.0) apartment (~> 1.0.0) @@ -522,12 +523,12 @@ DEPENDENCIES launchy letter_opener map_layers (= 0.0.4) - meta_request mimemagic newrelic_rpm ninoxe! pg poltergeist + polylines pry-rails quiet_assets (~> 1.0) rabl diff --git a/app/assets/images/icons/edit-disabled.png b/app/assets/images/icons/edit-disabled.png Binary files differnew file mode 100644 index 000000000..aaefed65c --- /dev/null +++ b/app/assets/images/icons/edit-disabled.png diff --git a/app/assets/javascripts/route_section.js.coffee b/app/assets/javascripts/route_section.js.coffee new file mode 100644 index 000000000..f2e494c0c --- /dev/null +++ b/app/assets/javascripts/route_section.js.coffee @@ -0,0 +1,58 @@ +class @RouteSectionMap + @onSelectedFeature: (feature) -> + route_section_id = feature.data.id + + routeSectionOption = $("option[value=#{route_section_id}]") + routeSectionOption.parent().val route_section_id + + $('#map-selection').show() + $('#empty-map-selection').hide() + + selectionUrl = location.pathname.replace /edit$/, "selection" + $.ajax(url: selectionUrl, method: 'POST', data: { route_section_id: route_section_id }, dataType: 'html').done (data) -> + $('#map-selection div').replaceWith(data) + + @onUnselectedFeature: (feature) -> + $('#map-selection').hide() + $('#empty-map-selection').show() + +jQuery -> + if $("#map.route_section").length > 0 and user_geometry? + projWGS84 = new OpenLayers.Projection("EPSG:4326") + proj900913 = new OpenLayers.Projection("EPSG:900913") + wtk_format = new OpenLayers.Format.WKT() + + user_geometry.events.on({ + afterfeaturemodified: (event) -> + wgs84_geometry = event.feature.geometry.transform(proj900913, projWGS84) + wgs84_feature = new OpenLayers.Feature.Vector(wgs84_geometry) + ewtk = "SRID=4326;#{wtk_format.write(wgs84_feature)}" + + $('#route_section_editable_geometry').val(ewtk) + return + }) + + $('#new_route_sections_selector select').on 'change', -> + new_route_section_id = $(this).val() + + edit_link = $(this).closest("tr").find("a.edit-route-section") + + # Save edit link to play with it + unless edit_link.data("href-pattern")? + edit_link.data "href-pattern", edit_link.attr('href').replace(new RegExp("/route_sections/([0-9]+)/edit"), "/route_sections/:id/edit") + + if !!new_route_section_id + edit_link.removeClass "disabled" + edit_link.attr 'href', edit_link.data("href-pattern").replace(/:id/, new_route_section_id) + else + edit_link.addClass "disabled" + edit_link.attr 'href', '#' + + $('form.route_section').find('button[type="submit"]').on 'click', (e) -> + e.preventDefault(); + if typeof modify_feature != 'undefined' + modify_feature.deactivate() + $('form.route_section').submit() + return + + return diff --git a/app/assets/stylesheets/main/route_sections.css.scss b/app/assets/stylesheets/main/route_sections.css.scss new file mode 100644 index 000000000..cc1c85abc --- /dev/null +++ b/app/assets/stylesheets/main/route_sections.css.scss @@ -0,0 +1,68 @@ +#workspace.route_sections_selectors.edit { + td.route_section { + .input { + padding: 0; + margin: 0; + + select { + width: 100%; + } + } + } + + a.edit-route-section { + background: url(image-path('icons/edit.png')) no-repeat 0% 50%; + text-indent: -9999px; + display: inline-block; + width: 16px; + height: 16px; + + margin-right: 8px; + + &.disabled { + background-image: url(image-path('icons/edit-disabled.png')); + } + } + + #map-selection { + position: relative; + span { + display: inline-block; + } + .departure, .arrival { + width: 25%; + } + .actions { + width: 25%; + overflow: visible; + padding-left: 0; + position: absolute; + right: 0; + } + } +} + +#workspace.route_sections.index { + th.distance, th.points { + text-align: center; + } + + td.distance, td.points, td.actions { + text-align: center; + } +} + +#workspace.route_sections.edit { + .formtastic { + .input .label { + width: 40%; + } + .actions { + padding-left: 19%; + } + } + #map { + width: 600px; + heigth: 600px; + } +} diff --git a/app/assets/stylesheets/main/routes.scss b/app/assets/stylesheets/main/routes.scss index 7714c13a3..44703c7e5 100644 --- a/app/assets/stylesheets/main/routes.scss +++ b/app/assets/stylesheets/main/routes.scss @@ -3,7 +3,7 @@ // You can use Sass (SCSS) here: http://sass-lang.com/ #workspace.lines.show -{ +{ } #workspace.routes.edit, #workspace.routes.new, #workspace.routes.create, #workspace.routes.update @@ -11,13 +11,13 @@ #route_color{ width: 100px; color: white; font-weight: bold;} - + #stop_points .nested-fields { ol { margin-left: 25%; - .handle { margin-left: 5px;} + .handle { margin-left: 5px;} - .search_stop_area { + .search_stop_area { margin-bottom: 0px !important; } @@ -31,7 +31,7 @@ #stop_points .links { margin: 10px 0 15px 25%; - } + } } #workspace.routes.edit_boarding_alighting{ @@ -39,10 +39,18 @@ .stop_area{ padding-top: 7px; } - + } #workspace.routes.show -{ -} +{ +} +.large-map { + width: 100%; + height: 600px; + #map { + width: 100%; + height: 100%; + } +} diff --git a/app/assets/stylesheets/modules/icons.scss b/app/assets/stylesheets/modules/icons.scss index 001e511d1..3c42c3bd6 100644 --- a/app/assets/stylesheets/modules/icons.scss +++ b/app/assets/stylesheets/modules/icons.scss @@ -5,6 +5,11 @@ a:before { vertical-align: middle; } +a.view:before { // fa-eye + content: "\f06e"; + color: $brand-success; +} + a.add:before { // fa-plus-circle content: "\f055"; color: $brand-success; diff --git a/app/controllers/route_sections_controller.rb b/app/controllers/route_sections_controller.rb new file mode 100644 index 000000000..64cb8c65c --- /dev/null +++ b/app/controllers/route_sections_controller.rb @@ -0,0 +1,70 @@ +class RouteSectionsController < ChouetteController + + defaults :resource_class => Chouette::RouteSection + + respond_to :html + respond_to :kml, :only => :show + + belongs_to :referential + + before_action :save_return_to_path, only: [:edit, :create_to_edit] + before_action ->(controller) { build_breadcrumb controller.action_name } + + helper_method :search + + def index + index! + end + + def new + @stop_areas = referential.stop_areas.with_geometry.order :name + new! + end + + def show + @map = RouteSectionMap.new(resource).with_helpers(self) + show! + end + + def edit + @map = RouteSectionMap.new(resource, true).with_helpers(self) + edit! + end + + def update + update! { session.delete(:return_to) } + end + + def create + create! { session.delete(:return_to) } + end + + def create_to_edit + route_section = Chouette::RouteSection.create(route_section_params) + redirect_to edit_referential_route_section_path(referential, route_section) + end + + protected + + def save_return_to_path + session[:return_to] = params[:return_to] if params[:return_to] + end + + def collection + # if q = params[:q] + # @route_sections ||= Chouette::RouteSection.joins(:departure, :arrival).where(departure: {name: "#{q}"}).or.where(arrival: {name: "#{q}"}) + # end + @route_sections ||= search.collection.includes(:departure, :arrival).paginate page: params[:page] + end + + def search + @search ||= RouteSectionSearch.new(params[:route_section_search]) + end + + private + + def route_section_params + params.require(:route_section).permit(:departure_id, :arrival_id, :editable_geometry, :no_processing) + end + +end diff --git a/app/controllers/route_sections_selectors_controller.rb b/app/controllers/route_sections_selectors_controller.rb new file mode 100644 index 000000000..05a399ae8 --- /dev/null +++ b/app/controllers/route_sections_selectors_controller.rb @@ -0,0 +1,42 @@ +class RouteSectionsSelectorsController < ChouetteController + + # singleton option makes association_chain crazy + #defaults singleton: true + + respond_to :html, only: [ :edit, :update ] + respond_to :js, only: :section + + belongs_to :referential do + belongs_to :line, :parent_class => Chouette::Line do + belongs_to :route, :parent_class => Chouette::Route do + belongs_to :journey_pattern, parent_class: Chouette::JourneyPattern + end + end + end + + def edit + @map = RouteSectionSelectorMap.new(resource).with_helpers(self) + end + + def selection + parent + + @route_section = referential.route_sections.find params[:route_section_id].to_i + render partial: 'selection', format: 'js' + end + + private + + def resource + @route_sections_selector ||= RouteSectionsSelector.new parent + end + + def build_resource + @route_sections_selector ||= RouteSectionsSelector.new parent, *resource_params + end + + def route_section_selector_params + params.require(:route_section_selector).permit() + end + +end diff --git a/app/controllers/routes_controller.rb b/app/controllers/routes_controller.rb index 6dfaf3dd0..59c129867 100644 --- a/app/controllers/routes_controller.rb +++ b/app/controllers/routes_controller.rb @@ -75,7 +75,7 @@ class RoutesController < ChouetteController end private - + def route_params params.require(:route).permit( :direction_code, :wayback_code, :line_id, :objectid, :object_version, :creation_time, :creator_id, :name, :comment, :opposite_route_id, :published_name, :number, :direction, :wayback, { stop_points_attributes: [ :id, :_destroy, :position, :stop_area_id, :for_boarding, :for_alighting ] } ) end diff --git a/app/controllers/stop_areas_controller.rb b/app/controllers/stop_areas_controller.rb index 9321ac9ae..dbbadb80c 100644 --- a/app/controllers/stop_areas_controller.rb +++ b/app/controllers/stop_areas_controller.rb @@ -137,6 +137,6 @@ class StopAreasController < ChouetteController def stop_area_params params.require(:stop_area).permit( :routing_stop_ids, :routing_line_ids, :children_ids, :stop_area_type, :parent_id, :objectid, :object_version, :creation_time, :creator_id, :name, :comment, :area_type, :registration_number, :nearest_topic_name, :fare_code, :longitude, :latitude, :long_lat_type, :country_code, :street_name, :zip_code, :city_name, :mobility_restricted_suitability, :stairs_availability, :lift_availability, :int_user_needs, :coordinates, :url, :time_zone ) - end + end end diff --git a/app/helpers/breadcrumb_helper.rb b/app/helpers/breadcrumb_helper.rb index 52da8b887..69494321b 100644 --- a/app/helpers/breadcrumb_helper.rb +++ b/app/helpers/breadcrumb_helper.rb @@ -1,6 +1,7 @@ module BreadcrumbHelper - def build_breadcrumb(action) + def build_breadcrumb(action) + action = action.to_sym case resource_class.to_s when "Chouette::Network" network_breadcrumb action @@ -30,6 +31,8 @@ module BreadcrumbHelper connection_link_breadcrumb action when "Chouette::TimeTable" time_table_breadcrumb action + when "Chouette::RouteSection" + route_section_breadcrumb action when "Chouette::Timeband" timeband_breadcrumb action when "StopAreaCopy" @@ -106,6 +109,12 @@ module BreadcrumbHelper add_breadcrumb breadcrumb_label(@time_table), referential_time_table_path(@referential, @time_table),:title => breadcrumb_tooltip(@time_table) if action == :edit end + def route_section_breadcrumb(action) + referential_breadcrumb + add_breadcrumb Chouette::RouteSection.model_name.human.pluralize, referential_route_sections_path(@referential) + add_breadcrumb breadcrumb_label(resource), referential_route_section_path(@referential, resource),:title => breadcrumb_tooltip(resource) if action.in?([:show, :edit]) + end + def timeband_breadcrumb(action) referential_breadcrumb add_breadcrumb Chouette::Timeband.model_name.human(:count => 2), referential_timebands_path(@referential) unless action == :index diff --git a/app/helpers/route_section_selectors_helper.rb b/app/helpers/route_section_selectors_helper.rb new file mode 100644 index 000000000..1be30066b --- /dev/null +++ b/app/helpers/route_section_selectors_helper.rb @@ -0,0 +1,23 @@ +module RouteSectionSelectorsHelper + + def link_to_edit_route_section(route_section) + classes = [ 'edit-route-section' ] + link ='#' + + if route_section.present? + return_to = edit_referential_line_route_journey_pattern_route_sections_selector_path(@referential, @line, @route, @journey_pattern) + link = edit_referential_route_section_path(@referential, route_section, return_to: return_to) + else + classes << 'disabled' + end + + link_to "Edit", link, class: classes, title: t('route_sections_selectors.edit.route_section.edit') + end + + def link_to_create_route_section(departure, arrival) + return_to = edit_referential_line_route_journey_pattern_route_sections_selector_path(@referential, @line, @route, @journey_pattern) + link_to t('route_sections_selectors.edit.route_section.new'), + create_to_edit_referential_route_sections_path(@referential, route_section: {departure_id:departure.id, arrival_id: arrival.id}, return_to: return_to) + end + +end diff --git a/app/maps/design/route_section_selector_style_map.rb b/app/maps/design/route_section_selector_style_map.rb new file mode 100644 index 000000000..12f192ec8 --- /dev/null +++ b/app/maps/design/route_section_selector_style_map.rb @@ -0,0 +1,73 @@ +class Design::RouteSectionSelectorStyleMap < Design::GenericStyleMap + attr_accessor :style + + def initialize(helpers, options = {}) + @helpers = helpers + @style = options[:style].present? ? default_style.merge(options[:style]) : default_style + end + + def select_style + { + fillColor: "blue", + graphicName: "square", + rotation: 90, + strokeColor: "#00dd00", + pointRadius: 15, + graphicZIndex: 100 + } + end + + def highlight_style + { + fillColor: "orange", + graphicName: "square", + rotation: 90, + strokeColor: "#dd0000", + pointRadius: 15, + graphicZIndex: 200 + } + end + + def default_style + { + label: "${label}", + fontColor: "black", + fontSize: "11px", + fontWeight: "bold", + labelAlign: "ct", + labelXOffset: 0, + labelYOffset: -15, + strokeColor: "#0000dd", + strokeOpacity: 1, + strokeWidth: 3, + strokeLineCap: "round", + strokeDashstyle: "solid", + externalGraphic: @helpers.assets_path_patch( "map/${positionType}.png"), + graphicWidth: 12, + graphicHeight: 12, + graphicOpacity: 1, + graphicXOffset: -6, + graphicYOffset: -6, + display: true, + fillColor: "red", + graphicName: "square", + rotation: 90, + graphicZIndex: 10 + } + end + + def context + { + label: :" function(feature) {if(feature.layer.map.getZoom() > 13) { return feature.attributes.name;} else {return '';}} ", + positionType: :" function(feature) { if (feature.attributes.iconCode != undefined) {return feature.attributes.iconCode;} else { return '';} } " + } + end + + def style_map + OpenLayers::StyleMap.new( + default: OpenLayers::Style.new(style, { context: context}), + select: OpenLayers::Style.new(style.merge(select_style), { context: context }), + highlight: OpenLayers::Style.new(style.merge( highlight_style), { context: context })) + end + +end diff --git a/app/maps/design/route_section_style_map.rb b/app/maps/design/route_section_style_map.rb new file mode 100644 index 000000000..2c94bb3a0 --- /dev/null +++ b/app/maps/design/route_section_style_map.rb @@ -0,0 +1,66 @@ +class Design::RouteSectionStyleMap < Design::GenericStyleMap + attr_accessor :style + + def initialize(helpers, options = {}) + @helpers= helpers + @style = options[:style].present? ? default_style.merge(options[:style]) : default_style + end + + def select_style + { + fillColor:"blue", + graphicName:"circle", + rotation:90, + :strokeColor => "red", + pointerEvents: "visiblePainted" + } + end + + def highlight_style + { + fillColor:"lightblue", + graphicName:"circle", + rotation:90, + :strokeColor => "#dd0000" + } + end + + def default_style + + { + :fontColor => "black", + :fontSize => "11px", + :fontWeight => "bold", + :labelAlign => "cm", + :labelXOffset => 0, + :labelYOffset => -15, + :strokeColor => "green", + :strokeOpacity => 1, + :strokeWidth => 2, + :strokeLineCap => "round", + :strokeLineJoin => "round", + :strokeDashstyle => "solid", + :lineCap => "round", + :lineJoin => "round", + :dashstyle => "solid", + :graphicWidth => 12, + :graphicHeight => 12, + :graphicOpacity => 1, + :graphicXOffset => -6, + :graphicYOffset => -6, + :display => true, + fillOpacity: 0.5, + fillColor: "lightblue", + graphicName: "circle", + pointRadius: 6, + pointerEvents: "visiblePainted", + rotation: 90 + } + + end + + def style_map + OpenLayers::StyleMap.new(:default => OpenLayers::Style.new(style), :select => OpenLayers::Style.new(style.merge( select_style)), :highlight => OpenLayers::Style.new(style.merge( highlight_style))) + end + +end diff --git a/app/maps/route_section_map.rb b/app/maps/route_section_map.rb new file mode 100644 index 000000000..cfa40d481 --- /dev/null +++ b/app/maps/route_section_map.rb @@ -0,0 +1,67 @@ +class RouteSectionMap < ApplicationMap + + attr_reader :route_section + + attr_accessor :editable + alias_method :editable?, :editable + + def initialize(route_section, editable = false) + @route_section = route_section + @editable = editable + end + + def customize_map(map, page) + # layers order seems to matter for ModifyFeature control + route_section.stop_areas.each do |stop_area| + layer = "stop_area_#{stop_area.id}".to_sym + page.assign layer.to_s, kml_layer(stop_area, :styleMap => Design::StopAreasStyleMap.new(helpers).style_map) + page << map.add_layer(layer) + page << map.add_control( hover_control_display_name(layer) ) + end + + geometry_options = {}.tap do |options| + options[:mode] = :editable if editable? + end + geometry_uneditable_kml_layer = kml_layer(route_section, :styleMap => Design::RouteSectionSelectorStyleMap.new(helpers).style_map) + page << map.add_layer(geometry_uneditable_kml_layer) + + if route_section.input_geometry + geometry_editable_layer = kml_layer(route_section, geometry_options, {}) # , :styleMap => Design::LineStyleMap.new(style: nil).style_map) + else + points = route_section.stop_areas.map{|point| OpenLayers::Geometry::Point.new(point.longitude, point.latitude).transform("EPSG:4326", "EPSG:900913")} + geometry_editable_layer = OpenLayers::Layer::Vector.new("user_geometry", {:projection => projection("EPSG:4326"), :styleMap => Design::RouteSectionStyleMap.new(helpers).style_map}) + #geometry_editable_layer = OpenLayers::Layer::Vector.new("user_geometry", {:projection => projection("EPSG:4326")}) + geometry_editable_features = OpenLayers::Feature::Vector.new(OpenLayers::Geometry::LineString.new(points)) + page.assign :geometry_editable_features, geometry_editable_features + end + + if editable + page.assign :user_geometry, geometry_editable_layer + + page << "user_geometry.addFeatures([geometry_editable_features])" if geometry_editable_features + + page << map.add_layer(:user_geometry) + + page.assign :modify_feature, OpenLayers::Control::ModifyFeature.new(:user_geometry, autoActivate: true) + page << map.add_control( :modify_feature ) + else + page << map.add_layer(geometry_editable_layer) + end + + page << map.zoom_to_extent(bounds.to_google.to_openlayers) if bounds + end + + def bounds + @bounds ||= + if route_section.geometry.present? + route_section.geometry.bounds + elsif route_section.stop_areas.present? + GeoRuby::SimpleFeatures::Point.bounds route_section.stop_areas.collect(&:geometry) + end + end + + def ready? + bounds.present? + end + +end diff --git a/app/maps/route_section_selector_map.rb b/app/maps/route_section_selector_map.rb new file mode 100644 index 000000000..425a6750a --- /dev/null +++ b/app/maps/route_section_selector_map.rb @@ -0,0 +1,118 @@ +class RouteSectionSelectorMap < ApplicationMap + + attr_reader :route_section_selector, :style + + def initialize(route_section_selector, style = nil) + @route_section_selector = route_section_selector + @style = nil + end + + def customize_map(map, page) + layer = kml_layer([route_section_selector.itinerary.referential, route_section_selector.itinerary.route.line, route_section_selector.itinerary.route, route_section_selector.itinerary], + { rendererOptions: { zIndexing: true }, styleMap: Design::JourneyPatternStyleMap.new(helpers).style_map }) + page.assign 'journeyPatternLayer', layer + + page << map.add_layer(:journeyPatternLayer) + page << map.add_control(hover_control_display_name(:journeyPatternLayer)) + + route_section_geometry = OpenLayers::Layer::Vector.new('Route Section Geometry', + { projection: projection('EPSG:900913'), + rendererOptions: { zIndexing: true }, + styleMap: Design::RouteSectionSelectorStyleMap.new(helpers).style_map}) + + route_section_layer_points = [] + route_section_selector.sections.reject{|s| s.candidates.length==0}.each do |section| + section.candidates.each do |candidate| + geometry = candidate.processed_geometry + route_section_layer_points << ["#{candidate.id}"] + clean_route_section_line(geometry) + end + end + + page.assign :route_section_layer_points, route_section_layer_points + page << <<EOF + var route_section_layers; + route_section_layers = route_section_layer_points.map(function(elt, index) { + var route_section_id = elt[0]; + elt.splice(0, 1); + var points = elt.map( function(e,i) { + return OpenLayers.Projection.transform(new OpenLayers.Geometry.Point(e[0], e[1]), "EPSG:4326", "EPSG:900913" ); + }) + return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString(points), {id: route_section_id, name: ""}); + }) +EOF + page.assign :route_section_geometry, route_section_geometry + page << 'route_section_geometry.addFeatures(route_section_layers)' + page << map.add_layer(:route_section_geometry) + + page << <<EOF + function selected(feature) { + RouteSectionMap.onSelectedFeature(feature); + } + function unselected(feature) { + RouteSectionMap.onUnselectedFeature(feature); + } + + highlightControl = new OpenLayers.Control.SelectFeature([route_section_geometry], + { + clickout: true, + toggle: false, + multiple:false, + hover:true, + highlightOnly:true, + eventListeners:{ + featurehighlighted: function (event) { + event.feature.layer.drawFeature( + event.feature, + 'highlight' + ); + }, + featureunhighlighted: function (event) { + event.feature.layer.drawFeature( + event.feature, + 'default' + ); + } + } + } + ); + selectControl = new OpenLayers.Control.SelectFeature([route_section_geometry], + { + onSelect:selected, + onUnselect:unselected + } + ); + map.addControl(highlightControl); + map.addControl(selectControl); + highlightControl.activate(); + selectControl.activate(); +EOF + + #page.assign :select_feature, OpenLayers::Control::SelectFeature.new(:route_section_geometry, {onSelect: selected, onUnselect: unselected}) + #page << map.add_control( :select_feature ) + + + page << map.zoom_to_extent(bounds.to_google.to_openlayers) if bounds + + end + + def clean_route_section_line(line) + point_array = line.to_s.scan(/\d+[.]\d+\s\d+[.]\d+/) + proj = OpenLayers::Projection.new('proj') + + point_array.map do |point| + point = point.scan(/\d+[.]\d+/) + lat = point[0].to_f + lng = point[1].to_f + [lat, lng] + end + + end + + def ready? + bounds.present? + end + + def bounds + @bounds ||= GeoRuby::SimpleFeatures::Point.bounds(route_section_selector.itinerary.route.stop_areas.collect(&:geometry).compact) + end +end diff --git a/app/models/referential.rb b/app/models/referential.rb index e32c956fb..d537246e5 100644 --- a/app/models/referential.rb +++ b/app/models/referential.rb @@ -91,6 +91,10 @@ class Referential < ActiveRecord::Base Chouette::VehicleJourney.all end + def route_sections + Chouette::RouteSection.all + end + after_initialize :define_default_attributes def define_default_attributes diff --git a/app/models/route_section_search.rb b/app/models/route_section_search.rb new file mode 100644 index 000000000..a03eb894d --- /dev/null +++ b/app/models/route_section_search.rb @@ -0,0 +1,34 @@ +class RouteSectionSearch + include ActiveModel::Conversion + extend ActiveModel::Naming + + attr_accessor :departure_name, :arrival_name, :line_id + attr_accessor :scope + + def scope + scope ||= Chouette::RouteSection + end + + def initialize(attributes = {}) + attributes.each { |k,v| send "#{k}=", v } if attributes + end + + def collection() + Rails.logger.debug "Search RouteSections with #{inspect}" + collection = scope + + [:departure, :arrival].each do |endpoint| + endpoint_name = send "#{endpoint}_name" + collection = collection.by_endpoint_name(endpoint, endpoint_name) if endpoint_name.present? + end + + collection = collection.by_line_id(line_id) if line_id.present? + + collection + end + + def persisted? + false + end + +end diff --git a/app/models/route_sections_selector.rb b/app/models/route_sections_selector.rb new file mode 100644 index 000000000..ba8a2cc9a --- /dev/null +++ b/app/models/route_sections_selector.rb @@ -0,0 +1,99 @@ +class RouteSectionsSelector + extend ActiveModel::Naming + include ActiveModel::Conversion + + include ActiveModel::Validations + + attr_reader :itinerary + + def initialize(route_or_journey_pattern, attributes = {}) + @itinerary = route_or_journey_pattern + + self.attributes = attributes + end + + def attributes=(attributes) + attributes.each { |k,v| send "#{k}=", v } + end + + def update_attributes(attributes) + self.attributes = attributes + save + end + + # def persisted? + # false + # end + + delegate :stop_points, to: :itinerary + + def route_sections + @route_sections ||= itinerary.route_sections.to_a + end + + def sections + @sections ||= create_sections + end + + def create_sections + [].tap do |sections| + stop_points.each_cons(2).each_with_index do |(departure, arrival), index| + sections << Section.new(departure.stop_area, arrival.stop_area, route_sections[index]) + end + end + end + + def sections_attributes=(attributes) + # Process the attributes hash + attributes.each do |index, section_attributes| + sections[index.to_i].attributes = section_attributes + end + end + + def save + itinerary.update_attribute :route_section_ids, sections.map(&:route_section_id) + end + + class Section + extend ActiveModel::Translation + + attr_accessor :departure, :arrival, :route_section_id + + def initialize(departure, arrival, route_section = nil) + @departure, @arrival = departure, arrival + + self.route_section = route_section + end + + def route_section=(route_section) + @route_section = route_section + @route_section_id = route_section.respond_to?(:id) ? route_section.id : nil + end + + def route_section + @route_section ||= candidates.find_by id: route_section_id + end + + def persisted? + false + end + + def candidates + @candidates ||= Chouette::RouteSection.where(departure: departure, arrival: arrival) + end + + def create_candidate + Chouette::RouteSection.create(departure: departure, arrival: arrival) + end + + def attributes=(attributes) + attributes.each { |k,v| send "#{k}=", v } + end + + def valid? + route_section.present? + end + + end + +end diff --git a/app/views/journey_patterns/show.html.erb b/app/views/journey_patterns/show.html.erb index dc9e852fa..3a2b18ea1 100644 --- a/app/views/journey_patterns/show.html.erb +++ b/app/views/journey_patterns/show.html.erb @@ -34,9 +34,9 @@ <ul class="actions"> <li><%= link_to t('journey_patterns.actions.new'), new_referential_line_route_journey_pattern_path(@referential, @line, @route), :class => "add" %></li> <li><%= link_to t('journey_patterns.actions.edit'), edit_referential_line_route_journey_pattern_path(@referential, @line, @route, @journey_pattern), :class => "edit" %></li> - <li><%= link_to t('journey_patterns.actions.destroy'), referential_line_route_journey_pattern_path(@referential, @line, @route, @journey_pattern), :method => :delete, :data => {:confirm => t('journey_patterns.actions.destroy_confirm')}, :class => "remove" %></li> + <li><%= link_to t('journey_patterns.actions.destroy'), referential_line_route_journey_pattern_path(@referential, @line, @route, @journey_pattern), :method => :delete, :data => {:confirm => t('journey_patterns.actions.destroy_confirm')}, :class => "remove" %></li> + <li><%= link_to t('journey_patterns.actions.edit_route_sections'), edit_referential_line_route_journey_pattern_route_sections_selector_path(@referential, @line, @route, @journey_pattern), class: 'edit' %></li> <li><%= link_to t('journey_patterns.journey_pattern.vehicle_journey_at_stops'), referential_line_route_vehicle_journeys_path(@referential, @line, @route, :q => {:journey_pattern_id_eq => @journey_pattern.id}), :class => "clock" %></li> </ul> <%= creation_tag(@journey_pattern) %> <% end %> - diff --git a/app/views/referentials/_counts.html.erb b/app/views/referentials/_counts.html.erb index 3ade4e945..20078429b 100644 --- a/app/views/referentials/_counts.html.erb +++ b/app/views/referentials/_counts.html.erb @@ -32,6 +32,10 @@ <%= Referential.human_attribute_name("connection_links") %> </li> <li class="list-group-item"> + <span class="badge"><%= @referential.route_sections.size %></span> + <%= link_to Referential.human_attribute_name("route_sections"), referential_route_sections_path(@referential) %> + </li> + <li class="list-group-item"> <span class="badge"><%= @referential.stop_areas.size %></span> <%= Referential.human_attribute_name("stop_areas") %> </li> diff --git a/app/views/route_sections/_form.html.erb b/app/views/route_sections/_form.html.erb new file mode 100644 index 000000000..28a1dd47a --- /dev/null +++ b/app/views/route_sections/_form.html.erb @@ -0,0 +1,24 @@ +<%= semantic_form_for [@referential, @route_section] do |form| %> + <%= form.inputs do %> + <% if @route_section.new_record? %> + <%= form.input :departure, as: :select, collection: @stop_areas, include_blank: false %> + <%= form.input :arrival, as: :select, collection: @stop_areas, include_blank: false %> + <% else %> + <li class="input optional"> + <label class="label"><%= @route_section.human_attribute_name("departure") %></label> + <%= @route_section.departure.name %> + </li> + <li class="input optional"> + <label class="label"><%= @route_section.human_attribute_name("arrival") %></label> + <%= @route_section.arrival.name %> + </li> + <%= form.input :editable_geometry, as: :hidden %> + <% end %> + + <%= form.input :no_processing, label: t('.no_processing'), as: :select, collection: { t('.standard_processor') => false, t('.no_processor') => true }, include_blank: false %> + <% end %> + <%= form.actions do %> + <%= form.action :submit, :as => :button, label: t('.submit') %> + <%= form.action :cancel, :as => :link %> + <% end %> +<% end %> diff --git a/app/views/route_sections/edit.html.erb b/app/views/route_sections/edit.html.erb new file mode 100644 index 000000000..80b7bde4a --- /dev/null +++ b/app/views/route_sections/edit.html.erb @@ -0,0 +1,4 @@ +<%= title_tag t('route_sections.edit.title') %> + +<%= @map.to_html %> +<%= render "form" %> diff --git a/app/views/route_sections/index.html.erb b/app/views/route_sections/index.html.erb new file mode 100644 index 000000000..5d7bef989 --- /dev/null +++ b/app/views/route_sections/index.html.erb @@ -0,0 +1,56 @@ +<%= title_tag t('.title') %> + +<%= form_for search, url: referential_route_sections_path(@referential), method: :get, class: "form-inline" do |form| %> + <div class="panel panel-default"> + <div class="panel-heading"> + <div class="col-md-6"> + <%= form.text_field :departure_name, class: 'form-control', placeholder: Chouette::RouteSection.human_attribute_name(:departure) %> + </div> + + <div class="input-group col-md-6"> + <%= form.text_field :arrival_name, class: 'form-control', placeholder: Chouette::RouteSection.human_attribute_name(:arrival) %> + <div class="input-group-btn"> + <button class="btn btn-default" type="submit"><i class="fa fa-search"></i></button> + </div> + </div> + </div> + + <div class="panel-body"> + <div class="col-md-4"> + <%= form.select :line_id, @referential.lines.order(:name).pluck(:name, :id), { include_blank: t('.all_lines')}, class: 'form-control' %> + </div> + </div> + </div> +<% end %> + +<table class="table table-hover table-striped"> + <thead> + <tr> + <th><%= Chouette::RouteSection.human_attribute_name :departure %></th> + <th><%= Chouette::RouteSection.human_attribute_name :arrival %></th> + <th class="distance"><%= Chouette::RouteSection.human_attribute_name :distance %></th> + <th class="points"><%= Chouette::RouteSection.human_attribute_name :points %></th> + <th class="actions"></th> + </tr> + </thead> + <tbody> + <% @route_sections.each do |route_section| %> + <tr> + <td><%= route_section.departure.name %> <%= link_to content_tag(:i, "", class: "fa fa-external-link"), referential_stop_area_path(@referential, route_section.departure) %></td> + <td><%= route_section.arrival.name %> <%= link_to content_tag(:i, "", class: "fa fa-external-link"), referential_stop_area_path(@referential, route_section.arrival) %></td> + <td class="distance"><%= route_section.distance.to_i if route_section.distance %></td> + <td class="points"><%= route_section.via_count if route_section.via_count > 0 %></td> + <td class="actions"> + <%= link_to t('.actions.show'), referential_route_section_path(@referential, route_section), class: "view" %> + <%= link_to t('.actions.edit'), edit_referential_route_section_path(@referential, route_section), class: "edit" %> + <%= link_to t('.actions.destroy'), referential_route_section_path(@referential, route_section), method: :delete, data: { confirm: t('route_sections.actions.destroy_confirm') }, class: "remove" %> + </td> + </tr> + <% end %> + </tbody> + +</table> + +<div class="pagination"> + <%= will_paginate @route_sections, :container => false, renderer: RemoteBootstrapPaginationLinkRenderer %> +</div> diff --git a/app/views/route_sections/new.html.erb b/app/views/route_sections/new.html.erb new file mode 100644 index 000000000..1ff3c74d0 --- /dev/null +++ b/app/views/route_sections/new.html.erb @@ -0,0 +1,3 @@ +<%= title_tag t('route_sections.new.title') %> + +<%= render "form" %> diff --git a/app/views/route_sections/show.html.erb b/app/views/route_sections/show.html.erb new file mode 100644 index 000000000..61c7c8149 --- /dev/null +++ b/app/views/route_sections/show.html.erb @@ -0,0 +1,28 @@ +<%= title_tag t('.title') %> + +<div class="route_section"> + <%= @map.to_html %> + + <div class="summary"> + <p> + <label><%= @route_section.human_attribute_name("departure") %>: </label> + <%= @route_section.departure.name %> + </p> + <p> + <label><%= @route_section.human_attribute_name("arrival") %>: </label> + <%= @route_section.arrival.name %> + </p> + <p> + <label><%= @route_section.human_attribute_name("distance") %>: </label> + <%= "#{@route_section.distance.round}m" if @route_section.distance %> + </p> + </div> +</div> + +<% content_for :sidebar do %> +<ul class="actions"> + <li><%= link_to t('route_sections.actions.edit'), edit_referential_route_section_path(@referential, @route_section), :class => "edit" %></li> + <li><%= link_to t('route_sections.actions.destroy'), referential_route_section_path(@referential, @route_section), :method => :delete, :data => {:confirm => t('route_sections.actions.destroy_confirm')}, :class => "remove" %></li> +</ul> + <%= creation_tag(@route_section) %> +<% end %> diff --git a/app/views/route_sections/show.kml.erb b/app/views/route_sections/show.kml.erb new file mode 100644 index 000000000..0d41f0fdb --- /dev/null +++ b/app/views/route_sections/show.kml.erb @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kml xmlns="http://www.opengis.net/kml/2.2"> + <Document> + <Placemark id="route-section-<%= @route_section.id %>"> + <%= @route_section.geometry(params[:mode]).kml_representation.html_safe %> + </Placemark> + </Document> +</kml> diff --git a/app/views/route_sections_selectors/_selection.js.erb b/app/views/route_sections_selectors/_selection.js.erb new file mode 100644 index 000000000..70d03cf75 --- /dev/null +++ b/app/views/route_sections_selectors/_selection.js.erb @@ -0,0 +1,28 @@ +<div> + <span class="departure"> + <label><%= @route_section.human_attribute_name("departure") %>:</label> + <%= link_to @route_section.departure.name, referential_stop_area_path(@referential, @route_section.departure) %> + </span> + + <span class="arrival"> + <label><%= @route_section.human_attribute_name("arrival") %>:</label> + <%= link_to @route_section.arrival.name, referential_stop_area_path(@referential, @route_section.arrival) %> + </span> + + <span class="distance"> + <label><%= @route_section.human_attribute_name("distance") %>:</label> + <%= "#{@route_section.distance.to_i} m" if @route_section.distance > 0 %> + </span> + + <% if @route_section.via_count > 0 %> + <span class="via_count"> + <label><%= @route_section.human_attribute_name("via_count") %>:</label> + <%= @route_section.via_count if @route_section.via_count > 0 %> + </span> + <% end %> + + <span class="actions"> + <%= link_to_edit_route_section @route_section %> + <%= link_to_create_route_section @route_section.departure, @route_section.arrival %> + </span> +</div> diff --git a/app/views/route_sections_selectors/edit.html.erb b/app/views/route_sections_selectors/edit.html.erb new file mode 100644 index 000000000..0cd58d9c1 --- /dev/null +++ b/app/views/route_sections_selectors/edit.html.erb @@ -0,0 +1,48 @@ +<%= title_tag t('.title', journey_pattern: journey_name(@journey_pattern)) %> + +<div class = "large-map"> + <%= @map.to_html %> +</div> + +<%= semantic_form_for resource, url: referential_line_route_journey_pattern_route_sections_selector_path(@referential, @line, @route, @journey_pattern), method: :put do |form| %> + +<h3><%= t('.selection.title') %></h3> + +<div id="map-selection" style="display: none"> + <div> + </div> +</div> + +<div id="empty-map-selection"> + <%= t('.no_selection') %> +</div> + +<h3><%= t('.form.title') %></h3> + +<table class="table table-hover table-striped"> + <tbody> + <%= form.fields_for :sections do |section_form| %> + <tr> + <td><%= link_to section_form.object.departure.name, referential_stop_area_path(@referential, section_form.object.departure) %></td> + <td class="route_section"> + <% if section_form.object.candidates.present? %> + <%= section_form.input :route_section_id, as: :select, label: false, collection: section_form.object.candidates, include_blank: t('.no_selection') %> + <% else %> + <%= t('.no_candidate') %> + <% end %> + </td> + <td class="action"> + <%= link_to_edit_route_section section_form.object.route_section %> + <%= link_to_create_route_section section_form.object.departure, section_form.object.arrival %> + </td> + </tr> + <% end %> + </tbody> +</table> + +<%= form.actions do %> + <%= form.action :submit, as: :button, label: t('.submit') %> + <%= form.action :cancel, as: :link, url: referential_line_route_journey_pattern_path(@referential, @line, @route, @journey_pattern) %> +<% end %> + +<% end %> diff --git a/app/views/shared/_header.erb b/app/views/shared/_header.erb index 1e8a63fba..9d53d807f 100644 --- a/app/views/shared/_header.erb +++ b/app/views/shared/_header.erb @@ -65,6 +65,10 @@ <span class="badge pull-right"><%= @referential.time_tables.size %></span><%= Referential.human_attribute_name("time_tables") %> <% end %> </li> + <li><%= link_to referential_route_sections_path(@referential) do %> + <span class="badge pull-right"><%= @referential.route_sections.size %></span><%= Referential.human_attribute_name("route_sections") %> + <% end %> + </li> <li><%= link_to referential_timebands_path(@referential) do %> <span class="badge pull-right"><%= @referential.timebands.size %></span><%= Referential.human_attribute_name("timebands") %> <% end %> diff --git a/config/database.yml b/config/database.yml index 08d265760..81951d183 100644 --- a/config/database.yml +++ b/config/database.yml @@ -1,12 +1,12 @@ default: &default - adapter: postgresql + adapter: postgis encoding: unicode - pool: 5 port: 5432 host: localhost - schema_search_path: "public" + schema_search_path: 'public,shared_extensions' username: chouette password: chouette + postgis_schema: 'shared_extensions' development: <<: *default diff --git a/config/database.yml.travis b/config/database.yml.travis index c554142f5..dc35cfcb2 100644 --- a/config/database.yml.travis +++ b/config/database.yml.travis @@ -1,11 +1,11 @@ default: &default - adapter: postgresql + adapter: postgis encoding: unicode - pool: 5 port: 5432 host: localhost - schema_search_path: "public" + schema_search_path: 'public,shared_extensions' username: postgres + postgis_schema: 'shared_extensions' development: <<: *default diff --git a/config/initializers/apartment.rb b/config/initializers/apartment.rb index b87a9fd67..31649f3e2 100644 --- a/config/initializers/apartment.rb +++ b/config/initializers/apartment.rb @@ -26,7 +26,7 @@ Apartment.configure do |config| #config.use_sql = true # configure persistent schemas (E.g. hstore ) - # config.persistent_schemas = %w{ hstore } + config.persistent_schemas = %w{ shared_extensions } # add the Rails environment to database names? # config.prepend_environment = true diff --git a/config/initializers/route_section.rb b/config/initializers/route_section.rb new file mode 100644 index 000000000..dadea36ee --- /dev/null +++ b/config/initializers/route_section.rb @@ -0,0 +1,3 @@ +Rails.application.config.to_prepare do + Chouette::RouteSection.processor = OsrmRouteSectionProcessor.new +end diff --git a/config/locales/referentials.fr.yml b/config/locales/referentials.fr.yml index bb328a430..7a1d26956 100644 --- a/config/locales/referentials.fr.yml +++ b/config/locales/referentials.fr.yml @@ -57,6 +57,7 @@ fr: access_points: "points d'accès" time_tables: "Calendriers" connection_links: "Correspondances" + route_sections: "Sections de parcours" quays: "quais" boarding_positions: "points d'embarquement" commercial_stops: "arrêts commerciaux" diff --git a/config/locales/route_sections.en.yml b/config/locales/route_sections.en.yml new file mode 100644 index 000000000..f799432f0 --- /dev/null +++ b/config/locales/route_sections.en.yml @@ -0,0 +1,47 @@ +en: + route_sections: + new: + title: "Add a new section" + show: + title: "Show this section" + edit: + title: "Edit this section" + form: + no_processing: "Geometry processing" + standard_processor: "Standard" + no_processor: "No treatment" + submit: "Submit" + index: + title: "Sections course" + all_lines: "All lines" + actions: + show: "Show" + edit: "Edit" + destroy: "Delete" + destroy_confirm: "Are you sure you want to delete this route section?" + actions: + edit: "Edit this section" + destroy: "Delete this section" + destroy_confirm: "Are you sure you want to delete this route section?" + route_sections_selectors: + edit: + title: "Changing the course of the mission %{journey_pattern}" + route_section: + edit: "Edit this section" + new: "Add alternative" + no_candidate: "No known path" + no_selection: "No selection" + selection: + title: "Selected section" + form: + title: "Full course" + submit: "Change the route" + activerecord: + models: + route_section: "Section course" + attributes: + route_section: + departure: "Departure point" + arrival: "Arrival point" + points: "Via" + distance: "Distance" diff --git a/config/locales/route_sections.fr.yml b/config/locales/route_sections.fr.yml new file mode 100644 index 000000000..65bead733 --- /dev/null +++ b/config/locales/route_sections.fr.yml @@ -0,0 +1,47 @@ +fr: + route_sections: + new: + title: "Ajouter une section" + show: + title: "Détails d'une Section de parcours" + edit: + title: "Modifier une Section de parcours" + form: + no_processing: "Traitement de la géométrie" + standard_processor: "Standard" + no_processor: "Pas de traitement" + submit: "Valider" + index: + title: "Sections de parcours" + all_lines: "Tous les lignes" + actions: + show: "Voir" + edit: "Modifier" + destroy: "Supprimer" + destroy_confirm: "Etes vous sûr de vouloir supprimer cette section de parcours ?" + actions: + edit: "Modifier cette section" + destroy: "Supprimer cette section" + destroy_confirm: "Etes vous sûr de vouloir supprimer cette section de parcours ?" + route_sections_selectors: + edit: + title: "Modification du parcours de la mission %{journey_pattern}" + route_section: + edit: "Modifier cette section" + new: "Ajouter une alternative" + no_candidate: "Aucun parcours connu" + no_selection: "Aucune selection" + selection: + title: "Section sélectionnée" + form: + title: "Parcours complet" + submit: "Modifier le parcours" + activerecord: + models: + route_section: "Section du parcours" + attributes: + route_section: + departure: "Arrêt de départ" + arrival: "Arrêt d'arrivée" + points: "Via" + distance: "Distance" diff --git a/config/routes.rb b/config/routes.rb index 8f41615d9..5f899292a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -46,6 +46,7 @@ ChouetteIhm::Application.routes.draw do resources :api_keys resources :autocomplete_stop_areas resources :autocomplete_time_tables + resources :autocomplete_route_sections resources :autocomplete_timebands resources :group_of_lines do collection do @@ -70,6 +71,9 @@ ChouetteIhm::Application.routes.draw do member do get 'new_vehicle_journey' end + resource :route_sections_selector, path: 'sections' do + post 'selection' + end end resources :vehicle_journeys, :vehicle_journey_frequencies do get 'select_journey_pattern', :on => :member @@ -164,6 +168,11 @@ ChouetteIhm::Application.routes.draw do end resources :clean_ups + resources :route_sections do + collection do + get 'create_to_edit' + end + end end root :to => "referentials#index" diff --git a/db/migrate/20150529134410_create_route_sections.ninoxe_engine.rb b/db/migrate/20150529134410_create_route_sections.ninoxe_engine.rb new file mode 100644 index 000000000..8e288c8ab --- /dev/null +++ b/db/migrate/20150529134410_create_route_sections.ninoxe_engine.rb @@ -0,0 +1,18 @@ +class CreateRouteSections < ActiveRecord::Migration + def change + create_table :route_sections do |t| + t.belongs_to :departure, limit: 8 + t.belongs_to :arrival, limit: 8 + + t.line_string :input_geometry, srid: 4326 + t.line_string :processed_geometry, srid: 4326 + + t.string :objectid, null: false + t.integer :object_version + t.datetime :creation_time + t.string :creator_id + end + add_foreign_key :route_sections, :stop_areas, column: :departure_id, dependent: :delete + add_foreign_key :route_sections, :stop_areas, column: :arrival_id, dependent: :delete + end +end diff --git a/db/migrate/20150922103725_add_distance_to_route_sections.ninoxe_engine.rb b/db/migrate/20150922103725_add_distance_to_route_sections.ninoxe_engine.rb new file mode 100644 index 000000000..321248039 --- /dev/null +++ b/db/migrate/20150922103725_add_distance_to_route_sections.ninoxe_engine.rb @@ -0,0 +1,8 @@ +# This migration comes from ninoxe_engine (originally 20150921100000) +class AddDistanceToRouteSections < ActiveRecord::Migration + + def change + add_column "route_sections", "distance", "float" + end + +end diff --git a/db/migrate/20151111210749_add_no_processing_to_route_sections.ninoxe_engine.rb b/db/migrate/20151111210749_add_no_processing_to_route_sections.ninoxe_engine.rb new file mode 100644 index 000000000..d5665fb6a --- /dev/null +++ b/db/migrate/20151111210749_add_no_processing_to_route_sections.ninoxe_engine.rb @@ -0,0 +1,8 @@ +# This migration comes from ninoxe_engine (originally 2015110517100832) +class AddNoProcessingToRouteSections < ActiveRecord::Migration + + def change + add_column :route_sections, :no_processing, :boolean + end + +end diff --git a/db/migrate/20151203132113_create_journey_pattern_sections.ninoxe_engine.rb b/db/migrate/20151203132113_create_journey_pattern_sections.ninoxe_engine.rb new file mode 100644 index 000000000..254e64567 --- /dev/null +++ b/db/migrate/20151203132113_create_journey_pattern_sections.ninoxe_engine.rb @@ -0,0 +1,16 @@ +# This migration comes from ninoxe_engine (originally 20151203131606) +class CreateJourneyPatternSections < ActiveRecord::Migration + def change + create_table :journey_pattern_sections do |t| + t.references :journey_pattern, null: false, index: true, limit: 8 + t.references :route_section, null: false, index: true, limit: 8 + t.integer :rank, null: false + t.foreign_key :journey_patterns, dependent: :delete + t.foreign_key :route_sections, dependent: :delete + + t.timestamps + end + add_index :journey_pattern_sections, [:journey_pattern_id, :route_section_id, :rank], + unique: true, name: 'index_jps_on_journey_pattern_id_and_route_section_id_and_rank' + end +end diff --git a/db/schema.rb b/db/schema.rb index d47122199..ac3a1dd2e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,10 +11,11 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20151124145300) do +ActiveRecord::Schema.define(version: 20151203132113) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" + enable_extension "postgis" create_table "access_links", force: true do |t| t.integer "access_point_id", limit: 8 @@ -38,7 +39,7 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.string "link_orientation" end - add_index "access_links", ["objectid"], name: "access_links_objectid_key", unique: true, using: :btree + add_index "access_links", ["objectid"], :name => "access_links_objectid_key", :unique => true create_table "access_points", force: true do |t| t.string "objectid" @@ -64,7 +65,7 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.string "city_name" end - add_index "access_points", ["objectid"], name: "access_points_objectid_key", unique: true, using: :btree + add_index "access_points", ["objectid"], :name => "access_points_objectid_key", :unique => true create_table "api_keys", force: true do |t| t.integer "referential_id" @@ -92,8 +93,8 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.string "time_zone" end - add_index "companies", ["objectid"], name: "companies_objectid_key", unique: true, using: :btree - add_index "companies", ["registration_number"], name: "companies_registration_number_key", using: :btree + add_index "companies", ["objectid"], :name => "companies_objectid_key", :unique => true + add_index "companies", ["registration_number"], :name => "companies_registration_number_key" create_table "connection_links", force: true do |t| t.integer "departure_id", limit: 8 @@ -116,7 +117,7 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.integer "int_user_needs" end - add_index "connection_links", ["objectid"], name: "connection_links_objectid_key", unique: true, using: :btree + add_index "connection_links", ["objectid"], :name => "connection_links_objectid_key", :unique => true create_table "delayed_jobs", force: true do |t| t.integer "priority", default: 0 @@ -132,7 +133,20 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.datetime "updated_at" end - add_index "delayed_jobs", ["priority", "run_at"], name: "delayed_jobs_priority", using: :btree + add_index "delayed_jobs", ["priority", "run_at"], :name => "delayed_jobs_priority" + + create_table "exports", force: true do |t| + t.integer "referential_id", limit: 8 + t.string "status" + t.string "type" + t.string "options" + t.datetime "created_at" + t.datetime "updated_at" + t.string "references_type" + t.string "reference_ids" + end + + add_index "exports", ["referential_id"], :name => "index_exports_on_referential_id" create_table "facilities", force: true do |t| t.integer "stop_area_id", limit: 8 @@ -158,7 +172,7 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.string "contained_in" end - add_index "facilities", ["objectid"], name: "facilities_objectid_key", unique: true, using: :btree + add_index "facilities", ["objectid"], :name => "facilities_objectid_key", :unique => true create_table "facilities_features", id: false, force: true do |t| t.integer "facility_id", limit: 8 @@ -188,7 +202,7 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.string "registration_number" end - add_index "group_of_lines", ["objectid"], name: "group_of_lines_objectid_key", unique: true, using: :btree + add_index "group_of_lines", ["objectid"], :name => "group_of_lines_objectid_key", :unique => true create_table "group_of_lines_lines", id: false, force: true do |t| t.integer "group_of_line_id", limit: 8 @@ -206,8 +220,20 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.integer "timeband_id" end - add_index "journey_frequencies", ["timeband_id"], name: "index_journey_frequencies_on_timeband_id", using: :btree - add_index "journey_frequencies", ["vehicle_journey_id"], name: "index_journey_frequencies_on_vehicle_journey_id", using: :btree + add_index "journey_frequencies", ["timeband_id"], :name => "index_journey_frequencies_on_timeband_id" + add_index "journey_frequencies", ["vehicle_journey_id"], :name => "index_journey_frequencies_on_vehicle_journey_id" + + create_table "journey_pattern_sections", force: true do |t| + t.integer "journey_pattern_id", limit: 8, null: false + t.integer "route_section_id", limit: 8, null: false + t.integer "rank", null: false + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "journey_pattern_sections", ["journey_pattern_id", "route_section_id", "rank"], :name => "index_jps_on_journey_pattern_id_and_route_section_id_and_rank", :unique => true + add_index "journey_pattern_sections", ["journey_pattern_id"], :name => "index_journey_pattern_sections_on_journey_pattern_id" + add_index "journey_pattern_sections", ["route_section_id"], :name => "index_journey_pattern_sections_on_route_section_id" create_table "journey_patterns", force: true do |t| t.integer "route_id", limit: 8 @@ -223,14 +249,14 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.integer "arrival_stop_point_id", limit: 8 end - add_index "journey_patterns", ["objectid"], name: "journey_patterns_objectid_key", unique: true, using: :btree + add_index "journey_patterns", ["objectid"], :name => "journey_patterns_objectid_key", :unique => true create_table "journey_patterns_stop_points", id: false, force: true do |t| t.integer "journey_pattern_id", limit: 8 t.integer "stop_point_id", limit: 8 end - add_index "journey_patterns_stop_points", ["journey_pattern_id"], name: "index_journey_pattern_id_on_journey_patterns_stop_points", using: :btree + add_index "journey_patterns_stop_points", ["journey_pattern_id"], :name => "index_journey_pattern_id_on_journey_patterns_stop_points" create_table "lines", force: true do |t| t.integer "network_id", limit: 8 @@ -254,8 +280,8 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.string "stable_id" end - add_index "lines", ["objectid"], name: "lines_objectid_key", unique: true, using: :btree - add_index "lines", ["registration_number"], name: "lines_registration_number_key", using: :btree + add_index "lines", ["objectid"], :name => "lines_objectid_key", :unique => true + add_index "lines", ["registration_number"], :name => "lines_registration_number_key" create_table "networks", force: true do |t| t.string "objectid", null: false @@ -272,8 +298,8 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.string "comment" end - add_index "networks", ["objectid"], name: "networks_objectid_key", unique: true, using: :btree - add_index "networks", ["registration_number"], name: "networks_registration_number_key", using: :btree + add_index "networks", ["objectid"], :name => "networks_objectid_key", :unique => true + add_index "networks", ["registration_number"], :name => "networks_registration_number_key" create_table "organisations", force: true do |t| t.string "name" @@ -295,7 +321,7 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.decimal "link_distance", precision: 19, scale: 2 end - add_index "pt_links", ["objectid"], name: "pt_links_objectid_key", unique: true, using: :btree + add_index "pt_links", ["objectid"], :name => "pt_links_objectid_key", :unique => true create_table "referentials", force: true do |t| t.string "name" @@ -313,6 +339,19 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.string "data_format" end + create_table "route_sections", force: true do |t| + t.integer "departure_id", limit: 8 + t.integer "arrival_id", limit: 8 + t.string "objectid", null: false + t.integer "object_version" + t.datetime "creation_time" + t.string "creator_id" + t.spatial "input_geometry", limit: {:srid=>4326, :type=>"line_string"} + t.spatial "processed_geometry", limit: {:srid=>4326, :type=>"line_string"} + t.float "distance" + t.boolean "no_processing" + end + create_table "routes", force: true do |t| t.integer "line_id", limit: 8 t.string "objectid", null: false @@ -328,7 +367,7 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.string "wayback" end - add_index "routes", ["objectid"], name: "routes_objectid_key", unique: true, using: :btree + add_index "routes", ["objectid"], :name => "routes_objectid_key", :unique => true create_table "routing_constraints_lines", id: false, force: true do |t| t.integer "stop_area_id", limit: 8 @@ -370,8 +409,8 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.string "time_zone" end - add_index "stop_areas", ["objectid"], name: "stop_areas_objectid_key", unique: true, using: :btree - add_index "stop_areas", ["parent_id"], name: "index_stop_areas_on_parent_id", using: :btree + add_index "stop_areas", ["objectid"], :name => "stop_areas_objectid_key", :unique => true + add_index "stop_areas", ["parent_id"], :name => "index_stop_areas_on_parent_id" create_table "stop_areas_stop_areas", id: false, force: true do |t| t.integer "child_id", limit: 8 @@ -390,7 +429,7 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.string "for_alighting" end - add_index "stop_points", ["objectid"], name: "stop_points_objectid_key", unique: true, using: :btree + add_index "stop_points", ["objectid"], :name => "stop_points_objectid_key", :unique => true create_table "taggings", force: true do |t| t.integer "tag_id" @@ -402,15 +441,15 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.datetime "created_at" end - add_index "taggings", ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], name: "taggings_idx", unique: true, using: :btree - add_index "taggings", ["taggable_id", "taggable_type", "context"], name: "index_taggings_on_taggable_id_and_taggable_type_and_context", using: :btree + add_index "taggings", ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], :name => "taggings_idx", :unique => true + add_index "taggings", ["taggable_id", "taggable_type", "context"], :name => "index_taggings_on_taggable_id_and_taggable_type_and_context" create_table "tags", force: true do |t| t.string "name" t.integer "taggings_count", default: 0 end - add_index "tags", ["name"], name: "index_tags_on_name", unique: true, using: :btree + add_index "tags", ["name"], :name => "index_tags_on_name", :unique => true create_table "time_table_dates", force: true do |t| t.integer "time_table_id", limit: 8, null: false @@ -419,7 +458,7 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.boolean "in_out" end - add_index "time_table_dates", ["time_table_id"], name: "index_time_table_dates_on_time_table_id", using: :btree + add_index "time_table_dates", ["time_table_id"], :name => "index_time_table_dates_on_time_table_id" create_table "time_table_periods", force: true do |t| t.integer "time_table_id", limit: 8, null: false @@ -428,7 +467,7 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.integer "position", null: false end - add_index "time_table_periods", ["time_table_id"], name: "index_time_table_periods_on_time_table_id", using: :btree + add_index "time_table_periods", ["time_table_id"], :name => "index_time_table_periods_on_time_table_id" create_table "time_tables", force: true do |t| t.string "objectid", null: false @@ -442,15 +481,15 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.date "end_date" end - add_index "time_tables", ["objectid"], name: "time_tables_objectid_key", unique: true, using: :btree + add_index "time_tables", ["objectid"], :name => "time_tables_objectid_key", :unique => true create_table "time_tables_vehicle_journeys", id: false, force: true do |t| t.integer "time_table_id", limit: 8 t.integer "vehicle_journey_id", limit: 8 end - add_index "time_tables_vehicle_journeys", ["time_table_id"], name: "index_time_tables_vehicle_journeys_on_time_table_id", using: :btree - add_index "time_tables_vehicle_journeys", ["vehicle_journey_id"], name: "index_time_tables_vehicle_journeys_on_vehicle_journey_id", using: :btree + add_index "time_tables_vehicle_journeys", ["time_table_id"], :name => "index_time_tables_vehicle_journeys_on_time_table_id" + add_index "time_tables_vehicle_journeys", ["vehicle_journey_id"], :name => "index_time_tables_vehicle_journeys_on_vehicle_journey_id" create_table "timebands", force: true do |t| t.string "objectid", null: false @@ -496,9 +535,9 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.datetime "invitation_created_at" end - add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree - add_index "users", ["invitation_token"], name: "index_users_on_invitation_token", unique: true, using: :btree - add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree + add_index "users", ["email"], :name => "index_users_on_email", :unique => true + add_index "users", ["invitation_token"], :name => "index_users_on_invitation_token", :unique => true + add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true create_table "vehicle_journey_at_stops", force: true do |t| t.integer "vehicle_journey_id", limit: 8 @@ -511,8 +550,8 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.string "for_alighting" end - add_index "vehicle_journey_at_stops", ["stop_point_id"], name: "index_vehicle_journey_at_stops_on_stop_pointid", using: :btree - add_index "vehicle_journey_at_stops", ["vehicle_journey_id"], name: "index_vehicle_journey_at_stops_on_vehicle_journey_id", using: :btree + add_index "vehicle_journey_at_stops", ["stop_point_id"], :name => "index_vehicle_journey_at_stops_on_stop_pointid" + add_index "vehicle_journey_at_stops", ["vehicle_journey_id"], :name => "index_vehicle_journey_at_stops_on_vehicle_journey_id" create_table "vehicle_journeys", force: true do |t| t.integer "route_id", limit: 8 @@ -535,9 +574,10 @@ ActiveRecord::Schema.define(version: 20151124145300) do t.integer "journey_category", default: 0, null: false end - add_index "vehicle_journeys", ["objectid"], name: "vehicle_journeys_objectid_key", unique: true, using: :btree - add_index "vehicle_journeys", ["route_id"], name: "index_vehicle_journeys_on_route_id", using: :btree + add_index "vehicle_journeys", ["objectid"], :name => "vehicle_journeys_objectid_key", :unique => true + add_index "vehicle_journeys", ["route_id"], :name => "index_vehicle_journeys_on_route_id" + Foreigner.load add_foreign_key "access_links", "access_points", name: "aclk_acpt_fkey", dependent: :delete add_foreign_key "access_links", "stop_areas", name: "aclk_area_fkey", dependent: :delete @@ -549,6 +589,9 @@ ActiveRecord::Schema.define(version: 20151124145300) do add_foreign_key "group_of_lines_lines", "group_of_lines", name: "groupofline_group_fkey", dependent: :delete add_foreign_key "group_of_lines_lines", "lines", name: "groupofline_line_fkey", dependent: :delete + add_foreign_key "journey_pattern_sections", "journey_patterns", name: "journey_pattern_sections_journey_pattern_id_fk", dependent: :delete + add_foreign_key "journey_pattern_sections", "route_sections", name: "journey_pattern_sections_route_section_id_fk", dependent: :delete + add_foreign_key "journey_patterns", "routes", name: "jp_route_fkey", dependent: :delete add_foreign_key "journey_patterns", "stop_points", name: "arrival_point_fkey", column: "arrival_stop_point_id", dependent: :nullify add_foreign_key "journey_patterns", "stop_points", name: "departure_point_fkey", column: "departure_stop_point_id", dependent: :nullify @@ -559,6 +602,9 @@ ActiveRecord::Schema.define(version: 20151124145300) do add_foreign_key "lines", "companies", name: "line_company_fkey", dependent: :nullify add_foreign_key "lines", "networks", name: "line_ptnetwork_fkey", dependent: :nullify + add_foreign_key "route_sections", "stop_areas", name: "route_sections_arrival_id_fk", column: "arrival_id", dependent: :delete + add_foreign_key "route_sections", "stop_areas", name: "route_sections_departure_id_fk", column: "departure_id", dependent: :delete + add_foreign_key "routes", "lines", name: "route_line_fkey", dependent: :delete add_foreign_key "routes", "routes", name: "route_opposite_route_fkey", column: "opposite_route_id", dependent: :nullify diff --git a/lib/osrm_route_section_processor.rb b/lib/osrm_route_section_processor.rb new file mode 100644 index 000000000..102c53966 --- /dev/null +++ b/lib/osrm_route_section_processor.rb @@ -0,0 +1,36 @@ +require 'open-uri' + +class OsrmRouteSectionProcessor + + def call(route_section) + points_string = (route_section.input_geometry || route_section.default_geometry).points.map do |point| + "loc=#{point.y.to_f},#{point.x.to_f}" + end.join + + Rails.logger.info "Invoke router.project-osrm.org for RouteSection StopArea:#{route_section.departure.id} -> StopArea:#{route_section.arrival.id}" + + response = open "http://router.project-osrm.org/viaroute?#{points_string}instructions=false" + geometry = JSON.parse(response.read.to_s)['route_geometry'] + + if geometry + decoded_geometry = Polylines::Decoder.decode_polyline(geometry, 1e6).map do |point| + GeoRuby::SimpleFeatures::Point.from_x_y(point[1], point[0], 4326) + end + + GeoRuby::SimpleFeatures::LineString.from_points(decoded_geometry).try(:to_rgeo) if decoded_geometry.many? + end + rescue OpenURI::HTTPError => e + Rails.logger.error "router.project-osrm.org failed: #{e}" + nil + end + + def self.create_all + Chouette::JourneyPattern.find_each do |journey_pattern| + selector = RouteSectionsSelector.new(journey_pattern) + selector.sections.each do |section| + section.create_candidate unless section.candidates.present? + end + end + end + +end diff --git a/lib/tasks/route_sections.rake b/lib/tasks/route_sections.rake new file mode 100644 index 000000000..d48ddbba4 --- /dev/null +++ b/lib/tasks/route_sections.rake @@ -0,0 +1,17 @@ +namespace :route_sections do + + def find_referential(id_or_slug) + if id_or_slug.to_s =~ /\A\d+\Z/ + Referential.find id_or_slug.to_i + else + Referential.find_by slug: id_or_slug + end + end + + desc "Generate all RouteSections for a given Referential" + task :create_all, [:referential] => [:environment] do |t, args| + find_referential(args[:referential]).switch + OsrmRouteSectionProcessor.create_all + end + +end diff --git a/spec/controllers/routes_controller_spec.rb b/spec/controllers/routes_controller_spec.rb index a813056c3..de6d16c8b 100644 --- a/spec/controllers/routes_controller_spec.rb +++ b/spec/controllers/routes_controller_spec.rb @@ -37,7 +37,7 @@ describe RoutesController, :type => :controller do it_behaves_like "line and referential linked" it_behaves_like "redirected to referential_line_path(referential,line)" end - + describe "POST /create" do before(:each) do post :create, :line_id => route.line_id, @@ -48,7 +48,7 @@ describe RoutesController, :type => :controller do it_behaves_like "line and referential linked" it_behaves_like "redirected to referential_line_path(referential,line)" end - + describe "PUT /update" do before(:each) do put :update, :id => route.id, :line_id => route.line_id, @@ -59,10 +59,10 @@ describe RoutesController, :type => :controller do it_behaves_like "route, line and referential linked" it_behaves_like "redirected to referential_line_path(referential,line)" end - + describe "GET /show" do before(:each) do - get :show, :id => route.id, + get :show, :id => route.id, :line_id => route.line_id, :referential_id => referential.id end @@ -78,6 +78,6 @@ describe RoutesController, :type => :controller do # expect(assigns[:stop_points]).to eq(route.stop_points.paginate(:page => nil)) #end end - + end diff --git a/spec/models/route_sections_selector_spec.rb b/spec/models/route_sections_selector_spec.rb new file mode 100644 index 000000000..a00945d42 --- /dev/null +++ b/spec/models/route_sections_selector_spec.rb @@ -0,0 +1,43 @@ +require 'spec_helper' + +describe RouteSectionsSelector, :type => :model do + + let(:stop_points) { create_list :stop_point, 5 } + let(:itinerary) { double stop_points: stop_points, route_sections: [] } + + subject { RouteSectionsSelector.new itinerary } + + describe "#sections" do + + it "should create a Section between each StopPoint" do + expect(subject.sections.size).to eq(stop_points.size - 1) + end + + end + +end + +describe RouteSectionsSelector::Section, :type => :model do + + let(:departure) { create :stop_point } + let(:arrival) { create :stop_point } + + subject { RouteSectionsSelector::Section.new departure, arrival } + + let(:route_sections) do + create_list :route_section, 5, + departure: departure.stop_area, + arrival: arrival.stop_area + end + + describe "#candidates" do + it "should return an empty array when no RouteSection exists" do + expect(subject.candidates).to be_empty + end + + it "should return the RouteSections with the same departure/arrival StopAreas" do + expect(subject.candidates).to match_array(route_sections) + end + end + +end diff --git a/spec/support/fake_iev_server.rb b/spec/support/fake_iev_server.rb index c311fdc91..8cd002fae 100644 --- a/spec/support/fake_iev_server.rb +++ b/spec/support/fake_iev_server.rb @@ -10,17 +10,11 @@ end # Importer ############ # get list -fixture_request :get, - "http://#{Rails.application.secrets.api_endpoint}referentials/test/scheduled_jobs?action=importer", - 'scheduled_jobs.json' +fixture_request :get, "#{Rails.application.secrets.api_endpoint}referentials/test/scheduled_jobs?action=importer", 'scheduled_jobs.json' # get element -fixture_request :get, - "http://#{Rails.application.secrets.api_endpoint}referentials/test/scheduled_jobs/1?action=importer", - 'scheduled_job.json' +fixture_request :get, "#{Rails.application.secrets.api_endpoint}referentials/test/scheduled_jobs/1?action=importer", 'scheduled_job.json' # post element -fixture_request :post, - "http://#{Rails.application.secrets.api_endpoint}referentials/test/scheduled_jobs/", - 'scheduled_job.json' +fixture_request :post, "#{Rails.application.secrets.api_endpoint}referentials/test/scheduled_jobs/", 'scheduled_job.json' # Optionnels # delete element @@ -36,6 +30,3 @@ fixture_request :post, ############ # Validation ############ - - - diff --git a/spec/support/referential.rb b/spec/support/referential.rb index d77a05f41..8c468eb53 100644 --- a/spec/support/referential.rb +++ b/spec/support/referential.rb @@ -12,7 +12,7 @@ module ReferentialHelper end module ClassMethods - + def assign_referential before(:each) do assign :referential, referential @@ -34,7 +34,7 @@ RSpec.configure do |config| config.before(:suite) do # Clean all tables to start - DatabaseCleaner.clean_with :truncation + DatabaseCleaner.clean_with :truncation, except: %w[spatial_ref_sys] # Truncating doesn't drop schemas, ensure we're clean here, first *may not* exist Apartment::Tenant.drop('first') rescue nil # Create the default tenant for our tests @@ -49,7 +49,7 @@ RSpec.configure do |config| end config.before(:each, :js => true) do - DatabaseCleaner.strategy = :truncation + DatabaseCleaner.strategy = :truncation, { except: %w[spatial_ref_sys] } end config.before(:each) do @@ -61,6 +61,6 @@ RSpec.configure do |config| Apartment::Tenant.reset # Rollback transaction DatabaseCleaner.clean - end + end end |
