diff --git a/app/assets/stylesheets/layout.scss b/app/assets/stylesheets/layout.scss index d19ccd525..00502081d 100644 --- a/app/assets/stylesheets/layout.scss +++ b/app/assets/stylesheets/layout.scss @@ -819,6 +819,7 @@ footer { .categories a, .geozone a, .sidebar-links a, +.sidebar-map a, .tags span { background: #ececec; border-radius: rem-calc(6); diff --git a/app/controllers/admin/budget_headings_controller.rb b/app/controllers/admin/budget_headings_controller.rb index 902f256b5..538e9a76a 100644 --- a/app/controllers/admin/budget_headings_controller.rb +++ b/app/controllers/admin/budget_headings_controller.rb @@ -33,7 +33,7 @@ class Admin::BudgetHeadingsController < Admin::BaseController private def budget_heading_params - params.require(:budget_heading).permit(:name, :price, :population) + params.require(:budget_heading).permit(:name, :price, :population, :latitude, :longitude) end end diff --git a/app/controllers/budgets/investments_controller.rb b/app/controllers/budgets/investments_controller.rb index ca2bf7dc4..4a9e327d7 100644 --- a/app/controllers/budgets/investments_controller.rb +++ b/app/controllers/budgets/investments_controller.rb @@ -1,5 +1,7 @@ module Budgets class InvestmentsController < ApplicationController + OSM_DISTRICT_LEVEL_ZOOM = 12 + include FeatureFlags include CommentableActions include FlagActions @@ -32,13 +34,17 @@ module Budgets respond_to :html, :js def index - if @budget.finished? - @investments = investments.winners.page(params[:page]).per(10).for_render - else - @investments = investments.page(params[:page]).per(10).for_render - end + all_investments = if @budget.finished? + investments.winners + else + investments + end + + @investments = all_investments.page(params[:page]).per(10).for_render @investment_ids = @investments.pluck(:id) + @investments_map_coordinates = MapLocation.where(investment_id: all_investments).map { |l| l.json_data } + load_investment_votes(@investments) @tag_cloud = tag_cloud end @@ -142,6 +148,7 @@ module Budgets if params[:heading_id].present? @heading = @budget.headings.find(params[:heading_id]) @assigned_heading = @ballot.try(:heading_for_group, @heading.try(:group)) + load_map end end @@ -167,6 +174,13 @@ module Budgets end end + def load_map + @map_location = MapLocation.new + @map_location.zoom = OSM_DISTRICT_LEVEL_ZOOM + @map_location.latitude = @heading.latitude.to_f + @map_location.longitude = @heading.longitude.to_f + end + end end diff --git a/app/models/budget/heading.rb b/app/models/budget/heading.rb index 4818eaeed..2d68ebe51 100644 --- a/app/models/budget/heading.rb +++ b/app/models/budget/heading.rb @@ -11,6 +11,10 @@ class Budget validates :price, presence: true validates :slug, presence: true, format: /\A[a-z0-9\-_]+\z/ validates :population, numericality: { greater_than: 0 }, allow_nil: true + validates :latitude, length: { maximum: 22, minimum: 1 }, presence: true, \ + format: /\A(-|\+)?([1-8]?\d(?:\.\d{1,})?|90(?:\.0{1,6})?)\z/ + validates :longitude, length: { maximum: 22, minimum: 1}, presence: true, \ + format: /\A(-|\+)?((?:1[0-7]|[1-9])?\d(?:\.\d{1,})?|180(?:\.0{1,})?)\z/ delegate :budget, :budget_id, to: :group, allow_nil: true diff --git a/app/views/admin/budgets/_heading_form.html.erb b/app/views/admin/budgets/_heading_form.html.erb index 5c50e21a8..019485cdf 100644 --- a/app/views/admin/budgets/_heading_form.html.erb +++ b/app/views/admin/budgets/_heading_form.html.erb @@ -1,28 +1,25 @@ <%= form_for [:admin, budget, group, heading], remote: true do |f| %> <%= render 'shared/errors', resource: heading %> - <%= f.text_field :name, - label: false, + label: t("admin.budgets.form.heading"), maxlength: 50, placeholder: t("admin.budgets.form.heading") %>
- <%= f.text_field :price, - label: false, + label: t("admin.budgets.form.amount"), maxlength: 8, placeholder: t("admin.budgets.form.amount") %>
-

<%= t("admin.budgets.form.population_help_text") %>

<%= f.text_field :population, - label: false, + label: t("admin.budgets.form.population"), maxlength: 8, placeholder: t("admin.budgets.form.population"), data: {toggle_focus: "population-info"}, @@ -34,6 +31,22 @@
+
+
+ <%= f.text_field :latitude, + label: t("admin.budgets.form.latitude"), + maxlength: 22, + placeholder: "latitude" %> +
+
+
+
+ <%= f.text_field :longitude, + label: t("admin.budgets.form.longitude"), + maxlength: 22, + placeholder: "longitude" %> +
+
<%= f.submit t("admin.budgets.form.save_heading"), class: "button success" %> <% end %> diff --git a/app/views/budgets/index.html.erb b/app/views/budgets/index.html.erb index bc236377f..9b0dd66f9 100644 --- a/app/views/budgets/index.html.erb +++ b/app/views/budgets/index.html.erb @@ -88,7 +88,7 @@ <% unless current_budget.informing? %> -
+

<%= t("budgets.index.map") %>

<%= render_map(nil, "budgets", false, nil, @budgets_coordinates) %>
diff --git a/app/views/budgets/investments/_map.html.erb b/app/views/budgets/investments/_map.html.erb new file mode 100644 index 000000000..af04ef639 --- /dev/null +++ b/app/views/budgets/investments/_map.html.erb @@ -0,0 +1,8 @@ + +
+ + diff --git a/app/views/budgets/investments/_sidebar.html.erb b/app/views/budgets/investments/_sidebar.html.erb index c020c8bbe..f78f3f1fa 100644 --- a/app/views/budgets/investments/_sidebar.html.erb +++ b/app/views/budgets/investments/_sidebar.html.erb @@ -21,6 +21,7 @@

<% end %> +<%= render 'budgets/investments/map' %> <%= render "shared/tag_cloud", taggable: 'budget/investment' %> <%= render 'budgets/investments/categories' %> diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index e1281fb32..66c9e6451 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -131,6 +131,8 @@ en: population_info: "Budget Heading population field is used for Statistic purposes at the end of the Budget to show for each Heading that represents an area with population what percentage voted. The field is optional so you can leave it empty if it doesn't apply." max_votable_headings: "Maximum number of headings in which a user can vote" current_of_max_headings: "%{current} of %{max}" + latitude: Latitude + longitude: Longitude winners: calculate: Calculate Winner Investments calculated: Winners being calculated, it may take a minute. diff --git a/config/routes/budget.rb b/config/routes/budget.rb index 475d5496a..0159b946a 100644 --- a/config/routes/budget.rb +++ b/config/routes/budget.rb @@ -25,3 +25,4 @@ scope '/participatory_budget' do end get 'investments/:id/json_data', action: :json_data, controller: 'budgets/investments' +get '/budgets/:budget_id/investments/:id/json_data', action: :json_data, controller: 'budgets/investments' diff --git a/db/dev_seeds/budgets.rb b/db/dev_seeds/budgets.rb index 6a44b977c..0c35dcf9b 100644 --- a/db/dev_seeds/budgets.rb +++ b/db/dev_seeds/budgets.rb @@ -40,21 +40,31 @@ section "Creating Budgets" do city_group = budget.groups.create!(name: I18n.t('seeds.budgets.groups.all_city')) city_group.headings.create!(name: I18n.t('seeds.budgets.groups.all_city'), price: 1000000, - population: 1000000) + population: 1000000, + latitude: '-40.123241', + longitude: '25.123249') districts_group = budget.groups.create!(name: I18n.t('seeds.budgets.groups.districts')) districts_group.headings.create!(name: I18n.t('seeds.geozones.north_district'), price: rand(5..10) * 100000, - population: 350000) + population: 350000, + latitude: '15.234521', + longitude: '-15.234234') districts_group.headings.create!(name: I18n.t('seeds.geozones.west_district'), price: rand(5..10) * 100000, - population: 300000) + population: 300000, + latitude: '14.125125', + longitude: '65.123124') districts_group.headings.create!(name: I18n.t('seeds.geozones.east_district'), price: rand(5..10) * 100000, - population: 200000) + population: 200000, + latitude: '23.234234', + longitude: '-47.134124') districts_group.headings.create!(name: I18n.t('seeds.geozones.central_district'), price: rand(5..10) * 100000, - population: 150000) + population: 150000, + latitude: '-26.133213', + longitude: '-10.123231') end end diff --git a/db/migrate/20181109111037_add_location_to_headings.rb b/db/migrate/20181109111037_add_location_to_headings.rb new file mode 100644 index 000000000..973cdf38e --- /dev/null +++ b/db/migrate/20181109111037_add_location_to_headings.rb @@ -0,0 +1,6 @@ +class AddLocationToHeadings < ActiveRecord::Migration + def change + add_column :budget_headings, :latitude, :text + add_column :budget_headings, :longitude, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index ea0b1bbbd..4a3185efd 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20180924071722) do +ActiveRecord::Schema.define(version: 20181109111037) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -156,6 +156,8 @@ ActiveRecord::Schema.define(version: 20180924071722) do t.integer "price", limit: 8 t.integer "population" t.string "slug" + t.text "latitude" + t.text "longitude" end add_index "budget_headings", ["group_id"], name: "index_budget_headings_on_group_id", using: :btree @@ -580,7 +582,7 @@ ActiveRecord::Schema.define(version: 20180924071722) do t.string "locale", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.text "title" + t.string "title" t.text "changelog" t.text "body" t.text "body_html" @@ -1163,17 +1165,17 @@ ActiveRecord::Schema.define(version: 20180924071722) do add_index "site_customization_images", ["name"], name: "index_site_customization_images_on_name", unique: true, using: :btree create_table "site_customization_page_translations", force: :cascade do |t| - t.integer "site_customization_page_id", null: false - t.string "locale", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.string "title" - t.string "subtitle" - t.text "content" - end + t.integer "site_customization_page_id", null: false + t.string "locale", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "title" + t.string "subtitle" + t.text "content" + end - add_index "site_customization_page_translations", ["locale"], name: "index_site_customization_page_translations_on_locale", using: :btree - add_index "site_customization_page_translations", ["site_customization_page_id"], name: "index_7fa0f9505738cb31a31f11fb2f4c4531fed7178b", using: :btree + add_index "site_customization_page_translations", ["locale"], name: "index_site_customization_page_translations_on_locale", using: :btree + add_index "site_customization_page_translations", ["site_customization_page_id"], name: "index_7fa0f9505738cb31a31f11fb2f4c4531fed7178b", using: :btree create_table "site_customization_pages", force: :cascade do |t| t.string "slug", null: false @@ -1418,6 +1420,12 @@ ActiveRecord::Schema.define(version: 20180924071722) do add_index "votes", ["votable_id", "votable_type", "vote_scope"], name: "index_votes_on_votable_id_and_votable_type_and_vote_scope", using: :btree add_index "votes", ["voter_id", "voter_type", "vote_scope"], name: "index_votes_on_voter_id_and_voter_type_and_vote_scope", using: :btree + create_table "web_sections", force: :cascade do |t| + t.text "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "widget_card_translations", force: :cascade do |t| t.integer "widget_card_id", null: false t.string "locale", null: false @@ -1450,12 +1458,6 @@ ActiveRecord::Schema.define(version: 20180924071722) do t.datetime "updated_at", null: false end - create_table "web_sections", force: :cascade do |t| - t.text "name" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - end - add_foreign_key "administrators", "users" add_foreign_key "annotations", "legacy_legislations" add_foreign_key "annotations", "users" diff --git a/lib/migrate_spending_proposals_to_investments.rb b/lib/migrate_spending_proposals_to_investments.rb index 908be8cc5..1f3fe1f39 100644 --- a/lib/migrate_spending_proposals_to_investments.rb +++ b/lib/migrate_spending_proposals_to_investments.rb @@ -8,10 +8,10 @@ class MigrateSpendingProposalsToInvestments if sp.geozone_id.present? group = budget.groups.find_or_create_by!(name: "Barrios") - heading = group.headings.find_or_create_by!(name: sp.geozone.name, price: 10000000) + heading = group.headings.find_or_create_by!(name: sp.geozone.name, price: 10000000, latitude: '40.416775', longitude: '-3.703790') else group = budget.groups.find_or_create_by!(name: "Toda la ciudad") - heading = group.headings.find_or_create_by!(name: "Toda la ciudad", price: 10000000) + heading = group.headings.find_or_create_by!(name: "Toda la ciudad", price: 10000000, latitude: '40.416775', longitude: '-3.703790') end feasibility = case sp.feasible diff --git a/spec/factories/budgets.rb b/spec/factories/budgets.rb index d713302fd..1b633077f 100644 --- a/spec/factories/budgets.rb +++ b/spec/factories/budgets.rb @@ -78,6 +78,8 @@ FactoryBot.define do sequence(:name) { |n| "Heading #{n}" } price 1000000 population 1234 + latitude '-25.172741' + longitude '40.127241' trait :drafting_budget do association :group, factory: [:budget_group, :drafting_budget] diff --git a/spec/features/admin/budgets_spec.rb b/spec/features/admin/budgets_spec.rb index dbad0494d..3ab17c18f 100644 --- a/spec/features/admin/budgets_spec.rb +++ b/spec/features/admin/budgets_spec.rb @@ -276,6 +276,8 @@ feature 'Admin budgets' do fill_in 'budget_heading_name', with: 'District 9 reconstruction' fill_in 'budget_heading_price', with: '6785' fill_in 'budget_heading_population', with: '100500' + fill_in 'budget_heading_latitude', with: '40.416775' + fill_in 'budget_heading_longitude', with: '-3.703790' click_button 'Save heading' end diff --git a/spec/features/budgets/investments_spec.rb b/spec/features/budgets/investments_spec.rb index 5a9798133..8ba4a6888 100644 --- a/spec/features/budgets/investments_spec.rb +++ b/spec/features/budgets/investments_spec.rb @@ -1436,10 +1436,10 @@ feature 'Budget Investments' do user = create(:user, :level_two) global_group = create(:budget_group, budget: budget, name: 'Global Group') - global_heading = create(:budget_heading, group: global_group, name: 'Global Heading') + global_heading = create(:budget_heading, group: global_group, name: 'Global Heading', latitude: -43.145412, longitude: 12.009423) carabanchel_heading = create(:budget_heading, group: group, name: "Carabanchel") - new_york_heading = create(:budget_heading, group: group, name: "New York") + new_york_heading = create(:budget_heading, group: group, name: "New York", latitude: -43.223412, longitude: 12.009423) sp1 = create(:budget_investment, :selected, price: 1, heading: global_heading) sp2 = create(:budget_investment, :selected, price: 10, heading: global_heading) @@ -1682,4 +1682,84 @@ feature 'Budget Investments' do expect(Flag.flagged?(user, investment)).not_to be end + context 'sidebar map' do + scenario "Display 6 investment's markers on sidebar map", :js do + investment1 = create(:budget_investment, heading: heading) + investment2 = create(:budget_investment, heading: heading) + investment3 = create(:budget_investment, heading: heading) + investment4 = create(:budget_investment, heading: heading) + investment5 = create(:budget_investment, heading: heading) + investment6 = create(:budget_investment, heading: heading) + + create(:map_location, longitude: 40.1231, latitude: -3.636, investment: investment1) + create(:map_location, longitude: 40.1232, latitude: -3.635, investment: investment2) + create(:map_location, longitude: 40.1233, latitude: -3.634, investment: investment3) + create(:map_location, longitude: 40.1234, latitude: -3.633, investment: investment4) + create(:map_location, longitude: 40.1235, latitude: -3.632, investment: investment5) + create(:map_location, longitude: 40.1236, latitude: -3.631, investment: investment6) + + visit budget_investments_path(budget, heading_id: heading.id) + + within ".map_location" do + expect(page).to have_css(".map-icon", count: 6, visible: false) + end + end + + scenario "Display 2 investment's markers on sidebar map", :js do + investment1 = create(:budget_investment, heading: heading) + investment2 = create(:budget_investment, heading: heading) + + create(:map_location, longitude: 40.1281, latitude: -3.656, investment: investment1) + create(:map_location, longitude: 40.1292, latitude: -3.665, investment: investment2) + + visit budget_investments_path(budget, heading_id: heading.id) + + within ".map_location" do + expect(page).to have_css(".map-icon", count: 2, visible: false) + end + end + + scenario "Display only investment's related to the current heading", :js do + heading_2 = create(:budget_heading, name: "Madrid", group: group) + + investment1 = create(:budget_investment, heading: heading) + investment2 = create(:budget_investment, heading: heading) + investment3 = create(:budget_investment, heading: heading) + investment4 = create(:budget_investment, heading: heading) + investment5 = create(:budget_investment, heading: heading_2) + investment6 = create(:budget_investment, heading: heading_2) + + create(:map_location, longitude: 40.1231, latitude: -3.636, investment: investment1) + create(:map_location, longitude: 40.1232, latitude: -3.685, investment: investment2) + create(:map_location, longitude: 40.1233, latitude: -3.664, investment: investment3) + create(:map_location, longitude: 40.1234, latitude: -3.673, investment: investment4) + create(:map_location, longitude: 40.1235, latitude: -3.672, investment: investment5) + create(:map_location, longitude: 40.1236, latitude: -3.621, investment: investment6) + + visit budget_investments_path(budget, heading_id: heading.id) + + within ".map_location" do + expect(page).to have_css(".map-icon", count: 4, visible: false) + end + end + + scenario "Do not display investment's, since they're all related to other heading", :js do + heading_2 = create(:budget_heading, name: "Madrid", group: group) + + investment1 = create(:budget_investment, heading: heading_2) + investment2 = create(:budget_investment, heading: heading_2) + investment3 = create(:budget_investment, heading: heading_2) + + create(:map_location, longitude: 40.1255, latitude: -3.644, investment: investment1) + create(:map_location, longitude: 40.1258, latitude: -3.637, investment: investment2) + create(:map_location, longitude: 40.1251, latitude: -3.649, investment: investment3) + + visit budget_investments_path(budget, heading_id: heading.id) + + within ".map_location" do + expect(page).to have_css(".map-icon", count: 0, visible: false) + end + end + end + end diff --git a/spec/features/tags/budget_investments_spec.rb b/spec/features/tags/budget_investments_spec.rb index 8719275ef..855ad934f 100644 --- a/spec/features/tags/budget_investments_spec.rb +++ b/spec/features/tags/budget_investments_spec.rb @@ -5,7 +5,7 @@ feature 'Tags' do let(:author) { create(:user, :level_two, username: 'Isabel') } let(:budget) { create(:budget, name: "Big Budget") } let(:group) { create(:budget_group, name: "Health", budget: budget) } - let!(:heading) { create(:budget_heading, name: "More hospitals", group: group) } + let!(:heading) { create(:budget_heading, name: "More hospitals", group: group, latitude: '40.416775', longitude: '-3.703790') } let!(:tag_medio_ambiente) { create(:tag, :category, name: 'Medio Ambiente') } let!(:tag_economia) { create(:tag, :category, name: 'Economía') } let(:admin) { create(:administrator).user } diff --git a/spec/models/budget/heading_spec.rb b/spec/models/budget/heading_spec.rb index b2a09cb55..edd96a8b8 100644 --- a/spec/models/budget/heading_spec.rb +++ b/spec/models/budget/heading_spec.rb @@ -44,6 +44,216 @@ describe Budget::Heading do end end + describe "save latitude" do + it "Doesn't allow latitude == nil" do + expect(build(:budget_heading, group: group, name: 'Latitude is nil', population: 12412512, latitude: nil, longitude: '12.123412')).not_to be_valid + end + + it "Doesn't allow latitude == ''" do + expect(build(:budget_heading, group: group, name: 'Latitude is an empty string', population: 12412512, latitude: '', longitude: '12.123412')).not_to be_valid + end + + it "Doesn't allow latitude < -90" do + heading = create(:budget_heading, group: group, name: 'Latitude is < -90') + + heading.latitude = '-90.127491' + expect(heading).not_to be_valid + + heading.latitude = '-91.723491' + expect(heading).not_to be_valid + + heading.latitude = '-108.127412' + expect(heading).not_to be_valid + + heading.latitude = '-1100.888491' + expect(heading).not_to be_valid + end + + it "Doesn't allow latitude > 90" do + heading = create(:budget_heading, group: group, name: 'Latitude is > 90') + + heading.latitude = '90.127491' + expect(heading).not_to be_valid + + heading.latitude = '97.723491' + expect(heading).not_to be_valid + + heading.latitude = '119.127412' + expect(heading).not_to be_valid + + heading.latitude = '1200.888491' + expect(heading).not_to be_valid + + heading.latitude = '+128.888491' + expect(heading).not_to be_valid + + heading.latitude = '+255.888491' + expect(heading).not_to be_valid + end + + it "Doesn't allow latitude length > 22" do + heading = create(:budget_heading, group: group, name: 'Latitude length is > 22') + + heading.latitude = '10.12749112312418238128213' + expect(heading).not_to be_valid + + heading.latitude = '7.7234941211121231231241' + expect(heading).not_to be_valid + + heading.latitude = '9.1274124111241248688995' + expect(heading).not_to be_valid + + heading.latitude = '+12.8884911231238684445311' + expect(heading).not_to be_valid + end + + it "Allows latitude inside [-90,90] interval" do + heading = create(:budget_heading, group: group, name: 'Latitude is inside [-90,90] interval') + + heading.latitude = '90' + expect(heading).to be_valid + + heading.latitude = '-90' + expect(heading).to be_valid + + heading.latitude = '-90.000' + expect(heading).to be_valid + + heading.latitude = '-90.00000' + expect(heading).to be_valid + + heading.latitude = '90.000' + expect(heading).to be_valid + + heading.latitude = '90.00000' + expect(heading).to be_valid + + heading.latitude = '-80.123451' + expect(heading).to be_valid + + heading.latitude = '+65.888491' + expect(heading).to be_valid + + heading.latitude = '80.144812' + expect(heading).to be_valid + + heading.latitude = '17.417412' + expect(heading).to be_valid + + heading.latitude = '-21.000054' + expect(heading).to be_valid + + heading.latitude = '+80.888491' + expect(heading).to be_valid + end + end + + + describe "save longitude" do + it "Doesn't allow longitude == nil" do + expect(build(:budget_heading, group: group, name: 'Longitude is nil', population: 12412512, latitude: '12.123412', longitude: nil)).not_to be_valid + end + + it "Doesn't allow longitude == ''" do + expect(build(:budget_heading, group: group, name: 'Longitude is an empty string', population: 12412512, latitude: '12.127412', longitude: '')).not_to be_valid + end + + it "Doesn't allow longitude < -180" do + heading = create(:budget_heading, group: group, name: 'Longitude is < -180') + + heading.longitude = '-180.127491' + expect(heading).not_to be_valid + + heading.longitude = '-181.723491' + expect(heading).not_to be_valid + + heading.longitude = '-188.127412' + expect(heading).not_to be_valid + + heading.longitude = '-1100.888491' + expect(heading).not_to be_valid + end + + it "Doesn't allow longitude > 180" do + heading = create(:budget_heading, group: group, name: 'Longitude is > 180') + + heading.longitude = '190.127491' + expect(heading).not_to be_valid + + heading.longitude = '197.723491' + expect(heading).not_to be_valid + + heading.longitude = '+207.723491' + expect(heading).not_to be_valid + + heading.longitude = '300.723491' + expect(heading).not_to be_valid + + heading.longitude = '189.127412' + expect(heading).not_to be_valid + + heading.longitude = '1200.888491' + expect(heading).not_to be_valid + end + + it "Doesn't allow longitude length > 23" do + heading = create(:budget_heading, group: group, name: 'Longitude length is > 23') + + heading.longitude = '50.1274911123124112312418238128213' + expect(heading).not_to be_valid + + heading.longitude = '53.73412349178811231241' + expect(heading).not_to be_valid + + heading.longitude = '+20.1274124124124123121435' + expect(heading).not_to be_valid + + heading.longitude = '10.88849112312312311232123311' + expect(heading).not_to be_valid + end + + it "Allows longitude inside [-180,180] interval" do + heading = create(:budget_heading, group: group, name: 'Longitude is inside [-180,180] interval') + + heading.longitude = '180' + expect(heading).to be_valid + + heading.longitude = '-180' + expect(heading).to be_valid + + heading.longitude = '-180.000' + expect(heading).to be_valid + + heading.longitude = '-180.00000' + expect(heading).to be_valid + + heading.longitude = '180.000' + expect(heading).to be_valid + + heading.longitude = '180.00000' + expect(heading).to be_valid + + heading.longitude = '+75.00000' + expect(heading).to be_valid + + heading.longitude = '+15.023321' + expect(heading).to be_valid + + heading.longitude = '-80.123451' + expect(heading).to be_valid + + heading.longitude = '80.144812' + expect(heading).to be_valid + + heading.longitude = '17.417412' + expect(heading).to be_valid + + heading.longitude = '-21.000054' + expect(heading).to be_valid + end + end + + describe "heading" do it "can be deleted if no budget's investments associated" do heading1 = create(:budget_heading, group: group, name: 'name')