diff --git a/.bummr-build.sh b/.bummr-build.sh new file mode 100755 index 000000000..19f8f7b14 --- /dev/null +++ b/.bummr-build.sh @@ -0,0 +1,2 @@ +#!/bin/sh +bundle exec rspec --fail-fast diff --git a/.codeclimate.yml b/.codeclimate.yml new file mode 100644 index 000000000..548da5110 --- /dev/null +++ b/.codeclimate.yml @@ -0,0 +1,36 @@ +engines: + brakeman: + enabled: true + bundler-audit: + enabled: true + csslint: + enabled: true + duplication: + enabled: true + config: + languages: + - ruby + # mass_threshold: 30 + - javascript + exclude_paths: + - 'spec/**/*' + - 'db/migrate/*' + - 'db/schema.rb' + eslint: + enabled: true + fixme: + enabled: true + reek: + enabled: true + exclude_paths: + - 'db/migrate/*' + rubocop: + enabled: true + scss-lint: + enabled: true + +ratings: + paths: + - app/** + - lib/** + - '**.rb' diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..7a77ac718 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +Dockerfile +tmp +log +*.md +.git* diff --git a/.reek b/.reek new file mode 100644 index 000000000..824a6a5ee --- /dev/null +++ b/.reek @@ -0,0 +1,13 @@ +IrresponsibleModule: + enabled: false +'spec': + DataClump: + enabled: false + LongParameterList: + enabled: false + TooManyStatements: + enabled: false + UtilityFunction: + enabled: false +exclude_paths: + - db/migrate diff --git a/.rubocop.yml b/.rubocop.yml index 5fe713a78..3896a0b44 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,60 +1,96 @@ +# This configuration only includes the cops that differ from the Rubocop +# defaults, which can be found here: +# https://github.com/bbatsov/rubocop/blob/master/config/default.yml +# https://github.com/bbatsov/rubocop/blob/master/config/enabled.yml +# https://github.com/bbatsov/rubocop/blob/master/config/disabled.yml + AllCops: Include: - - 'Gemfile' - - 'Rakefile' + - '**/Gemfile' + - '**/Rakefile' - 'lib/tasks/*' Exclude: - - 'bin/**/*' - 'db/schema.rb' - - 'db/seeds.rb' + - 'bin/**/*' + - 'config/initializers/devise.rb' - 'db/migrate/*' - - 'config/initializers/generators.rb' + TargetRubyVersion: 2.3 + UseCache: true + +Metrics/AbcSize: + Description: A calculated magnitude based on number of assignments, branches, and + conditions. + Enabled: true + Max: 15 + Exclude: + - spec/**/* + +Metrics/BlockLength: + CountComments: false # count full line comments? + Enabled: true + Max: 25 + Exclude: + - 'Rakefile' + - '**/*.rake' + - 'config/environments/production.rb' + - 'config/environments/test.rb' + - 'config/routes.rb' + - 'lib/location_presenter.rb' + - 'lib/location_importer.rb' + - 'spec/**/*.rb' Metrics/ClassLength: Description: Avoid classes longer than 100 lines of code. Enabled: true CountComments: false Max: 100 + Exclude: + - spec/**/* Metrics/LineLength: Description: Limit lines to 80 characters. StyleGuide: https://github.com/bbatsov/ruby-style-guide#80-character-limits - Enabled: false + Enabled: true Max: 100 AllowURI: true URISchemes: - http - https + Exclude: + - config/initializers/secret_token.rb + - app/validators/url_validator.rb Metrics/MethodLength: Description: Avoid methods longer than 10 lines of code. StyleGuide: https://github.com/bbatsov/ruby-style-guide#short-methods Enabled: true CountComments: false - Max: 15 + Max: 10 + Exclude: + - 'db/migrate/*' + - app/controllers/api/v1/root_controller.rb + - spec/**/* Metrics/ModuleLength: - Description: Avoid modules longer than 100 lines of code. - Enabled: true CountComments: false Max: 100 + Description: Avoid modules longer than 100 lines of code. + Enabled: true Exclude: - - spec/support/features/form_helpers.rb + - spec/**/* Rails/HasAndBelongsToMany: - Description: Prefer has_many :through to has_and_belongs_to_many. - Enabled: true - Exclude: - - app/models/service.rb - - app/models/category.rb + Description: 'Prefer has_many :through to has_and_belongs_to_many.' + StyleGuide: 'https://github.com/bbatsov/rails-style-guide#has-many-through' + Enabled: false -Rails/ScopeArgs: - Description: Checks the arguments of ActiveRecord scopes. - Enabled: true - Exclude: - - app/models/concerns/search.rb +# This is a Rails 5 feature, so it should be disabled until we upgrade +Rails/HttpPositionalArguments: + Description: 'Use keyword arguments instead of positional arguments in http method calls.' + Enabled: false Include: - - app/models/**/*.rb + - 'spec/**/*' + - 'test/**/*' Rails/TimeZone: # The value `strict` means that `Time` should be used with `zone`. @@ -65,10 +101,35 @@ Rails/TimeZone: - strict - flexible +Style/AlignParameters: + # Alignment of parameters in multi-line method calls. + # + # The `with_first_parameter` style aligns the following lines along the same + # column as the first parameter. + # + # method_call(a, + # b) + # + # The `with_fixed_indentation` style aligns the following lines with one + # level of indentation relative to the start of the line with the method call. + # + # method_call(a, + # b) + Description: >- + Align the parameters of a method call if they span more + than one line. + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-double-indent' + EnforcedStyle: with_first_parameter + SupportedStyles: + - with_first_parameter + - with_fixed_indentation + # By default, the indentation width from Style/IndentationWidth is used + # But it can be overridden by setting this parameter + IndentationWidth: ~ + Style/AndOr: Description: Use &&/|| instead of and/or. StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-and-or-or - Enabled: true EnforcedStyle: conditionals SupportedStyles: - always @@ -77,31 +138,118 @@ Style/AndOr: Style/Documentation: Description: Document classes and non-namespace modules. Enabled: false + Exclude: + - 'spec/**/*' + - 'test/**/*' Style/DotPosition: Description: Checks the position of the dot in multi-line method calls. StyleGuide: https://github.com/bbatsov/ruby-style-guide#consistent-multi-line-chains - Enabled: true EnforcedStyle: trailing SupportedStyles: - leading - trailing +# Warn on empty else statements +# empty - warn only on empty else +# nil - warn on else with nil in it +# both - warn on empty else and else with nil in it +Style/EmptyElse: + EnforcedStyle: both + SupportedStyles: + - empty + - nil + - both + Style/ExtraSpacing: - Description: Do not use unnecessary spacing. + # When true, allows most uses of extra spacing if the intent is to align + # things with the previous or next line, not counting empty lines or comment + # lines. + AllowForAlignment: true + # When true, forces the alignment of = in assignments on consecutive lines. + ForceEqualSignAlignment: false + +Style/FrozenStringLiteralComment: + Description: >- + Add the frozen_string_literal comment to the top of files + to help transition from Ruby 2.3.0 to Ruby 3.0. Enabled: false +# `MinBodyLength` defines the number of lines of the a body of an if / unless +# needs to have to trigger this cop Style/GuardClause: - Description: Check for conditionals that can be replaced with guard clauses - StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-nested-conditionals + MinBodyLength: 2 + +Style/IfUnlessModifier: + Description: Favor modifier if/unless usage when you have a single-line body. + StyleGuide: https://github.com/bbatsov/ruby-style-guide#if-as-a-modifier Enabled: true - MinBodyLength: 3 + MaxLineLength: 80 + +# Checks the indentation of the first element in an array literal. +Style/IndentArray: + # The value `special_inside_parentheses` means that array literals with + # brackets that have their opening bracket on the same line as a surrounding + # opening round parenthesis, shall have their first element indented relative + # to the first position inside the parenthesis. + # + # The value `consistent` means that the indentation of the first element shall + # always be relative to the first position of the line where the opening + # bracket is. + # + # The value `align_brackets` means that the indentation of the first element + # shall always be relative to the position of the opening bracket. + EnforcedStyle: special_inside_parentheses + SupportedStyles: + - special_inside_parentheses + - consistent + - align_brackets + # By default, the indentation width from Style/IndentationWidth is used + # But it can be overridden by setting this parameter + IndentationWidth: ~ + +Style/MultilineOperationIndentation: + EnforcedStyle: aligned + SupportedStyles: + - aligned + - indented + # By default, the indentation width from Style/IndentationWidth is used + # But it can be overridden by setting this parameter + IndentationWidth: ~ + +Style/NumericLiteralPrefix: + EnforcedOctalStyle: zero_only + SupportedOctalStyles: + - zero_with_o + - zero_only Style/StringLiterals: Description: Checks if uses of quotes match the configured preference. StyleGuide: https://github.com/bbatsov/ruby-style-guide#consistent-string-literals - Enabled: true EnforcedStyle: single_quotes SupportedStyles: - single_quotes - double_quotes + ConsistentQuotesInMultiline: true + +Style/TrailingCommaInArguments: + # If `comma`, the cop requires a comma after the last argument, but only for + # parenthesized method calls where each argument is on its own line. + # If `consistent_comma`, the cop requires a comma after the last argument, + # for all parenthesized method calls with arguments. + EnforcedStyleForMultiline: no_comma + SupportedStyles: + - comma + - consistent_comma + - no_comma + +Style/TrailingCommaInLiteral: + # If `comma`, the cop requires a comma after the last item in an array or + # hash, but only when each item is on its own line. + # If `consistent_comma`, the cop requires a comma after the last item of all + # non-empty array and hash literals. + EnforcedStyleForMultiline: no_comma + SupportedStyles: + - comma + - consistent_comma + - no_comma diff --git a/.ruby-version b/.ruby-version index 585940699..0bee604df 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.2.3 +2.3.3 diff --git a/.scss-lint.yml b/.scss-lint.yml new file mode 100644 index 000000000..918ab4be3 --- /dev/null +++ b/.scss-lint.yml @@ -0,0 +1,8 @@ +linters: + Comment: + exclude: + - 'app/assets/stylesheets/application.css.scss' + - 'app/assets/stylesheets/admin/application.css.scss' + PlaceholderInExtend: + exclude: + - 'app/assets/stylesheets/framework_and_overrides.css.scss' diff --git a/.travis.yml b/.travis.yml index a5cd434e8..e9791259c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,9 +2,11 @@ bundler_args: --without assets:development:production language: ruby cache: bundler rvm: - - 2.2.3 + - 2.3.3 addons: postgresql: "9.3" +before_install: + - gem update --system before_script: - psql -c 'create database ohana_api_test;' -U postgres - psql -U postgres -q -d ohana_api_test -f db/structure.sql diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..2dcbbe64d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,25 @@ +# Use the rails image because it properly sets up Node.js and Postgres +FROM rails:4.2.6 + +# PhantomJS is required for running tests +ENV PHANTOMJS_SHA256 86dd9a4bf4aee45f1a84c9f61cf1947c1d6dce9b9e8d2a907105da7852460d2f + +RUN mkdir /usr/local/phantomjs \ + && curl -o phantomjs.tar.bz2 -L https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2 \ + && echo "$PHANTOMJS_SHA256 *phantomjs.tar.bz2" | sha256sum -c - \ + && tar -xjf phantomjs.tar.bz2 -C /usr/local/phantomjs --strip-components=1 \ + && rm phantomjs.tar.bz2 + +RUN ln -s ../phantomjs/bin/phantomjs /usr/local/bin/ + +WORKDIR /ohana-api + +COPY Gemfile /ohana-api +COPY Gemfile.lock /ohana-api + +RUN bundle install --jobs 20 --retry 5 + +COPY . /ohana-api + +EXPOSE 8080 +CMD ["rails", "server", "-b", "0.0.0.0", "-p", "8080"] diff --git a/Gemfile b/Gemfile index 0ed6b57de..3693dfb53 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -ruby '2.2.3' +ruby '2.3.3' gem 'rails', '~> 4.2' gem 'pg' @@ -34,7 +34,7 @@ gem 'kaminari' gem 'active_model_serializers', '~> 0.8.0' # Authentication -gem 'devise', '~> 3.4' +gem 'devise', '~> 4.1' # Authorization gem 'pundit' @@ -80,6 +80,7 @@ group :test do gem 'coveralls', require: false gem 'rubocop' gem 'haml_lint' + gem 'test_after_commit' gem 'webmock' end @@ -96,4 +97,8 @@ group :development do gem 'derailed' gem 'rack-mini-profiler' gem 'flamegraph' + gem 'stackprof' + + gem 'bummr' + gem 'reek' end diff --git a/Gemfile.lock b/Gemfile.lock index c9dab9e68..c0750be34 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,94 +1,88 @@ GEM remote: https://rubygems.org/ specs: - actionmailer (4.2.5.1) - actionpack (= 4.2.5.1) - actionview (= 4.2.5.1) - activejob (= 4.2.5.1) + actionmailer (4.2.7.1) + actionpack (= 4.2.7.1) + actionview (= 4.2.7.1) + activejob (= 4.2.7.1) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 1.0, >= 1.0.5) - actionpack (4.2.5.1) - actionview (= 4.2.5.1) - activesupport (= 4.2.5.1) + actionpack (4.2.7.1) + actionview (= 4.2.7.1) + activesupport (= 4.2.7.1) rack (~> 1.6) rack-test (~> 0.6.2) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (4.2.5.1) - activesupport (= 4.2.5.1) + actionview (4.2.7.1) + activesupport (= 4.2.7.1) builder (~> 3.1) erubis (~> 2.7.0) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) active_model_serializers (0.8.3) activemodel (>= 3.0) - activejob (4.2.5.1) - activesupport (= 4.2.5.1) + activejob (4.2.7.1) + activesupport (= 4.2.7.1) globalid (>= 0.3.0) - activemodel (4.2.5.1) - activesupport (= 4.2.5.1) + activemodel (4.2.7.1) + activesupport (= 4.2.7.1) builder (~> 3.1) - activerecord (4.2.5.1) - activemodel (= 4.2.5.1) - activesupport (= 4.2.5.1) + activerecord (4.2.7.1) + activemodel (= 4.2.7.1) + activesupport (= 4.2.7.1) arel (~> 6.0) - activesupport (4.2.5.1) + activesupport (4.2.7.1) i18n (~> 0.7) json (~> 1.7, >= 1.7.7) minitest (~> 5.1) thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) - addressable (2.4.0) - ancestry (2.1.0) + addressable (2.5.0) + public_suffix (~> 2.0, >= 2.0.2) + ancestry (2.2.2) activerecord (>= 3.0.0) arel (6.0.3) - ast (2.2.0) - auto_strip_attributes (2.0.6) + ast (2.3.0) + auto_strip_attributes (2.1.0) activerecord (>= 3.0) - autoprefixer-rails (6.2.1) + autoprefixer-rails (6.4.0.1) execjs - json - bcrypt (3.1.10) - benchmark-ips (2.3.0) + axiom-types (0.1.1) + descendants_tracker (~> 0.0.4) + ice_nine (~> 0.11.0) + thread_safe (~> 0.3, >= 0.3.1) + bcrypt (3.1.11) + benchmark-ips (2.5.0) better_errors (2.1.1) coderay (>= 1.0.0) erubis (>= 2.6.6) rack (>= 0.9.0) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) - bootstrap-sass (3.3.6) + bootstrap-sass (3.3.7) autoprefixer-rails (>= 5.2.1) sass (>= 3.3.4) - builder (3.2.2) - bullet (5.0.0) + builder (3.2.3) + bullet (5.5.0) activesupport (>= 3.0.0) - uniform_notifier (~> 1.9.0) - capybara (2.6.0) + uniform_notifier (~> 1.10.0) + bummr (0.1.6) + rainbow + thor + capybara (2.12.0) addressable mime-types (>= 1.16) nokogiri (>= 1.3.3) rack (>= 1.0.0) rack-test (>= 0.5.4) xpath (~> 2.0) - celluloid (0.17.2) - celluloid-essentials - celluloid-extras - celluloid-fsm - celluloid-pool - celluloid-supervision - timers (>= 4.1.1) - celluloid-essentials (0.20.5) - timers (>= 4.1.1) - celluloid-extras (0.20.5) - timers (>= 4.1.1) - celluloid-fsm (0.20.5) - timers (>= 4.1.1) - celluloid-pool (0.20.5) - timers (>= 4.1.1) - celluloid-supervision (0.20.5) - timers (>= 4.1.1) cliver (0.3.2) - coderay (1.1.0) + codeclimate-engine-rb (0.4.0) + virtus (~> 1.0) + coderay (1.1.1) + coercible (1.0.0) + descendants_tracker (~> 0.0.1) coffee-rails (4.1.1) coffee-script (>= 2.2.0) railties (>= 4.0.0, < 5.1.x) @@ -96,20 +90,19 @@ GEM coffee-script-source execjs coffee-script-source (1.10.0) - concurrent-ruby (1.0.0) - coveralls (0.8.10) - json (~> 1.8) - rest-client (>= 1.6.8, < 2) - simplecov (~> 0.11.0) + concurrent-ruby (1.0.2) + coveralls (0.8.19) + json (>= 1.8, < 3) + simplecov (~> 0.12.0) term-ansicolor (~> 1.3) thor (~> 0.19.1) - tins (~> 1.6.0) + tins (~> 1.6) crack (0.4.3) safe_yaml (~> 1.0.0) - csv_shaper (1.2.0) + csv_shaper (1.3.0) activesupport (>= 3.0.0) - dalli (2.7.5) - database_cleaner (1.5.1) + dalli (2.7.6) + database_cleaner (1.5.3) debug_inspector (0.0.2) derailed (0.1.0) derailed_benchmarks @@ -121,39 +114,35 @@ GEM rack (>= 1) rake (~> 10) thor (~> 0.19) - devise (3.5.5) + descendants_tracker (0.0.4) + thread_safe (~> 0.3, >= 0.3.1) + devise (4.2.0) bcrypt (~> 3.0) orm_adapter (~> 0.1) - railties (>= 3.2.6, < 5) + railties (>= 4.1.0, < 5.1) responders - thread_safe (~> 0.1) warden (~> 1.2.3) diff-lcs (1.2.5) docile (1.1.5) - domain_name (0.5.25) - unf (>= 0.0.5, < 1.0.0) - enumerize (1.1.0) + enumerize (2.0.1) activesupport (>= 3.2) + equalizer (0.0.11) erubis (2.7.0) - execjs (2.6.0) - factory_girl (4.5.0) + execjs (2.7.0) + factory_girl (4.8.0) activesupport (>= 3.0.0) - factory_girl_rails (4.5.0) - factory_girl (~> 4.5.0) + factory_girl_rails (4.8.0) + factory_girl (~> 4.8.0) railties (>= 3.0.0) - fast_stack (0.1.0) - rake - rake-compiler - ffi (1.9.10) + ffi (1.9.14) figaro (1.1.1) thor (~> 0.14) - flamegraph (0.1.0) - fast_stack - friendly_id (5.1.0) + flamegraph (0.9.5) + friendly_id (5.2.0) activerecord (>= 4.0.0) - geocoder (1.2.14) + geocoder (1.4.3) get_process_mem (0.2.0) - globalid (0.3.6) + globalid (0.3.7) activesupport (>= 4.1.0) haml (4.0.7) tilt @@ -163,206 +152,209 @@ GEM haml (>= 4.0.6, < 5.0) html2haml (>= 1.0.1) railties (>= 4.0.1) - haml_lint (0.16.0) + haml_lint (0.20.0) haml (~> 4.0) - rake (~> 10.0) - rubocop (>= 0.36.0) + rake (>= 10, < 13) + rubocop (>= 0.47.0) sysexits (~> 1.1) - hashdiff (0.2.3) + hashdiff (0.3.2) heapy (0.1.2) - hitimes (1.2.3) html2haml (2.0.0) erubis (~> 2.7.0) haml (~> 4.0.0) nokogiri (~> 1.6.0) ruby_parser (~> 3.5) - http-cookie (1.0.2) - domain_name (~> 0.5) - i18n (0.7.0) - jquery-rails (4.1.0) - rails-dom-testing (~> 1.0) + i18n (0.8.0) + ice_nine (0.11.2) + jquery-rails (4.2.2) + rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) - json (1.8.3) - kaminari (0.16.3) + json (1.8.6) + kaminari (0.17.0) actionpack (>= 3.0.0) activesupport (>= 3.0.0) - kgio (2.10.0) + kgio (2.11.0) launchy (2.4.3) addressable (~> 2.3) letter_opener (1.4.1) launchy (~> 2.2) - listen (3.0.5) - rb-fsevent (>= 0.9.3) - rb-inotify (>= 0.9) + listen (3.1.5) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + ruby_dep (~> 1.2) loofah (2.0.3) nokogiri (>= 1.5.9) - mail (2.6.3) - mime-types (>= 1.16, < 3) + mail (2.6.4) + mime-types (>= 1.16, < 4) memcachier (0.0.2) memory_profiler (0.9.6) - mime-types (2.99) - mini_portile2 (2.0.0) - minitest (5.8.4) - multi_json (1.11.2) - netrc (0.11.0) - nokogiri (1.6.7.2) - mini_portile2 (~> 2.0.0.rc2) + mime-types (3.1) + mime-types-data (~> 3.2015) + mime-types-data (3.2016.0521) + mini_portile2 (2.1.0) + minitest (5.10.1) + nokogiri (1.6.8.1) + mini_portile2 (~> 2.1.0) orm_adapter (0.5.0) - parser (2.3.0.2) + parser (2.3.3.1) ast (~> 2.2) - pg (0.18.4) - poltergeist (1.8.1) + pg (0.19.0) + poltergeist (1.13.0) capybara (~> 2.1) cliver (~> 0.3.1) - multi_json (~> 1.0) websocket-driver (>= 0.2.0) powerpack (0.1.1) protected_attributes (1.1.3) activemodel (>= 4.0.1, < 5.0) - puma (2.15.3) + public_suffix (2.0.5) + puma (3.7.0) pundit (1.1.0) activesupport (>= 3.0.0) quiet_assets (1.1.0) railties (>= 3.1, < 5.0) - rack (1.6.4) - rack-cache (1.5.1) + rack (1.6.5) + rack-cache (1.7.0) rack (>= 0.4) - rack-cors (0.4.0) - rack-mini-profiler (0.9.8) - rack (>= 1.1.3) + rack-cors (0.4.1) + rack-mini-profiler (0.10.2) + rack (>= 1.2.0) rack-test (0.6.3) rack (>= 1.0) - rails (4.2.5.1) - actionmailer (= 4.2.5.1) - actionpack (= 4.2.5.1) - actionview (= 4.2.5.1) - activejob (= 4.2.5.1) - activemodel (= 4.2.5.1) - activerecord (= 4.2.5.1) - activesupport (= 4.2.5.1) + rails (4.2.7.1) + actionmailer (= 4.2.7.1) + actionpack (= 4.2.7.1) + actionview (= 4.2.7.1) + activejob (= 4.2.7.1) + activemodel (= 4.2.7.1) + activerecord (= 4.2.7.1) + activesupport (= 4.2.7.1) bundler (>= 1.3.0, < 2.0) - railties (= 4.2.5.1) + railties (= 4.2.7.1) sprockets-rails rails-deprecated_sanitizer (1.0.3) activesupport (>= 4.2.0.alpha) - rails-dom-testing (1.0.7) + rails-dom-testing (1.0.8) activesupport (>= 4.2.0.beta, < 5.0) - nokogiri (~> 1.6.0) + nokogiri (~> 1.6) rails-deprecated_sanitizer (>= 1.0.1) rails-html-sanitizer (1.0.3) loofah (~> 2.0) rails_12factor (0.0.3) rails_serve_static_assets rails_stdout_logging - rails_serve_static_assets (0.0.4) + rails_serve_static_assets (0.0.5) rails_stdout_logging (0.0.4) - railties (4.2.5.1) - actionpack (= 4.2.5.1) - activesupport (= 4.2.5.1) + railties (4.2.7.1) + actionpack (= 4.2.7.1) + activesupport (= 4.2.7.1) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) - rainbow (2.1.0) + rainbow (2.2.1) rake (10.5.0) - rake-compiler (0.9.5) - rake rb-fsevent (0.9.7) - rb-inotify (0.9.5) + rb-inotify (0.9.7) ffi (>= 0.5.0) - responders (2.1.1) + reek (4.5.5) + codeclimate-engine-rb (~> 0.4.0) + parser (~> 2.3.1, >= 2.3.1.2) + rainbow (~> 2.0) + responders (2.2.0) railties (>= 4.2.0, < 5.1) - rest-client (1.8.0) - http-cookie (>= 1.0.2, < 2.0) - mime-types (>= 1.16, < 3.0) - netrc (~> 0.7) - rspec-core (3.4.1) - rspec-support (~> 3.4.0) - rspec-expectations (3.4.0) + rspec-core (3.5.4) + rspec-support (~> 3.5.0) + rspec-expectations (3.5.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.4.0) + rspec-support (~> 3.5.0) rspec-its (1.2.0) rspec-core (>= 3.0.0) rspec-expectations (>= 3.0.0) - rspec-mocks (3.4.1) + rspec-mocks (3.5.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.4.0) - rspec-rails (3.4.0) - actionpack (>= 3.0, < 4.3) - activesupport (>= 3.0, < 4.3) - railties (>= 3.0, < 4.3) - rspec-core (~> 3.4.0) - rspec-expectations (~> 3.4.0) - rspec-mocks (~> 3.4.0) - rspec-support (~> 3.4.0) - rspec-support (3.4.1) - rubocop (0.36.0) - parser (>= 2.3.0.0, < 3.0) + rspec-support (~> 3.5.0) + rspec-rails (3.5.2) + actionpack (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-core (~> 3.5.0) + rspec-expectations (~> 3.5.0) + rspec-mocks (~> 3.5.0) + rspec-support (~> 3.5.0) + rspec-support (3.5.0) + rubocop (0.47.1) + parser (>= 2.3.3.1, < 3.0) powerpack (~> 0.1) rainbow (>= 1.99.1, < 3.0) ruby-progressbar (~> 1.7) - ruby-progressbar (1.7.5) - ruby_parser (3.7.2) + unicode-display_width (~> 1.0, >= 1.0.1) + ruby-progressbar (1.8.1) + ruby_dep (1.5.0) + ruby_parser (3.8.1) sexp_processor (~> 4.1) - rubyzip (1.1.7) + rubyzip (1.2.1) safe_yaml (1.0.4) - sass (3.4.20) - sass-rails (5.0.4) - railties (>= 4.0.0, < 5.0) + sass (3.4.22) + sass-rails (5.0.6) + railties (>= 4.0.0, < 6) sass (~> 3.1) sprockets (>= 2.8, < 4.0) sprockets-rails (>= 2.0, < 4.0) tilt (>= 1.1, < 3) - select2-rails (3.5.9.3) + select2-rails (3.5.10) thor (~> 0.14) - sexp_processor (4.6.0) - shoulda-matchers (3.1.0) + sexp_processor (4.7.0) + shoulda-matchers (3.1.1) activesupport (>= 4.0.0) - simplecov (0.11.1) + simplecov (0.12.0) docile (~> 1.1.0) - json (~> 1.8) + json (>= 1.8, < 3) simplecov-html (~> 0.10.0) simplecov-html (0.10.0) - smarter_csv (1.1.0) - spring (1.6.2) + smarter_csv (1.1.4) + spring (2.0.1) + activesupport (>= 4.2) spring-commands-rspec (1.0.4) spring (>= 0.9.1) - spring-watcher-listen (2.0.0) + spring-watcher-listen (2.0.1) listen (>= 2.7, < 4.0) - spring (~> 1.2) - sprockets (3.5.2) + spring (>= 1.2, < 3.0) + sprockets (3.7.0) concurrent-ruby (~> 1.0) rack (> 1, < 3) - sprockets-rails (3.0.0) + sprockets-rails (3.1.1) actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) - sucker_punch (1.6.0) - celluloid (~> 0.17.2) + stackprof (0.2.10) + sucker_punch (2.0.2) + concurrent-ruby (~> 1.0.0) sysexits (1.2.0) - term-ansicolor (1.3.2) + term-ansicolor (1.4.0) tins (~> 1.0) - thor (0.19.1) + test_after_commit (1.1.0) + activerecord (>= 3.2) + thor (0.19.4) thread_safe (0.3.5) - tilt (2.0.2) - timers (4.1.1) - hitimes - tins (1.6.0) + tilt (2.0.6) + tins (1.13.2) tzinfo (1.2.2) thread_safe (~> 0.1) - uglifier (2.7.2) - execjs (>= 0.3.0) - json (>= 1.8.0) - unf (0.1.4) - unf_ext - unf_ext (0.0.7.1) - uniform_notifier (1.9.0) - warden (1.2.4) + uglifier (3.0.4) + execjs (>= 0.3.0, < 3) + unicode-display_width (1.1.3) + uniform_notifier (1.10.0) + virtus (1.0.5) + axiom-types (~> 0.1) + coercible (~> 1.0) + descendants_tracker (~> 0.0, >= 0.0.3) + equalizer (~> 0.0, >= 0.0.9) + warden (1.2.6) rack (>= 1.0) - webmock (1.22.6) + webmock (2.3.2) addressable (>= 2.3.6) crack (>= 0.3.2) hashdiff - websocket-driver (0.6.3) + websocket-driver (0.6.5) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.2) xpath (2.0.0) @@ -379,6 +371,7 @@ DEPENDENCIES binding_of_caller (>= 0.7.1) bootstrap-sass (~> 3.3.0) bullet + bummr capybara coffee-rails (~> 4.1.0) coveralls @@ -386,7 +379,7 @@ DEPENDENCIES dalli database_cleaner (>= 1.0.0.RC1) derailed - devise (~> 3.4) + devise (~> 4.1) enumerize factory_girl_rails (>= 4.2.0) figaro (~> 1.0) @@ -411,6 +404,7 @@ DEPENDENCIES rack-mini-profiler rails (~> 4.2) rails_12factor + reek rspec-its rspec-rails (~> 3.1) rubocop @@ -422,9 +416,14 @@ DEPENDENCIES spring spring-commands-rspec spring-watcher-listen + stackprof sucker_punch + test_after_commit uglifier (>= 1.3.0) webmock +RUBY VERSION + ruby 2.3.3p222 + BUNDLED WITH - 1.10.6 + 1.14.3 diff --git a/INSTALL.md b/INSTALL.md index 2fd9b4be1..13e332036 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,30 +1,70 @@ - # Running Ohana API on your computer +# Running Ohana API on your computer -## Install Prerequisites +## Fork and clone -Before you can run Ohana API, you'll need to have the following software -packages installed on your computer: Git, Ruby 2.1+, RVM (or rbenv), and Postgres. -If you're on a Linux machine, you'll also need Node.js and libpq-dev. +[Fork this repository to your GitHub account][fork]. -If you already have all of the prerequisites installed, you can go straight -to the [Ohana Installation](#install-ohana-api). Otherwise, there are three ways -you can install the tools: +Clone it on your computer and navigate to the project's directory: -1. If you're on a Mac, the easiest way to install all the tools is to use -@monfresh's [laptop] script. + git clone https://github.com//ohana-api.git && cd ohana-api + +[fork]: http://help.github.com/fork-a-repo/ + +## Docker Setup (recommended, especially for Windows users) + +1. Download, install, and launch [Docker] -2. Use our Vagrant [virtual machine][dev-box], which has everything set up for -you. This is the recommended method for Windows users. +1. Set up the Docker image: -[dev-box]: https://github.com/codeforamerica/ohana-api-dev-box + $ script/bootstrap -3. Install everything manually: [Build tools][build-tools], [Ruby with RVM][ruby], -[Postgres][postgres], and [Node.js][node] (Linux only). +1. Start the app: + + $ docker-compose up + +Once the docker images are up and running, the app will be accessible at +[http://localhost:8080](http://localhost:8080). + +### Verify the app is returning JSON + +[http://localhost:8080/api/locations](http://localhost:8080/api/locations) + +[http://localhost:8080/api/search?keyword=food](http://localhost:8080/api/search?keyword=food) + +We recommend the [JSONView][jsonview] Google Chrome extension for formatting +the JSON response so it is easier to read in the browser. + +[jsonview]: https://chrome.google.com/webstore/detail/jsonview/chklaanhfefbnpoihckbnefhakgolnmc + +### More useful Docker commands + +* Stop this running container: `docker-compose stop` +* Stop and delete the containers: `docker-compose down` +* Open a shell in the web container: `docker-compose run --rm web bash` + +[Docker]: https://docs.docker.com/engine/installation/ + +## Local Setup + +Before you can run Ohana API, you'll need to have the following software +packages installed on your computer: Git, PhantomJS, Postgres, Ruby 2.3+, +and RVM (or rbenv). +If you're on a Linux machine, you'll also need Node.js and `libpq-dev`. + +If you don't already have all the prerequisites installed, there are two ways +you can install them: + +- If you're on a Mac, the easiest way to install all the tools is to use +@monfresh's [laptop] script. + +- Install everything manually: [Build tools], [Ruby with RVM], [PhantomJS], +[Postgres], and [Node.js][node] (Linux only). [laptop]: https://github.com/monfresh/laptop -[build-tools]: https://github.com/codeforamerica/howto/blob/master/Build-Tools.md -[ruby]: https://github.com/codeforamerica/howto/blob/master/Ruby.md -[postgres]: https://github.com/codeforamerica/howto/blob/master/PostgreSQL.md +[Build tools]: https://github.com/codeforamerica/howto/blob/master/Build-Tools.md +[Ruby with RVM]: https://github.com/codeforamerica/howto/blob/master/Ruby.md +[PhantomJS]: https://github.com/jonleighton/poltergeist#installing-phantomjs +[Postgres]: https://github.com/codeforamerica/howto/blob/master/PostgreSQL.md [node]: https://github.com/codeforamerica/howto/blob/master/Node.js.md ### PostgreSQL Accounts @@ -36,25 +76,30 @@ On Linux, PostgreSQL authentication can be [set to _Trust_](http://www.postgresq On a Mac with Postgres.app or a Homebrew Postgres installation, this setup is provided by default. -## Install Ohana API +### Install the dependencies and populate the database with sample data: -### Fork and clone + bin/setup -[Fork this repository to your GitHub account][fork]. +_Note: Installation and preparation can take several minutes to complete!_ -Clone it on your computer and navigate to the project's directory: +### Run the app - git clone https://github.com//ohana-api.git && cd ohana-api +Start the app locally on port 8080: -[fork]: http://help.github.com/fork-a-repo/ + puma -p 8080 -### Install the dependencies and populate the database with sample data: +### Verify the app is returning JSON - bin/setup +[http://localhost:8080/api/locations](http://localhost:8080/api/locations) -_Note: Installation and preparation can take several minutes to complete!_ +[http://localhost:8080/api/search?keyword=food](http://localhost:8080/api/search?keyword=food) + +We recommend the [JSONView][jsonview] Google Chrome extension for formatting +the JSON response so it is easier to read in the browser. + +[jsonview]: https://chrome.google.com/webstore/detail/jsonview/chklaanhfefbnpoihckbnefhakgolnmc -### Set up the environment variables & customizable settings +## Set up the environment variables & customizable settings #### Configure environment variables Inside the `config` folder, you will find a file named `application.yml`. @@ -72,24 +117,7 @@ You can also translate the text by copying and pasting the contents of `en.yml` into a new locale for your language. Find out how in the [Rails Internationalization Guide](http://guides.rubyonrails.org/i18n.html). -### Run the app - -Start the app locally on port 8080: - - puma -p 8080 - -### Verify the app is returning JSON - -[http://localhost:8080/api/locations](http://localhost:8080/api/locations) - -[http://localhost:8080/api/search?keyword=food](http://localhost:8080/api/search?keyword=food) - -We recommend the [JSONView][jsonview] Google Chrome extension for formatting -the JSON response so it is easier to read in the browser. - -[jsonview]: https://chrome.google.com/webstore/detail/jsonview/chklaanhfefbnpoihckbnefhakgolnmc - -### Uploading and validating your own data +## Uploading and validating your own data - [Prepare your data][prepare] in a format compatible with Ohana API. diff --git a/README.md b/README.md index ce7b25e05..f5d78a359 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Ohana API is a Ruby on Rails application that makes it easy for communities to publish and maintain a database of social services, and allows developers to build impactful applications that serve underprivileged residents. -This is the API + Admin Interface portion of the [Ohana API](http://ohanapi.org) project, developed by [@monfresh](https://github.com/monfresh), [@spara](https://github.com/spara), and [@anselmbradford](https://github.com/anselmbradford) during their Code for America Fellowship in 2013, in partnership with San Mateo County's Human Services Agency. +This is the API + Admin Interface portion of the Ohana project, developed by [@monfresh](https://github.com/monfresh), [@spara](https://github.com/spara), and [@anselmbradford](https://github.com/anselmbradford) during their Code for America Fellowship in 2013, in partnership with San Mateo County's Human Services Agency. Apps built on top of Ohana API include a [web-based search interface](https://github.com/codeforamerica/ohana-web-search) and an [SMS app] that allow anyone to easily find services that are available in a particular community. @@ -13,8 +13,8 @@ Apps built on top of Ohana API include a [web-based search interface](https://gi ## Stack Overview -* Ruby version 2.2.3 -* Rails version 4.2.5 +* Ruby version 2.3.3 +* Rails version 4.2.7.1 * Postgres * Testing Frameworks: RSpec, Factory Girl, Capybara diff --git a/app/assets/javascripts/admin/form.js.coffee b/app/assets/javascripts/admin/form.js.coffee index 1ba354d92..ad7b00720 100644 --- a/app/assets/javascripts/admin/form.js.coffee +++ b/app/assets/javascripts/admin/form.js.coffee @@ -1,21 +1,21 @@ jQuery -> - $('.edit_entry').on 'click', '.delete_association', (event) -> + $('.edit-entry').on 'click', '.delete_association', (event) -> $(this).prevAll('input[type=hidden]').val('1') $(this).closest('fieldset').hide() event.preventDefault() - $('.edit_entry').on 'click', '.delete_attribute', (event) -> + $('.edit-entry').on 'click', '.delete_attribute', (event) -> $(this).closest('fieldset').find('input').val('') $(this).closest('fieldset').hide() event.preventDefault() - $('.edit_entry').on 'click', '.add_fields', (event) -> + $('.edit-entry').on 'click', '.add-fields', (event) -> time = new Date().getTime() regexp = new RegExp($(this).data('id'), 'g') $(this).before($(this).data('fields').replace(regexp, time)) event.preventDefault() - $('.edit_entry').on 'click', '.add_array_fields', (event) -> + $('.edit-entry').on 'click', '.add-array-fields', (event) -> time = new Date().getTime() $(this).before($(this).data('fields')) inputs = $(this).parent().find('input') diff --git a/app/assets/stylesheets/_variables.scss b/app/assets/stylesheets/_variables.scss new file mode 100644 index 000000000..4dd5dc099 --- /dev/null +++ b/app/assets/stylesheets/_variables.scss @@ -0,0 +1,13 @@ +$light-blue: #c8d4e8; +$lighter-blue: #cbe0f3; + +$black: #000; +$white: #fff; + +$red: #b5121b; +$light-red: #df3e3e; +$lighter-red: #de9292; + +$gray: #fcfcfc; + +$light-green: #c8e8ca; diff --git a/app/assets/stylesheets/admin/application.css.scss b/app/assets/stylesheets/admin/application.css.scss index 3d2ca66f5..920be54a5 100644 --- a/app/assets/stylesheets/admin/application.css.scss +++ b/app/assets/stylesheets/admin/application.css.scss @@ -16,176 +16,159 @@ *= require_self */ +@import 'variables'; + // creates styles for text in the navbar that is not a link -.navbar-default .navbar-nav > li > a.logged-in -{ - color:#DE9292; +.navbar-default .navbar-nav > li > a.logged-in { + color: $lighter-red; } -.content-box -{ - -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.15); - -moz-box-shadow: 0 1px 2px rgba(0,0,0,.15); - box-shadow: 0 1px 2px rgba(0,0,0,.15); - - border:1px solid #DE9292; - margin-bottom:10px; - padding:20px; - - h1 - { - color:#DE9292; - font-size:14px; - margin:0; - padding:0; +.content-box { + border: 1px solid $lighter-red; + margin-bottom: 10px; + padding: 20px; + + h1 { + color: $lighter-red; + font-size: 14px; + margin: 0; + padding: 0; text-transform: uppercase; } + p { padding-top: 10px; } } -.inst-box -{ - -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.15); - -moz-box-shadow: 0 1px 2px rgba(0,0,0,.15); - box-shadow: 0 1px 2px rgba(0,0,0,.15); - - border:1px solid #C8D4E8; - margin-bottom:20px; - header - { - background:#cbe0f3; - margin-bottom:10px; - padding:10px; - - .desc - { - font-size:14px; - display:inline; - - em - { - color:#b5121b; +.inst-box { + border: 1px solid $light-blue; + margin-bottom: 20px; + + header { + background: $lighter-blue; + margin-bottom: 10px; + padding: 10px; + + .desc { + display: inline; + font-size: 14px; + + em { + color: $red; } } - label {font-weight: bold; font-size:16px;} + + label { font-size: 16px; font-weight: bold; } } - input, textarea - { - margin:0px 0px 20px 0px; + + input, + textarea { + margin: 0 0 20px; } - p - { - padding:0px 10px 0px 10px; + p { + padding: 0 10px; } - fieldset - { + + fieldset { padding: 10px; } - hr - { - margin-left:-10px; + hr { + margin-left: -10px; } } -.add_fields, .add_array_fields -{ - margin: 10px 0px 15px 10px; +.add-fields, +.add-array-fields { + margin: 10px 0 15px 10px; } // Adds a red border around invalid input fields after form submission. -.field_with_errors -{ - input, select, textarea - { - border-color: red; +// scss-lint:disable SelectorFormat +.field_with_errors { + input, + select, + textarea { + border-color: $red; border-width: 2px; } } +// scss-lint:enable SelectorFormat -.accessibility -{ +.accessibility { input { margin-top: 4px; } label { margin-bottom: 7px; } } -#categories -{ - label { padding-left: 5px; margin-bottom: 7px; } - input { margin: 4px 0px 0px -20px; } +#categories { + label { margin-bottom: 7px; padding-left: 5px; } + input { margin: 4px 0 0 -20px; } } // margin added to accommodate for floating footer // This needs to be added to the last form element before the save button -.edit_entry, .new_entry -{ +.edit-entry { margin-bottom: 60px; } -.danger-zone -{ - border:1px solid #DE9292; - margin-bottom:20px; - color:white; - - header - { - background:#df3e3e; - margin-bottom:10px; - padding:10px; +.danger-zone { + border: 1px solid $lighter-red; + color: $white; + margin-bottom: 20px; + + header { + background: $light-red; + margin-bottom: 10px; + padding: 10px; } - p - { - padding:10px; - color: #000000; + p { + color: $black; + padding: 10px; } - h4 - { + h4 { + color: $black; font-weight: bold; - color: #000000; - padding:10px 0 0 10px; + padding: 10px 0 0 10px; } } -a.boxed-action,a.boxed-action:link,a.boxed-action:visited -{ - display:inline-block; - color: #df3e3e; - border:1px solid #C8E8CA; - padding: 10px; +a.boxed-action, +a.boxed-action:link, +a.boxed-action:visited { + background-color: $gray; + border: 1px solid $light-green; + color: $light-red; + display: inline-block; font-weight: bold; - background-color: #fcfcfc; - text-decoration:none; + padding: 10px; + text-decoration: none; } -a.boxed-action:hover, a.boxed-action:active -{ - background-color: #df3e3e; - color: #fff; +a.boxed-action:hover, +a.boxed-action:active { + background-color: $light-red; + color: $white; } -.save-box -{ - position:fixed; - bottom:0; - left:0; - right:0; - text-align:center; - - input - { - margin-top:20px; - margin-bottom:20px; +.save-box { + bottom: 0; + left: 0; + position: fixed; + right: 0; + text-align: center; + + input { + margin-bottom: 20px; + margin-top: 20px; } - p - { - display:inline-block; - margin-top:20px; - margin-right:20px; - margin-bottom:0px; + + p { + display: inline-block; + margin-bottom: 0; + margin-right: 20px; + margin-top: 20px; } } diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss index 9ac4ae780..c0c547a4d 100644 --- a/app/assets/stylesheets/application.css.scss +++ b/app/assets/stylesheets/application.css.scss @@ -14,8 +14,9 @@ *= require framework_and_overrides */ +@import 'variables'; + // creates styles for text in the navbar that is not a link -.navbar-default .navbar-nav > li > a.logged-in -{ - color:#DE9292; +.navbar-default .navbar-nav > li > a.logged-in { + color: $light-red; } diff --git a/app/assets/stylesheets/framework_and_overrides.css.scss b/app/assets/stylesheets/framework_and_overrides.css.scss index 7901e42ac..fc37dc5ac 100644 --- a/app/assets/stylesheets/framework_and_overrides.css.scss +++ b/app/assets/stylesheets/framework_and_overrides.css.scss @@ -1,42 +1,51 @@ // import the CSS framework -@import "bootstrap-sprockets"; -@import "bootstrap"; +@import 'bootstrap-sprockets'; +@import 'bootstrap'; .content { - padding: 70px 10px 60px 10px; font-size: 16px; line-height: 1.428; + padding: 70px 10px 60px; } .authform { - padding-top: 30px; - max-width: 320px; margin: 0 auto; + max-width: 320px; + padding-top: 30px; + + form { + @extend .well; + @extend .well-lg; + padding-bottom: 40px; + } + + .right { + float: right; + } + + .button { + @extend .btn; + @extend .btn-primary; + } + + fieldset { + @extend .well; + } } -.authform form { - @extend .well; - @extend .well-lg; - padding-bottom: 40px; -} -.authform .right { - float: right !important; -} -.authform .button { - @extend .btn; - @extend .btn-primary; -} -.authform fieldset { - @extend .well; -} + +// scss-lint:disable SelectorFormat, IdSelector #error_explanation { @extend .alert; @extend .alert-danger; + + h2 { + font-size: 16px; + } } -#error_explanation h2 { - font-size: 16px; -} +// scss-lint:disable SelectorFormat, IdSelector + .button-xs { @extend .btn; @extend .btn-primary; @extend .btn-xs; -} \ No newline at end of file +} diff --git a/app/controllers/admin/csv_controller.rb b/app/controllers/admin/csv_controller.rb index 8672e3202..91baf8344 100644 --- a/app/controllers/admin/csv_controller.rb +++ b/app/controllers/admin/csv_controller.rb @@ -36,7 +36,7 @@ def services def all redirect_to :back, notice: I18n.t('admin.notices.zip_file_generation') - ZipDownloadJob.new.async.later(2, tmp_file_name, url_prefix) + ZipDownloadJob.perform_in(2, tmp_file_name, url_prefix) end def download_zip @@ -46,7 +46,7 @@ def download_zip filename: zip_file_name, x_sendfile: true - ZipDeleteJob.new.async.later(60, tmp_file_name) + ZipDeleteJob.perform_in(60, tmp_file_name) else redirect_to admin_dashboard_url, notice: I18n.t('admin.notices.wait_for_zip_file') diff --git a/app/controllers/admin/registrations_controller.rb b/app/controllers/admin/registrations_controller.rb index 742b9a32c..ef20019cb 100644 --- a/app/controllers/admin/registrations_controller.rb +++ b/app/controllers/admin/registrations_controller.rb @@ -7,8 +7,8 @@ class RegistrationsController < Devise::RegistrationsController protected def configure_permitted_parameters - devise_parameter_sanitizer.for(:sign_up).push(:name) - devise_parameter_sanitizer.for(:account_update).push(:name) + devise_parameter_sanitizer.permit(:sign_up, keys: [:name]) + devise_parameter_sanitizer.permit(:account_update, keys: [:name]) end def after_inactive_sign_up_path_for(_resource) diff --git a/app/controllers/admin/services_controller.rb b/app/controllers/admin/services_controller.rb index 669e1ce33..c859b17cb 100644 --- a/app/controllers/admin/services_controller.rb +++ b/app/controllers/admin/services_controller.rb @@ -39,6 +39,7 @@ def new @service = Service.new end + # rubocop:disable Metrics/MethodLength def create preprocess_service_params @@ -55,6 +56,7 @@ def create render :new end end + # rubocop:enable Metrics/MethodLength def destroy service = Service.find(params[:id]) diff --git a/app/controllers/api/v1/categories_controller.rb b/app/controllers/api/v1/categories_controller.rb index 738b655b0..4ea26f393 100644 --- a/app/controllers/api/v1/categories_controller.rb +++ b/app/controllers/api/v1/categories_controller.rb @@ -7,7 +7,7 @@ def index end def children - children = Category.find_by_taxonomy_id(params[:taxonomy_id]).children + children = Category.find_by(taxonomy_id: params[:taxonomy_id]).children render json: children, status: 200 end end diff --git a/app/controllers/api/v1/errors_controller.rb b/app/controllers/api/v1/errors_controller.rb index 127b946bb..672a9407b 100644 --- a/app/controllers/api/v1/errors_controller.rb +++ b/app/controllers/api/v1/errors_controller.rb @@ -3,7 +3,7 @@ module V1 class ErrorsController < ApplicationController def raise_not_found! message = "No route matches #{params[:unmatched_route]}" - fail ActionController::RoutingError, message + raise ActionController::RoutingError, message end end end diff --git a/app/controllers/api/v1/root_controller.rb b/app/controllers/api/v1/root_controller.rb index 7e99a231e..e7bf22384 100644 --- a/app/controllers/api/v1/root_controller.rb +++ b/app/controllers/api/v1/root_controller.rb @@ -6,12 +6,12 @@ def index organizations_url: "#{api_organizations_url}{?page,per_page}", organization_url: "#{api_organizations_url}/{organization}", organization_locations_url: "#{api_url}/organizations/{organization}"\ - '/locations{?page,per_page}', + "/locations{?page,per_page}", locations_url: "#{api_locations_url}{?page,per_page}", location_url: "#{api_locations_url}/{location}", location_search_url: "#{api_search_index_url}{?category,email,"\ - 'keyword,language,lat_lng,location,org_name,radius,service_area,'\ - 'status,page,per_page}' + "keyword,language,lat_lng,location,org_name,radius,service_area,"\ + "status,page,per_page}" } render json: json_for_root_endpoint, status: 200 end diff --git a/app/controllers/api/v1/search_controller.rb b/app/controllers/api/v1/search_controller.rb index bb21870ae..550d9496b 100644 --- a/app/controllers/api/v1/search_controller.rb +++ b/app/controllers/api/v1/search_controller.rb @@ -11,10 +11,10 @@ def index locations = Location.search(params).page(params[:page]). per(params[:per_page]) - if stale?(etag: cache_key(locations), public: true) - generate_pagination_headers(locations) - render json: locations.preload(tables), each_serializer: LocationsSerializer, status: 200 - end + return unless stale?(etag: cache_key(locations), public: true) + + generate_pagination_headers(locations) + render json: locations.preload(tables), each_serializer: LocationsSerializer, status: 200 end def nearby diff --git a/app/controllers/api/v1/services_controller.rb b/app/controllers/api/v1/services_controller.rb index ea8454065..928d0e773 100644 --- a/app/controllers/api/v1/services_controller.rb +++ b/app/controllers/api/v1/services_controller.rb @@ -10,7 +10,8 @@ class ServicesController < ApplicationController def index location = Location.includes( services: [:categories, :contacts, :phones, :regular_schedules, - :holiday_schedules]).find(params[:location_id]) + :holiday_schedules] + ).find(params[:location_id]) services = location.services render json: services, status: 200 end diff --git a/app/controllers/api/v1/status_controller.rb b/app/controllers/api/v1/status_controller.rb index 878dfe9e2..f07196213 100644 --- a/app/controllers/api/v1/status_controller.rb +++ b/app/controllers/api/v1/status_controller.rb @@ -3,7 +3,7 @@ module V1 class StatusController < ApplicationController def check_status response_hash = {} - response_hash[:dependencies] = %w(Mandrill Postgres) + response_hash[:dependencies] = %w(SendGrid Postgres) response_hash[:status] = everything_ok? ? 'ok' : 'NOT OK' response_hash[:updated] = Time.zone.now.to_i diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 1846bfae6..184693ac4 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,8 +1,7 @@ class ApplicationController < ActionController::Base include Pundit # Prevent CSRF attacks by raising an exception (with: :exception), - # or, for APIs, you may want to use :null_session instead. - protect_from_forgery with: :null_session + protect_from_forgery with: :exception # This is to prevent the app from returning a 500 Internal Server Error # when a valid Accept Header is passed to a non-API URL, such as the @@ -51,7 +50,7 @@ def render_not_found def user_not_authorized flash[:error] = I18n.t('admin.not_authorized') - redirect_to(request.referrer || admin_dashboard_path) + redirect_to(request.referer || admin_dashboard_path) end protected diff --git a/app/controllers/concerns/private_registration.rb b/app/controllers/concerns/private_registration.rb index 9b03bffe7..5b51be723 100644 --- a/app/controllers/concerns/private_registration.rb +++ b/app/controllers/concerns/private_registration.rb @@ -15,7 +15,7 @@ def create private def resource_valid_except_for_duplicate_email? - resource_class.find_by_email(resource.email).present? && + resource_class.find_by(email: resource.email).present? && only_email_error_is_duplicate? end diff --git a/app/controllers/user/registrations_controller.rb b/app/controllers/user/registrations_controller.rb index 4ff7c8d56..d380a2f26 100644 --- a/app/controllers/user/registrations_controller.rb +++ b/app/controllers/user/registrations_controller.rb @@ -7,8 +7,8 @@ class RegistrationsController < Devise::RegistrationsController protected def configure_permitted_parameters - devise_parameter_sanitizer.for(:sign_up).push(:name) - devise_parameter_sanitizer.for(:account_update).push(:name) + devise_parameter_sanitizer.permit(:sign_up, keys: [:name]) + devise_parameter_sanitizer.permit(:account_update, keys: [:name]) end def after_update_path_for(_resource) diff --git a/app/helpers/admin/form_helper.rb b/app/helpers/admin/form_helper.rb index 04ca98410..240e8ae0a 100644 --- a/app/helpers/admin/form_helper.rb +++ b/app/helpers/admin/form_helper.rb @@ -6,17 +6,25 @@ def link_to_add_fields(name, f, association) fields = f.fields_for(association, new_object, child_index: id) do |builder| render("admin/locations/forms/#{association.to_s.singularize}_fields", f: builder) end - link_to(name, '#', class: 'add_fields btn btn-primary', data: { id: id, fields: fields.gsub('\n', '') }) + link_to( + name, + '#', + class: 'add-fields btn btn-primary', data: { id: id, fields: fields.gsub('\n', '') } + ) end def link_to_add_array_fields(name, model, field) id = ''.object_id fields = render("admin/#{model}/forms/#{field}_fields") - link_to(name, '#', class: 'add_array_fields btn btn-primary', data: { id: id, fields: fields.gsub('\n', '') }) + link_to( + name, + '#', + class: 'add-array-fields btn btn-primary', data: { id: id, fields: fields.gsub('\n', '') } + ) end def nested_categories(categories) - cats_and_subcats(categories).map do |category, sub_categories| + safe_join(cats_and_subcats(categories).map do |category, sub_categories| content_tag(:ul) do concat(content_tag(:li, class: class_name_for(category)) do concat(checkbox_tag_for(category)) @@ -24,7 +32,7 @@ def nested_categories(categories) concat(nested_categories(sub_categories)) end) end - end.join.html_safe + end) end def cats_and_subcats(categories) @@ -36,7 +44,7 @@ def cats_and_subcats(categories) end def class_name_for(category) - return 'depth0 checkbox' if category.depth == 0 + return 'depth0 checkbox' if category.depth.zero? "hide depth#{category.depth} checkbox" end @@ -62,6 +70,7 @@ def field_contains_errors?(model, attribute, field) model.errors[attribute].select { |error| error.include?(field) }.present? end + # rubocop:disable Metrics/MethodLength def org_autocomplete_field_for(f, admin) if admin.super_admin? f.hidden_field( @@ -79,6 +88,7 @@ def org_autocomplete_field_for(f, admin) ) end end + # rubocop:enable Metrics/MethodLength def program_autocomplete_field_for(f) f.select( diff --git a/app/helpers/admin/zip_download_helper.rb b/app/helpers/admin/zip_download_helper.rb index 2000a8f21..7c8588865 100644 --- a/app/helpers/admin/zip_download_helper.rb +++ b/app/helpers/admin/zip_download_helper.rb @@ -2,9 +2,14 @@ class Admin module ZipDownloadHelper def zip_file_status if File.exist?(tmp_file_name) - link_to I18n.t('admin.buttons.download_zip_file'), admin_csv_download_zip_url, class: 'btn btn-primary' + link_to( + I18n.t('admin.buttons.download_zip_file'), + admin_csv_download_zip_url, class: 'btn btn-primary' + ) else - link_to I18n.t('admin.buttons.generate_zip_file'), admin_csv_all_path, class: 'btn btn-primary' + link_to( + I18n.t('admin.buttons.generate_zip_file'), admin_csv_all_path, class: 'btn btn-primary' + ) end end diff --git a/app/models/admin.rb b/app/models/admin.rb index 4e9f7e67f..ee49fa65d 100644 --- a/app/models/admin.rb +++ b/app/models/admin.rb @@ -4,7 +4,7 @@ class Admin < ActiveRecord::Base # Devise already checks for presence of email and password. validates :name, presence: true - validates :email, uniqueness: { case_sensitive: false } + validates :email, email: true, uniqueness: { case_sensitive: false } devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, diff --git a/app/models/category.rb b/app/models/category.rb index 7c226bcc7..a6e52a3c1 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -9,7 +9,8 @@ class Category < ActiveRecord::Base validates :taxonomy_id, uniqueness: { message: I18n.t('errors.messages.duplicate_taxonomy_id'), - case_sensitive: false } + case_sensitive: false + } has_ancestry end diff --git a/app/models/concerns/search.rb b/app/models/concerns/search.rb index 2016ef251..7cf8b93da 100644 --- a/app/models/concerns/search.rb +++ b/app/models/concerns/search.rb @@ -10,15 +10,17 @@ def nearbys(radius) super(r) end - scope :category, ->(category) { joins(services: :categories).where(categories: { name: category }) } + scope :category, (lambda do |category| + joins(services: :categories).where(categories: { name: category }) + end) - scope :is_near, LocationFilter.new(self) + scope :is_near, LocationFilter scope :org_name, (lambda do |org| joins(:organization).where('organizations.name @@ :q', q: org) end) - scope :with_email, EmailFilter.new(self) + scope :with_email, EmailFilter end module ClassMethods diff --git a/app/models/organization.rb b/app/models/organization.rb index 0adfef808..57d33fb5c 100644 --- a/app/models/organization.rb +++ b/app/models/organization.rb @@ -42,7 +42,7 @@ def self.with_locations(ids) private def needs_touch? - return false if locations.count == 0 + return false if locations.count.zero? name_changed? end diff --git a/app/models/user.rb b/app/models/user.rb index 2e541b493..7570fd8d5 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -7,7 +7,7 @@ class User < ActiveRecord::Base # Devise checks for presence of email and password by default validates :name, presence: true - validates :email, uniqueness: { case_sensitive: false } + validates :email, email: true, uniqueness: { case_sensitive: false } devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, diff --git a/app/validators/date_validator.rb b/app/validators/date_validator.rb index 6ed097cb1..413fa402b 100644 --- a/app/validators/date_validator.rb +++ b/app/validators/date_validator.rb @@ -34,7 +34,7 @@ def split_date(date) date.split('/').map(&:to_i) else date.tr(',', '').split(' ').map.with_index do |e, i| - i == 0 ? Date::MONTHNAMES.index(e) || 0 : e.to_i + i.zero? ? Date::MONTHNAMES.index(e) || 0 : e.to_i end end end diff --git a/app/validators/regex_validator.rb b/app/validators/regex_validator.rb index 6772a0caf..677ea949e 100644 --- a/app/validators/regex_validator.rb +++ b/app/validators/regex_validator.rb @@ -1,7 +1,7 @@ class RegexValidator < ActiveModel::EachValidator def regex_validate_each(regex, err_msg, record, attribute, value) - unless value =~ regex - record.errors[attribute] << (options[:message] || err_msg) - end + return if value =~ regex + + record.errors[attribute] << (options[:message] || err_msg) end end diff --git a/app/validators/service_area_validator.rb b/app/validators/service_area_validator.rb index 482a63aba..cdee5050e 100644 --- a/app/validators/service_area_validator.rb +++ b/app/validators/service_area_validator.rb @@ -3,8 +3,8 @@ def validate_each(record, attribute, value) return if value.blank? || SETTINGS[:valid_service_areas].blank? default_message = "#{value} #{I18n.t('errors.messages.invalid_service_area')}" - unless SETTINGS[:valid_service_areas].include?(value) - record.errors[attribute] << (options[:message] || default_message) - end + return if SETTINGS[:valid_service_areas].include?(value) + + record.errors[attribute] << (options[:message] || default_message) end end diff --git a/app/validators/state_province_validator.rb b/app/validators/state_province_validator.rb index 91cfa22d9..279152591 100644 --- a/app/validators/state_province_validator.rb +++ b/app/validators/state_province_validator.rb @@ -5,8 +5,8 @@ def validate_each(record, attribute, value) return unless COUNTRIES_NEEDING_VALIDATION.include?(record.country) default_message = I18n.t('errors.messages.invalid_state_province') - unless value.present? && value.size == 2 - record.errors[attribute] << (options[:message] || default_message) - end + return if value.present? && value.size == 2 + + record.errors[attribute] << (options[:message] || default_message) end end diff --git a/app/views/admin/contacts/edit.html.haml b/app/views/admin/contacts/edit.html.haml index cc0dca355..12cad7240 100644 --- a/app/views/admin/contacts/edit.html.haml +++ b/app/views/admin/contacts/edit.html.haml @@ -1,5 +1,5 @@ .content-box %h2 #{@contact.try(:name)} / #{@location.name} -= form_for [:admin, @location, @contact], html: { class: 'edit_entry' } do |f| += form_for [:admin, @location, @contact], html: { class: 'edit-entry' } do |f| = render 'admin/contacts/form', f: f diff --git a/app/views/admin/contacts/new.html.haml b/app/views/admin/contacts/new.html.haml index c1009073b..58fe44576 100644 --- a/app/views/admin/contacts/new.html.haml +++ b/app/views/admin/contacts/new.html.haml @@ -1,5 +1,5 @@ .content-box %h1 Create a new contact -= form_for [:admin, @location, @contact], html: { method: :post, class: 'edit_entry' } do |f| += form_for [:admin, @location, @contact], html: { method: :post, class: 'edit-entry' } do |f| = render 'admin/contacts/forms/new_contact', f: f diff --git a/app/views/admin/locations/edit.html.haml b/app/views/admin/locations/edit.html.haml index 98c4eff54..aa91e759c 100644 --- a/app/views/admin/locations/edit.html.haml +++ b/app/views/admin/locations/edit.html.haml @@ -1,5 +1,5 @@ .content-box %h2= @location.name == @org.try(:name) ? @location.name : "#{@org.try(:name)} / #{@location.name}" -= form_for [:admin, @location], html: { class: 'edit_entry' } do |f| += form_for [:admin, @location], html: { class: 'edit-entry' } do |f| = render 'form', f: f diff --git a/app/views/admin/locations/new.html.haml b/app/views/admin/locations/new.html.haml index d4ada5e6a..d65ae392c 100644 --- a/app/views/admin/locations/new.html.haml +++ b/app/views/admin/locations/new.html.haml @@ -3,5 +3,5 @@ %p You'll be able to add Contacts and Services to this location after you create it. -= form_for [:admin, @location], url: admin_locations_path, html: { method: :post, class: 'edit_entry' } do |f| += form_for [:admin, @location], url: admin_locations_path, html: { method: :post, class: 'edit-entry' } do |f| = render 'admin/locations/forms/new_location_form', f: f diff --git a/app/views/admin/organization_contacts/edit.html.haml b/app/views/admin/organization_contacts/edit.html.haml index a9d6bfad5..8c3d61644 100644 --- a/app/views/admin/organization_contacts/edit.html.haml +++ b/app/views/admin/organization_contacts/edit.html.haml @@ -1,4 +1,4 @@ .content-box %h2 #{@contact.try(:name)} / #{@organization.name} -= form_for [:admin, @organization, @contact], html: { class: 'edit_entry' } do |f| += form_for [:admin, @organization, @contact], html: { class: 'edit-entry' } do |f| = render 'admin/contacts/form', f: f diff --git a/app/views/admin/organization_contacts/new.html.haml b/app/views/admin/organization_contacts/new.html.haml index 658d5e4dd..fa1581b71 100644 --- a/app/views/admin/organization_contacts/new.html.haml +++ b/app/views/admin/organization_contacts/new.html.haml @@ -1,5 +1,5 @@ .content-box %h1 Create a new contact -= form_for [:admin, @organization, @contact], html: { method: :post, class: 'edit_entry' } do |f| += form_for [:admin, @organization, @contact], html: { method: :post, class: 'edit-entry' } do |f| = render 'admin/contacts/forms/new_org_contact', f: f diff --git a/app/views/admin/organizations/edit.html.haml b/app/views/admin/organizations/edit.html.haml index d0f71a86a..d9b593c66 100644 --- a/app/views/admin/organizations/edit.html.haml +++ b/app/views/admin/organizations/edit.html.haml @@ -1,4 +1,4 @@ .content-box %h2= @organization.name -= form_for [:admin, @organization], html: { class: 'edit_entry' } do |f| += form_for [:admin, @organization], html: { class: 'edit-entry' } do |f| = render 'admin/organizations/form', f: f diff --git a/app/views/admin/organizations/new.html.haml b/app/views/admin/organizations/new.html.haml index 6ff07a4b7..a970df5b1 100644 --- a/app/views/admin/organizations/new.html.haml +++ b/app/views/admin/organizations/new.html.haml @@ -1,5 +1,5 @@ .content-box %h1 Create a new organization -= form_for [:admin, @organization], url: admin_organizations_path, html: { method: :post, class: 'edit_entry' } do |f| += form_for [:admin, @organization], url: admin_organizations_path, html: { method: :post, class: 'edit-entry' } do |f| = render 'admin/organizations/forms/new_organization_form', f: f diff --git a/app/views/admin/programs/edit.html.haml b/app/views/admin/programs/edit.html.haml index a13f4137d..e68334f4a 100644 --- a/app/views/admin/programs/edit.html.haml +++ b/app/views/admin/programs/edit.html.haml @@ -1,4 +1,4 @@ .content-box %h2 #{@program.organization.try(:name)} / #{@program.name} -= form_for [:admin, @program], html: { class: 'edit_entry' } do |f| += form_for [:admin, @program], html: { class: 'edit-entry' } do |f| = render 'admin/programs/form', f: f diff --git a/app/views/admin/programs/new.html.haml b/app/views/admin/programs/new.html.haml index c28bde073..b3a6da270 100644 --- a/app/views/admin/programs/new.html.haml +++ b/app/views/admin/programs/new.html.haml @@ -1,5 +1,5 @@ .content-box %h1 Create a new program -= form_for [:admin, @program], url: admin_programs_path, html: { method: :post, class: 'edit_entry' } do |f| += form_for [:admin, @program], url: admin_programs_path, html: { method: :post, class: 'edit-entry' } do |f| = render 'admin/programs/forms/new_program_form', f: f diff --git a/app/views/admin/service_contacts/edit.html.haml b/app/views/admin/service_contacts/edit.html.haml index 316a015c7..4da879f6a 100644 --- a/app/views/admin/service_contacts/edit.html.haml +++ b/app/views/admin/service_contacts/edit.html.haml @@ -1,4 +1,4 @@ .content-box %h2 #{@contact.try(:name)} / #{@service.name} -= form_for [:admin, @service.location, @service, @contact], html: { class: 'edit_entry' } do |f| += form_for [:admin, @service.location, @service, @contact], html: { class: 'edit-entry' } do |f| = render 'admin/contacts/form', f: f diff --git a/app/views/admin/service_contacts/new.html.haml b/app/views/admin/service_contacts/new.html.haml index caff3b710..6f25b24b5 100644 --- a/app/views/admin/service_contacts/new.html.haml +++ b/app/views/admin/service_contacts/new.html.haml @@ -1,5 +1,5 @@ .content-box %h1 Create a new contact -= form_for [:admin, @service.location, @service, @contact], html: { method: :post, class: 'edit_entry' } do |f| += form_for [:admin, @service.location, @service, @contact], html: { method: :post, class: 'edit-entry' } do |f| = render 'admin/contacts/forms/new_service_contact', f: f diff --git a/app/views/admin/services/edit.html.haml b/app/views/admin/services/edit.html.haml index 982add993..9c2e3d97f 100644 --- a/app/views/admin/services/edit.html.haml +++ b/app/views/admin/services/edit.html.haml @@ -1,5 +1,5 @@ .content-box %h2 #{@service.try(:name)} / #{@location.name} -= form_for [:admin, @location, @service], html: { class: 'edit_entry' } do |f| += form_for [:admin, @location, @service], html: { class: 'edit-entry' } do |f| = render 'admin/services/form', f: f diff --git a/app/views/admin/services/new.html.haml b/app/views/admin/services/new.html.haml index a6eca1de6..70e20f5ba 100644 --- a/app/views/admin/services/new.html.haml +++ b/app/views/admin/services/new.html.haml @@ -1,5 +1,5 @@ .content-box %h1 Create a new service -= form_for [:admin, @location, @service], html: { method: :post, class: 'edit_entry' } do |f| += form_for [:admin, @location, @service], html: { method: :post, class: 'edit-entry' } do |f| = render 'admin/services/forms/new_service_form', f: f diff --git a/bin/setup b/bin/setup index 5c185e957..70f93afa7 100755 --- a/bin/setup +++ b/bin/setup @@ -14,6 +14,10 @@ Dir.chdir APP_ROOT do system 'cp config/application.example.yml config/application.yml' end + if ARGV.shift == "--docker" then + exit + end + puts '== Installing dependencies ==' system 'gem install bundler --conservative' system 'bundle check || bundle install' diff --git a/config/environments/production.rb b/config/environments/production.rb index 648f62d1b..7f122302a 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -24,7 +24,8 @@ # Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = false - # `config.assets.version` and `config.assets.precompile` have moved to config/initializers/assets.rb + # `config.assets.version` and `config.assets.precompile` have moved to + # config/initializers/assets.rb # Specifies the header that your server uses for sending files. # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache @@ -91,11 +92,12 @@ config.action_mailer.smtp_settings = { port: '587', - address: 'smtp.mandrillapp.com', - user_name: ENV['MANDRILL_USERNAME'], - password: ENV['MANDRILL_APIKEY'], + address: 'smtp.sendgrid.net', + user_name: ENV['SENDGRID_USERNAME'], + password: ENV['SENDGRID_PASSWORD'], domain: 'heroku.com', - authentication: :plain + authentication: :plain, + enable_starttls_auto: true } # Enable locale fallbacks for I18n (makes lookups for any locale fall back to diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb index 59385cdf3..cf74fe3d7 100644 --- a/config/initializers/backtrace_silencers.rb +++ b/config/initializers/backtrace_silencers.rb @@ -1,7 +1,9 @@ # Be sure to restart your server when you modify this file. -# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. +# You can add backtrace silencers for libraries that you're using but don't +# wish to see in your backtraces. # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } -# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. +# You can also remove all the silencers if you're trying to debug a problem +# that might stem from framework code. # Rails.backtrace_cleaner.remove_silencers! diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index f8f59ab70..2ce6d7bd0 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -248,7 +248,7 @@ # random tokens. Changing this key will render invalid all existing # confirmation, reset password and unlock tokens in the database. if Rails.env.production? && ENV['DEVISE_SECRET_KEY'].blank? - fail 'The DEVISE_SECRET_KEY environment variable is not set on your production' \ + raise 'The DEVISE_SECRET_KEY environment variable is not set on your production' \ ' server. To generate a random key, run "rake secret" from the command' \ ' line, then set it in production. If you\'re using Heroku, you can set it ' \ 'like this: "heroku config:set DEVISE_SECRET_KEY=the_key_you_generated".' diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb index e77991e9d..e5c7abdfc 100644 --- a/config/initializers/filter_parameter_logging.rb +++ b/config/initializers/filter_parameter_logging.rb @@ -1,4 +1,6 @@ # Be sure to restart your server when you modify this file. # Configure sensitive parameters which will be filtered from the log file. -Rails.application.config.filter_parameters += [:password, :password_confirmation, :api_token, :email] +Rails.application.config.filter_parameters += [ + :password, :password_confirmation, :api_token, :email +] diff --git a/config/initializers/secret_token.rb b/config/initializers/secret_token.rb index 359e479f5..c8539237b 100644 --- a/config/initializers/secret_token.rb +++ b/config/initializers/secret_token.rb @@ -8,10 +8,10 @@ # You can use `rake secret` to generate a secure secret key. if Rails.env.production? && ENV['SECRET_TOKEN'].blank? - fail 'The SECRET_TOKEN environment variable is not set on your production' \ - ' server. To generate a random token, run "rake secret" from the command' \ - ' line, then set it in production. If you\'re using Heroku, you can set it ' \ - 'like this: "heroku config:set SECRET_TOKEN=the_token_you_generated".' + raise 'The SECRET_TOKEN environment variable is not set on your production' \ + ' server. To generate a random token, run "rake secret" from the command' \ + ' line, then set it in production. If you\'re using Heroku, you can set ' \ + 'it like this: "heroku config:set SECRET_TOKEN=the_token_you_generated".' end # Make sure the secrets in this file are kept private diff --git a/config/routes.rb b/config/routes.rb index 78da18965..cfbd0b584 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -8,7 +8,9 @@ # Read more about routing: http://guides.rubyonrails.org/routing.html devise_for :users, controllers: { registrations: 'user/registrations' } - devise_for :admins, path: ENV['ADMIN_PATH'] || '/', controllers: { registrations: 'admin/registrations' } + devise_for( + :admins, path: ENV['ADMIN_PATH'] || '/', controllers: { registrations: 'admin/registrations' } + ) constraints(SubdomainConstraints.new(subdomain: ENV['ADMIN_SUBDOMAIN'])) do namespace :admin, path: ENV['ADMIN_PATH'] do @@ -64,13 +66,16 @@ resources :organizations do resources :locations, only: :create end - get 'organizations/:organization_id/locations', to: 'organizations#locations', as: :org_locations + get 'organizations/:organization_id/locations', + to: 'organizations#locations', as: :org_locations resources :locations do resources :address, except: [:index, :show] resources :mail_address, except: [:index, :show] resources :contacts, except: [:show] do - resources :phones, except: [:show, :index], path: '/phones', controller: 'contact_phones' + resources :phones, + except: [:show, :index], + path: '/phones', controller: 'contact_phones' end resources :phones, except: [:show], path: '/phones', controller: 'location_phones' resources :services @@ -80,11 +85,13 @@ resources :categories, only: :index - put 'services/:service_id/categories', to: 'services#update_categories', as: :service_categories + put 'services/:service_id/categories', + to: 'services#update_categories', as: :service_categories get 'categories/:taxonomy_id/children', to: 'categories#children', as: :category_children get 'locations/:location_id/nearby', to: 'search#nearby', as: :location_nearby - match '*unmatched_route' => 'errors#raise_not_found!', via: [:get, :delete, :patch, :post, :put] + match '*unmatched_route' => 'errors#raise_not_found!', + via: [:get, :delete, :patch, :post, :put] # CORS support match '*unmatched_route' => 'cors#render_204', via: [:options] diff --git a/db/seeds.rb b/db/seeds.rb index 2dc1012dc..81ad39214 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -8,49 +8,49 @@ # Mayor.create(name: 'Emanuel', city: cities.first) # Set up test users for the Developer Portal. -puts 'Setting up first test user...' +Kernel.puts 'Setting up first test user...' user = User.new name: 'First User', - email: 'user@example.com', - password: 'mong01dtest', - password_confirmation: 'mong01dtest' + email: 'user@example.com', + password: 'mong01dtest', + password_confirmation: 'mong01dtest' user.skip_confirmation! user.save -user.confirm! +user.confirm -puts 'Setting up second test user...' +Kernel.puts 'Setting up second test user...' user2 = User.new name: 'Second User', - email: 'user2@example.com', - password: 'mong01dtest', - password_confirmation: 'mong01dtest' + email: 'user2@example.com', + password: 'mong01dtest', + password_confirmation: 'mong01dtest' user2.skip_confirmation! user2.save -user2.confirm! +user2.confirm # Set up test users for the Admin Interface. -puts 'Setting up first test admin...' -admin = Admin.new :name => 'admin with custom domain name', - :email => 'ohana@samaritanhouse.com', - :password => 'ohanatest', - :password_confirmation => 'ohanatest' +Kernel.puts 'Setting up first test admin...' +admin = Admin.new name: 'admin with custom domain name', + email: 'ohana@samaritanhouse.com', + password: 'ohanatest', + password_confirmation: 'ohanatest' admin.skip_confirmation! admin.save -admin.confirm! +admin.confirm -puts 'Setting up second test admin...' -admin2 = Admin.new :name => 'admin with generic email', - :email => 'ohana@gmail.com', - :password => 'ohanatest', - :password_confirmation => 'ohanatest' +Kernel.puts 'Setting up second test admin...' +admin2 = Admin.new name: 'admin with generic email', + email: 'ohana@gmail.com', + password: 'ohanatest', + password_confirmation: 'ohanatest' admin2.skip_confirmation! admin2.save -admin2.confirm! +admin2.confirm -puts 'Setting up test super admin...' -admin3 = Admin.new :name => 'Super Admin', - :email => 'masteradmin@ohanapi.org', - :password => 'ohanatest', - :password_confirmation => 'ohanatest' +Kernel.puts 'Setting up test super admin...' +admin3 = Admin.new name: 'Super Admin', + email: 'masteradmin@ohanapi.org', + password: 'ohanatest', + password_confirmation: 'ohanatest' admin3.skip_confirmation! admin3.super_admin = true admin3.save -admin3.confirm! +admin3.confirm diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..0acf94008 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,14 @@ +version: '2' +services: + web: + build: . + volumes: + - .:/ohana-api + ports: + - "8080:8080" + environment: + DATABASE_URL: "postgres://postgres@db" + depends_on: + - db + db: + image: postgres diff --git a/lib/email_filter.rb b/lib/email_filter.rb index 9d12c7f64..62bd678b3 100644 --- a/lib/email_filter.rb +++ b/lib/email_filter.rb @@ -1,5 +1,9 @@ class EmailFilter - def initialize(model_class) + class << self + delegate :call, to: :new + end + + def initialize(model_class = Location) @model_class = model_class end diff --git a/lib/entity_importer.rb b/lib/entity_importer.rb index 802e21f08..02f0cdb0c 100644 --- a/lib/entity_importer.rb +++ b/lib/entity_importer.rb @@ -8,10 +8,10 @@ def self.import_file(path) def self.check_and_import_file(path) check = FileChecker.new(path, required_headers).validate - if check != 'skip import' - Kernel.puts("\n===> Importing #{path.to_s.split('/').last}") - process_import(path) - end + return if check == 'skip import' + + Kernel.puts("\n===> Importing #{path.to_s.split('/').last}") + process_import(path) end def self.process_import(path) diff --git a/lib/location_filter.rb b/lib/location_filter.rb index c4a07c5cc..f2ba46705 100644 --- a/lib/location_filter.rb +++ b/lib/location_filter.rb @@ -1,7 +1,11 @@ require 'exceptions' class LocationFilter - def initialize(model_class) + class << self + delegate :call, to: :new + end + + def initialize(model_class = Location) @model_class = model_class end @@ -13,7 +17,7 @@ def call(location, lat_lng, radius) def validated_radius(radius, custom_radius) return custom_radius unless radius.present? - fail Exceptions::InvalidRadius if radius.to_f == 0.0 + raise Exceptions::InvalidRadius if radius.to_f == 0.0 # radius must be between 0.1 miles and 50 miles [[0.1, radius.to_f].max, 50].min @@ -34,7 +38,7 @@ def coords(location, lat_lng) def validated_coordinates(lat_lng) lat, lng = lat_lng.split(',') - fail Exceptions::InvalidLatLon if lat.to_f == 0.0 || lng.to_f == 0.0 + raise Exceptions::InvalidLatLon if lat.to_f == 0.0 || lng.to_f == 0.0 [Float(lat), Float(lng)] end end diff --git a/script/bootstrap b/script/bootstrap index c6b709948..b5c41a6a6 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -2,12 +2,15 @@ set -e -echo "===> Bundling..." -bundle install +bin/setup --docker -if [ ! -f config/application.yml ]; then - echo 'Setting default environment variables...' - cp config/application.example.yml config/application.yml -fi +echo "===> Building the Docker image..." +docker-compose build -script/setup_db +echo "===> Starting the Docker image..." +docker-compose up -d + +echo "===> Setting up the database on the Docker image..." +docker-compose run --rm web rake db:setup RAILS_ENV=development +docker-compose run --rm web rake db:setup RAILS_ENV=test +docker-compose run --rm web pg_restore -c --no-owner -d ohana_api_development /ohana-api/data/ohana_api_development.dump -U postgres -h db diff --git a/script/setup_heroku b/script/setup_heroku index 726aa94a9..3f814b120 100755 --- a/script/setup_heroku +++ b/script/setup_heroku @@ -14,12 +14,12 @@ then echo "Setting DEVISE_SECRET_KEY" # generate a random string with 36 characters - token1=$(python -c 'import uuid; print uuid.uuid4()') + token1=$(python -c 'import uuid; print (uuid.uuid4())') heroku config:set DEVISE_SECRET_KEY=$token1 --app $herokuApp echo "Setting SECRET_TOKEN" # generate a random string with 36 characters - token2=$(python -c 'import uuid; print uuid.uuid4()') + token2=$(python -c 'import uuid; print (uuid.uuid4())') heroku config:set SECRET_TOKEN=$token2 --app $herokuApp echo "Getting ready to install add-ons for $herokuApp" @@ -27,8 +27,8 @@ then echo "Installing Postgres" heroku addons:create heroku-postgresql --app $herokuApp - echo "Installing Mandrill by MailChimp" - heroku addons:create mandrill --app $herokuApp + echo "Installing SendGrid" + heroku addons:create sendgrid:starter --app $herokuApp echo "Installing Memcachier" heroku addons:create memcachier --app $herokuApp diff --git a/spec/active_record_spec_helper.rb b/spec/active_record_spec_helper.rb index 7c58e3087..85fdf813b 100644 --- a/spec/active_record_spec_helper.rb +++ b/spec/active_record_spec_helper.rb @@ -7,7 +7,7 @@ config.around do |example| ActiveRecord::Base.transaction do example.run - fail ActiveRecord::Rollback + raise ActiveRecord::Rollback end end end diff --git a/spec/api/contacts/patch_phone_spec.rb b/spec/api/contacts/patch_phone_spec.rb index 8f2377775..14ac21374 100644 --- a/spec/api/contacts/patch_phone_spec.rb +++ b/spec/api/contacts/patch_phone_spec.rb @@ -18,7 +18,9 @@ describe 'PATCH /locations/:location_id/contacts/:contact_id/phones/:id' do it 'returns 200 when validations pass' do patch( - api_location_contact_phone_url(@location, @contact, @phone, subdomain: ENV['API_SUBDOMAIN']), + api_location_contact_phone_url( + @location, @contact, @phone, subdomain: ENV['API_SUBDOMAIN'] + ), @attrs ) expect(response).to have_http_status(200) @@ -26,7 +28,9 @@ it 'returns the updated phone when validations pass' do patch( - api_location_contact_phone_url(@location, @contact, @phone, subdomain: ENV['API_SUBDOMAIN']), + api_location_contact_phone_url( + @location, @contact, @phone, subdomain: ENV['API_SUBDOMAIN'] + ), @attrs ) expect(json['number_type']).to eq 'fax' @@ -34,7 +38,9 @@ it "updates the contact's phone" do patch( - api_location_contact_phone_url(@location, @contact, @phone, subdomain: ENV['API_SUBDOMAIN']), + api_location_contact_phone_url( + @location, @contact, @phone, subdomain: ENV['API_SUBDOMAIN'] + ), @attrs ) get api_location_url(@location, subdomain: ENV['API_SUBDOMAIN']) @@ -43,7 +49,9 @@ it "doesn't add a new phone" do patch( - api_location_contact_phone_url(@location, @contact, @phone, subdomain: ENV['API_SUBDOMAIN']), + api_location_contact_phone_url( + @location, @contact, @phone, subdomain: ENV['API_SUBDOMAIN'] + ), @attrs ) expect(@contact.reload.phones.count).to eq(1) @@ -61,7 +69,9 @@ it 'returns 422 when attribute is invalid' do patch( - api_location_contact_phone_url(@location, @contact, @phone, subdomain: ENV['API_SUBDOMAIN']), + api_location_contact_phone_url( + @location, @contact, @phone, subdomain: ENV['API_SUBDOMAIN'] + ), @attrs.merge!(number: '703') ) expect(response.status).to eq(422) @@ -72,7 +82,9 @@ it "doesn't allow updating a phone without a valid token" do patch( - api_location_contact_phone_url(@location, @contact, @phone, subdomain: ENV['API_SUBDOMAIN']), + api_location_contact_phone_url( + @location, @contact, @phone, subdomain: ENV['API_SUBDOMAIN'] + ), @attrs, 'HTTP_X_API_TOKEN' => 'invalid_token' ) diff --git a/spec/api/create_location_spec.rb b/spec/api/create_location_spec.rb index 96a47c828..925b15019 100644 --- a/spec/api/create_location_spec.rb +++ b/spec/api/create_location_spec.rb @@ -11,7 +11,8 @@ description: 'description', address_attributes: { address_1: 'main', city: 'utopia', state_province: 'CA', postal_code: '12345', - country: 'US' } + country: 'US' + } } end diff --git a/spec/api/get_location_spec.rb b/spec/api/get_location_spec.rb index 0f7aee679..421fcb77c 100644 --- a/spec/api/get_location_spec.rb +++ b/spec/api/get_location_spec.rb @@ -283,7 +283,8 @@ create!(name: 'Orthodontics', taxonomy_id: '102-01') create_service @service.category_ids = [ - @food.id, @food_child.id, @health.id, @health_child.id] + @food.id, @food_child.id, @health.id, @health_child.id + ] end it 'orders the categories by taxonomy_id' do diff --git a/spec/api/get_locations_spec.rb b/spec/api/get_locations_spec.rb index 4230fca91..ee620e868 100644 --- a/spec/api/get_locations_spec.rb +++ b/spec/api/get_locations_spec.rb @@ -179,39 +179,6 @@ json = JSON.parse(response.body) expect(json['name']).to eq(@location.name) end - - xit 'displays mail_address when present' do - @location.create_mail_address!(attributes_for(:mail_address)) - get api_locations_url(subdomain: ENV['API_SUBDOMAIN']) - - serialized_mail_address = - { - 'id' => @location.mail_address.id, - 'attention' => @location.mail_address.attention, - 'address_1' => @location.mail_address.address_1, - 'city' => @location.mail_address.city, - 'state_province' => @location.mail_address.state_province, - 'postal_code' => @location.mail_address.postal_code - } - expect(json.first['mail_address']).to eq(serialized_mail_address) - end - - xit 'displays contacts when present' do - @location.contacts.create!(attributes_for(:contact)) - get api_locations_url(subdomain: ENV['API_SUBDOMAIN']) - - serialized_contacts = - [{ - 'id' => @location.contacts.first.id, - 'name' => @location.contacts.first.name, - 'title' => @location.contacts.first.title, - 'phone' => nil, - 'email' => nil, - 'extension' => nil, - 'fax' => nil - }] - expect(json.first['contacts']).to eq(serialized_contacts) - end end context 'with nil fields' do diff --git a/spec/api/get_organization_locations_spec.rb b/spec/api/get_organization_locations_spec.rb index 0ab3cf1c6..83f1bd318 100644 --- a/spec/api/get_organization_locations_spec.rb +++ b/spec/api/get_organization_locations_spec.rb @@ -9,7 +9,7 @@ admin_emails: %w(foo@bar.com), description: 'testing 1 2 3', email: 'foo@bar.com', - languages: %w(french, arabic), + languages: %w(french arabic), latitude: 37.583939, longitude: -122.3715745, name: 'new location', @@ -68,11 +68,6 @@ expect(json.first['address']['address_1']).to eq(@location.address.address_1) end - xit 'includes the location mail_address attribute in the serialization' do - expect(json.first['mail_address']['city']). - to eq(@location.mail_address.city) - end - it 'includes the location updated_at attribute in the serialization' do expect(json.first.keys).to include('updated_at') end diff --git a/spec/api/nearby_spec.rb b/spec/api/nearby_spec.rb index b641ac1d3..9a758a5dd 100644 --- a/spec/api/nearby_spec.rb +++ b/spec/api/nearby_spec.rb @@ -8,7 +8,9 @@ end it 'is paginated' do - get api_location_nearby_url(@loc, page: 2, per_page: 1, radius: 5, subdomain: ENV['API_SUBDOMAIN']) + get api_location_nearby_url( + @loc, page: 2, per_page: 1, radius: 5, subdomain: ENV['API_SUBDOMAIN'] + ) expect(json.first['name']).to eq('Belmont Farmers Market') end diff --git a/spec/api/pagination_headers_spec.rb b/spec/api/pagination_headers_spec.rb index 7db035a95..e76ed2561 100644 --- a/spec/api/pagination_headers_spec.rb +++ b/spec/api/pagination_headers_spec.rb @@ -13,7 +13,8 @@ before(:each) do get api_search_index_url( - keyword: 'jobs', per_page: 1, subdomain: ENV['API_SUBDOMAIN']) + keyword: 'jobs', per_page: 1, subdomain: ENV['API_SUBDOMAIN'] + ) end after(:all) do @@ -27,9 +28,9 @@ it 'returns a Link header' do expect(headers['Link']).to eq( "<#{@prefix}?keyword=jobs&page=2" \ - '&per_page=1>; rel="last", ' \ + "&per_page=1>; rel=\"last\", " \ "<#{@prefix}?keyword=jobs&page=2" \ - '&per_page=1>; rel="next"' + "&per_page=1>; rel=\"next\"" ) end @@ -48,7 +49,8 @@ before(:each) do get api_search_index_url( - keyword: 'jobs', page: 2, per_page: 1, subdomain: ENV['API_SUBDOMAIN']) + keyword: 'jobs', page: 2, per_page: 1, subdomain: ENV['API_SUBDOMAIN'] + ) end after(:all) do @@ -58,9 +60,9 @@ it 'returns a Link header' do expect(headers['Link']).to eq( "<#{@prefix}?keyword=jobs&page=1" \ - '&per_page=1>; rel="first", ' \ + "&per_page=1>; rel=\"first\", " \ "<#{@prefix}?keyword=jobs&page=1" \ - '&per_page=1>; rel="prev"' + "&per_page=1>; rel=\"prev\"" ) end end @@ -74,7 +76,8 @@ before(:each) do get api_search_index_url( - keyword: 'jobs', page: 2, per_page: 1, subdomain: ENV['API_SUBDOMAIN']) + keyword: 'jobs', page: 2, per_page: 1, subdomain: ENV['API_SUBDOMAIN'] + ) end after(:all) do @@ -84,13 +87,13 @@ it 'returns a Link header' do expect(headers['Link']).to eq( "<#{@prefix}?keyword=jobs&page=1" \ - '&per_page=1>; rel="first", ' \ + "&per_page=1>; rel=\"first\", " \ "<#{@prefix}?keyword=jobs&page=1" \ - '&per_page=1>; rel="prev", ' \ + "&per_page=1>; rel=\"prev\", " \ "<#{@prefix}?keyword=jobs&page=3" \ - '&per_page=1>; rel="last", ' \ + "&per_page=1>; rel=\"last\", " \ "<#{@prefix}?keyword=jobs&page=3" \ - '&per_page=1>; rel="next"' + "&per_page=1>; rel=\"next\"" ) end end @@ -104,7 +107,8 @@ before(:each) do get api_search_index_url( - keyword: 'vrs', page: 3, subdomain: ENV['API_SUBDOMAIN']) + keyword: 'vrs', page: 3, subdomain: ENV['API_SUBDOMAIN'] + ) end after(:all) do @@ -124,7 +128,8 @@ it 'does not return a Link header' do create(:location) get api_search_index_url( - keyword: 'jobs', subdomain: ENV['API_SUBDOMAIN']) + keyword: 'jobs', subdomain: ENV['API_SUBDOMAIN'] + ) expect(headers.keys).not_to include 'Link' end end diff --git a/spec/api/root_endpoint_spec.rb b/spec/api/root_endpoint_spec.rb index 8bf0cbd07..017053482 100644 --- a/spec/api/root_endpoint_spec.rb +++ b/spec/api/root_endpoint_spec.rb @@ -7,12 +7,12 @@ 'organizations_url' => "#{api_organizations_url}{?page,per_page}", 'organization_url' => "#{api_organizations_url}/{organization}", 'organization_locations_url' => "#{api_url}/organizations/{organization}"\ - '/locations{?page,per_page}', + "/locations{?page,per_page}", 'locations_url' => "#{api_locations_url}{?page,per_page}", 'location_url' => "#{api_locations_url}/{location}", 'location_search_url' => "#{api_search_index_url}{?category,email,"\ - 'keyword,language,lat_lng,location,org_name,radius,service_area,'\ - 'status,page,per_page}' + "keyword,language,lat_lng,location,org_name,radius,service_area,"\ + "status,page,per_page}" } expect(json).to eq(hash) end diff --git a/spec/api/search_spec.rb b/spec/api/search_spec.rb index 6ee4d7367..68431d1a8 100644 --- a/spec/api/search_spec.rb +++ b/spec/api/search_spec.rb @@ -30,7 +30,9 @@ end it 'is a paginated resource' do - get api_search_index_url(keyword: 'jobs', per_page: 1, page: 2, subdomain: ENV['API_SUBDOMAIN']) + get api_search_index_url( + keyword: 'jobs', per_page: 1, page: 2, subdomain: ENV['API_SUBDOMAIN'] + ) expect(json.length).to eq(1) end @@ -56,21 +58,27 @@ context 'with radius too small but within range' do it 'returns the farmers market name' do - get api_search_index_url(location: 'la honda, ca', radius: 0.05, subdomain: ENV['API_SUBDOMAIN']) + get api_search_index_url( + location: 'la honda, ca', radius: 0.05, subdomain: ENV['API_SUBDOMAIN'] + ) expect(json.first['name']).to eq('Belmont Farmers Market') end end context 'with radius too big but within range' do it 'returns the farmers market name' do - get api_search_index_url(location: 'san gregorio, ca', radius: 50, subdomain: ENV['API_SUBDOMAIN']) + get api_search_index_url( + location: 'san gregorio, ca', radius: 50, subdomain: ENV['API_SUBDOMAIN'] + ) expect(json.first['name']).to eq('Belmont Farmers Market') end end context 'with radius not within range' do it 'returns an empty response array' do - get api_search_index_url(location: 'pescadero, ca', radius: 5, subdomain: ENV['API_SUBDOMAIN']) + get api_search_index_url( + location: 'pescadero, ca', radius: 5, subdomain: ENV['API_SUBDOMAIN'] + ) expect(json).to eq([]) end end @@ -127,7 +135,8 @@ end it 'includes an error description' do - expect(json['description']).to eq 'lat_lng must be a comma-delimited lat,long pair of floats.' + expect(json['description']). + to eq 'lat_lng must be a comma-delimited lat,long pair of floats.' end end @@ -141,7 +150,8 @@ end it 'includes an error description' do - expect(json['description']).to eq 'lat_lng must be a comma-delimited lat,long pair of floats.' + expect(json['description']). + to eq 'lat_lng must be a comma-delimited lat,long pair of floats.' end end @@ -196,7 +206,9 @@ context 'with keyword and location parameters' do it 'only returns locations matching both parameters' do - get api_search_index_url(keyword: 'books', location: 'Burlingame', subdomain: ENV['API_SUBDOMAIN']) + get api_search_index_url( + keyword: 'books', location: 'Burlingame', subdomain: ENV['API_SUBDOMAIN'] + ) expect(headers['X-Total-Count']).to eq '1' expect(json.first['name']).to eq('Library') end @@ -285,7 +297,10 @@ end it 'allows searching for both org_name and location' do - get api_search_index_url(org_name: 'stamps', location: '1236 Broadway, Burlingame, CA 94010', subdomain: ENV['API_SUBDOMAIN']) + get api_search_index_url( + org_name: 'stamps', + location: '1236 Broadway, Burlingame, CA 94010', subdomain: ENV['API_SUBDOMAIN'] + ) expect(headers['X-Total-Count']).to eq '1' expect(json.first['name']).to eq('Library') end @@ -334,9 +349,9 @@ end it 'finds domain name when URL contains a dash' do - create(:location, website: 'http://www.childsup-connect.ca.gov') + create(:location, website: 'http://www.bar-connect.ca.gov') create(:nearby_loc, email: 'gov@childsup-connect.gov') - get "#{api_search_index_url(subdomain: ENV['API_SUBDOMAIN'])}?email=foo@childsup-connect.ca.gov" + get "#{api_search_index_url(subdomain: ENV['API_SUBDOMAIN'])}?email=foo@bar-connect.ca.gov" expect(headers['X-Total-Count']).to eq '1' end @@ -425,7 +440,9 @@ it 'sorts by distance by default' do create(:location) create(:nearby_loc) - get api_search_index_url(location: '1236 Broadway, Burlingame, CA 94010', subdomain: ENV['API_SUBDOMAIN']) + get api_search_index_url( + location: '1236 Broadway, Burlingame, CA 94010', subdomain: ENV['API_SUBDOMAIN'] + ) expect(json.first['name']).to eq('VRS Services') end end diff --git a/spec/controllers/admin/csv_controller_spec.rb b/spec/controllers/admin/csv_controller_spec.rb index e16c35753..22038277b 100644 --- a/spec/controllers/admin/csv_controller_spec.rb +++ b/spec/controllers/admin/csv_controller_spec.rb @@ -10,8 +10,7 @@ request.env['HTTP_REFERER'] = 'http://example.com' - expect(ZipDownloadJob).to receive_message_chain(:new, :async, :later). - with(2, tmp_file_name, url_prefix) + expect(ZipDownloadJob).to receive(:perform_in).with(2, tmp_file_name, url_prefix) get :all end @@ -33,8 +32,7 @@ filename: zip_file_name, x_sendfile: true) - expect(ZipDeleteJob).to receive_message_chain(:new, :async, :later). - with(60, tmp_file_name) + expect(ZipDeleteJob).to receive(:perform_in).with(60, tmp_file_name) get :download_zip end diff --git a/spec/controllers/api_applications_controller_spec.rb b/spec/controllers/api_applications_controller_spec.rb index 8e2ea9a22..8c3f4c272 100644 --- a/spec/controllers/api_applications_controller_spec.rb +++ b/spec/controllers/api_applications_controller_spec.rb @@ -11,15 +11,13 @@ let(:valid_attributes) do { name: 'test app', main_url: 'http://codeforamerica.org', - callback_url: 'https://github.com/codeforamerica' - } + callback_url: 'https://github.com/codeforamerica' } end let(:invalid_attributes) do { name: '', main_url: 'localhost:8080', - callback_url: 'localhost:8080' - } + callback_url: 'localhost:8080' } end describe 'GET index' do diff --git a/spec/features/admin/csv/download_addresses_csv_spec.rb b/spec/features/admin/csv/download_addresses_csv_spec.rb index af708bc29..8444d0a26 100644 --- a/spec/features/admin/csv/download_addresses_csv_spec.rb +++ b/spec/features/admin/csv/download_addresses_csv_spec.rb @@ -14,6 +14,7 @@ it 'populates address attribute values' do expect(csv.second).to eq [ @address.id.to_s, @address.location_id.to_s, '1800 Easton Drive', nil, - 'Burlingame', 'CA', '94010', 'US'] + 'Burlingame', 'CA', '94010', 'US' + ] end end diff --git a/spec/features/admin/csv/download_contacts_csv_spec.rb b/spec/features/admin/csv/download_contacts_csv_spec.rb index 6afeeb5a7..938927aaf 100644 --- a/spec/features/admin/csv/download_contacts_csv_spec.rb +++ b/spec/features/admin/csv/download_contacts_csv_spec.rb @@ -9,7 +9,8 @@ :contact_with_extra_whitespace, location_id: @location.id, organization_id: @org_id, - service_id: @service.id) + service_id: @service.id + ) visit admin_csv_contacts_path(format: 'csv') end @@ -21,6 +22,7 @@ it 'populates contact attribute values' do expect(csv.second).to eq [ @contact.id.to_s, @location.id.to_s, @org_id.to_s, @service.id.to_s, - 'Foo', 'Bar', 'foo@bar.com', 'Screening'] + 'Foo', 'Bar', 'foo@bar.com', 'Screening' + ] end end diff --git a/spec/features/admin/csv/download_holiday_schedules_csv_spec.rb b/spec/features/admin/csv/download_holiday_schedules_csv_spec.rb index 1497daf77..fd491a8c8 100644 --- a/spec/features/admin/csv/download_holiday_schedules_csv_spec.rb +++ b/spec/features/admin/csv/download_holiday_schedules_csv_spec.rb @@ -17,7 +17,8 @@ it 'populates holiday_schedule attribute values' do expect(csv.second).to eq [ @holiday_schedule.id.to_s, @location.id.to_s, nil, - 'December 24, 2014', 'December 24, 2014', 'true', nil, nil] + 'December 24, 2014', 'December 24, 2014', 'true', nil, nil + ] end end @@ -32,7 +33,8 @@ it 'formats the date and time values' do expect(csv.second).to eq [ @holiday_schedule.id.to_s, @location.id.to_s, nil, - 'December 24, 2014', 'December 24, 2014', 'false', '09:00', '17:00'] + 'December 24, 2014', 'December 24, 2014', 'false', '09:00', '17:00' + ] end end end diff --git a/spec/features/admin/csv/download_locations_csv_spec.rb b/spec/features/admin/csv/download_locations_csv_spec.rb index 374b4bb57..50a38f0dd 100644 --- a/spec/features/admin/csv/download_locations_csv_spec.rb +++ b/spec/features/admin/csv/download_locations_csv_spec.rb @@ -5,7 +5,8 @@ before do @loc = create( :loc_with_extra_whitespace, - accessibility: [:tape_braille, :disabled_parking]) + accessibility: [:tape_braille, :disabled_parking] + ) visit admin_csv_locations_path(format: 'csv') end @@ -13,7 +14,8 @@ expect(csv.first).to eq %w( id organization_id accessibility admin_emails alternate_name description email languages latitude - longitude name short_desc transportation website virtual) + longitude name short_desc transportation website virtual + ) end it 'converts arrays to comma-separated strings' do @@ -31,7 +33,8 @@ context 'location has nil array attributes' do before do @loc = create( - :location, accessibility: nil, languages: nil, admin_emails: nil) + :location, accessibility: nil, languages: nil, admin_emails: nil + ) visit admin_csv_locations_path(format: 'csv') end diff --git a/spec/features/admin/csv/download_mail_addresses_csv_spec.rb b/spec/features/admin/csv/download_mail_addresses_csv_spec.rb index dd6e85364..c87aaec82 100644 --- a/spec/features/admin/csv/download_mail_addresses_csv_spec.rb +++ b/spec/features/admin/csv/download_mail_addresses_csv_spec.rb @@ -14,6 +14,7 @@ it 'populates mail address attribute values' do expect(csv.second).to eq [ @mail_address.id.to_s, @mail_address.location_id.to_s, 'Monfresh', - '1 davis dr', nil, 'Belmont', 'CA', '90210', 'US'] + '1 davis dr', nil, 'Belmont', 'CA', '90210', 'US' + ] end end diff --git a/spec/features/admin/csv/download_organizations_csv_spec.rb b/spec/features/admin/csv/download_organizations_csv_spec.rb index 893e694f4..8f925498a 100644 --- a/spec/features/admin/csv/download_organizations_csv_spec.rb +++ b/spec/features/admin/csv/download_organizations_csv_spec.rb @@ -11,7 +11,8 @@ expect(csv.first).to eq %w( id accreditations alternate_name date_incorporated description email funding_sources legal_status licenses - name tax_id tax_status website) + name tax_id tax_status website + ) end it 'converts arrays to comma-separated strings' do @@ -31,7 +32,8 @@ accreditations: nil, date_incorporated: nil, funding_sources: nil, - licenses: nil) + licenses: nil + ) visit admin_csv_organizations_path(format: 'csv') end diff --git a/spec/features/admin/csv/download_phones_csv_spec.rb b/spec/features/admin/csv/download_phones_csv_spec.rb index dd69fa9ad..df5d1fb12 100644 --- a/spec/features/admin/csv/download_phones_csv_spec.rb +++ b/spec/features/admin/csv/download_phones_csv_spec.rb @@ -9,7 +9,8 @@ :phone, location_id: @location.id, organization_id: @org_id, - service_id: @service.id) + service_id: @service.id + ) visit admin_csv_phones_path(format: 'csv') end @@ -22,6 +23,7 @@ it 'populates phone attribute values' do expect(csv.second).to eq [ @phone.id.to_s, nil, @location.id.to_s, @org_id.to_s, @service.id.to_s, - nil, nil, '200', '650 851-1210', 'voice', nil] + nil, nil, '200', '650 851-1210', 'voice', nil + ] end end diff --git a/spec/features/admin/csv/download_programs_csv_spec.rb b/spec/features/admin/csv/download_programs_csv_spec.rb index a63249347..e09fef4e7 100644 --- a/spec/features/admin/csv/download_programs_csv_spec.rb +++ b/spec/features/admin/csv/download_programs_csv_spec.rb @@ -13,6 +13,7 @@ it 'populates program attribute values' do expect(csv.second).to eq [ @program.id.to_s, @program.organization_id.to_s, 'Also Known As', - 'Collection of Services'] + 'Collection of Services' + ] end end diff --git a/spec/features/admin/csv/download_regular_schedules_csv_spec.rb b/spec/features/admin/csv/download_regular_schedules_csv_spec.rb index 374924eda..54c94250e 100644 --- a/spec/features/admin/csv/download_regular_schedules_csv_spec.rb +++ b/spec/features/admin/csv/download_regular_schedules_csv_spec.rb @@ -16,6 +16,7 @@ it 'formats the date and time values' do expect(csv.second).to eq [ @regular_schedule.id.to_s, @location.id.to_s, nil, 'Sunday', '09:30', - '17:00'] + '17:00' + ] end end diff --git a/spec/features/admin/csv/download_services_csv_spec.rb b/spec/features/admin/csv/download_services_csv_spec.rb index 7b80e9d6d..7dc34bf91 100644 --- a/spec/features/admin/csv/download_services_csv_spec.rb +++ b/spec/features/admin/csv/download_services_csv_spec.rb @@ -8,7 +8,8 @@ @jobs = create(:jobs) @service = create( :service_with_extra_whitespace, - category_ids: [@food.id, @health.id, @jobs.id]) + category_ids: [@food.id, @health.id, @jobs.id] + ) visit admin_csv_services_path(format: 'csv') end @@ -19,7 +20,8 @@ eligibility email fees funding_sources interpretation_services keywords languages name required_documents service_areas status wait_time website - taxonomy_ids) + taxonomy_ids + ) end it 'converts arrays to comma-separated strings' do diff --git a/spec/features/admin/dashboard_spec.rb b/spec/features/admin/dashboard_spec.rb index cf7e4b2b0..bfeb106d6 100644 --- a/spec/features/admin/dashboard_spec.rb +++ b/spec/features/admin/dashboard_spec.rb @@ -24,7 +24,8 @@ it 'does not include a link to Your locations in the navigation' do within '.navbar' do - expect(page).not_to have_link I18n.t('admin.navigation.locations'), href: admin_locations_path + expect(page). + not_to have_link I18n.t('admin.navigation.locations'), href: admin_locations_path end end @@ -114,7 +115,8 @@ it 'includes a link to organizations in the navigation' do within '.navbar' do - expect(page).to have_link I18n.t('admin.buttons.organizations'), href: admin_organizations_path + expect(page). + to have_link I18n.t('admin.buttons.organizations'), href: admin_organizations_path end end @@ -125,15 +127,18 @@ end it 'does not display a link to add a new organization' do - expect(page).not_to have_link I18n.t('admin.buttons.add_organization'), new_admin_organization_path + expect(page). + not_to have_link I18n.t('admin.buttons.add_organization'), href: new_admin_organization_path end it 'does not display a link to add a new location' do - expect(page).to_not have_link I18n.t('admin.buttons.add_location'), new_admin_location_path + expect(page). + to_not have_link I18n.t('admin.buttons.add_location'), href: new_admin_location_path end it 'does not display a link to add a new program' do - expect(page).to_not have_link I18n.t('admin.buttons.add_program'), new_admin_program_path + expect(page). + to_not have_link I18n.t('admin.buttons.add_program'), href: new_admin_program_path end it 'does not display a link to download CSV' do @@ -141,7 +146,8 @@ expect(page). to_not have_link( t('admin.buttons.generate_zip_file'), - admin_csv_all_path) + href: admin_csv_all_path + ) end end @@ -152,15 +158,18 @@ end it 'displays a link to add a new organization' do - expect(page).to have_link I18n.t('admin.buttons.add_organization'), new_admin_organization_path + expect(page). + to have_link I18n.t('admin.buttons.add_organization'), href: new_admin_organization_path end it 'does not display a link to add a new location' do - expect(page).to_not have_link I18n.t('admin.buttons.add_location'), new_admin_location_path + expect(page). + to_not have_link I18n.t('admin.buttons.add_location'), href: new_admin_location_path end it 'does not display a link to add a new program' do - expect(page).to_not have_link I18n.t('admin.buttons.add_program'), new_admin_program_path + expect(page). + to_not have_link I18n.t('admin.buttons.add_program'), href: new_admin_program_path end end @@ -172,18 +181,18 @@ end it 'displays a link to add a new location' do - expect(page).to have_link I18n.t('admin.buttons.add_location'), new_admin_location_path + expect(page).to have_link I18n.t('admin.buttons.add_location'), href: new_admin_location_path end it 'displays a link to add a new program' do - expect(page).to have_link I18n.t('admin.buttons.add_program'), new_admin_program_path + expect(page).to have_link I18n.t('admin.buttons.add_program'), href: new_admin_program_path end it 'displays link to generate zip file' do expect(page).to have_content 'CSV Downloads' expect(page). - to have_link(t('admin.buttons.generate_zip_file'), admin_csv_all_path) + to have_link(t('admin.buttons.generate_zip_file'), href: admin_csv_all_path) end it 'displays a notice while the zip is being generated' do diff --git a/spec/features/admin/organizations/create_organization_spec.rb b/spec/features/admin/organizations/create_organization_spec.rb index 0a1587e88..83bfd708b 100644 --- a/spec/features/admin/organizations/create_organization_spec.rb +++ b/spec/features/admin/organizations/create_organization_spec.rb @@ -116,7 +116,7 @@ select2('second', 'organization_accreditations', multiple: true, tag: true) click_button I18n.t('admin.buttons.create_organization') - organization = Organization.find_by_name('new org') + organization = Organization.find_by(name: 'new org') expect(organization.accreditations).to eq %w(first second) end @@ -127,7 +127,7 @@ select2('second', 'organization_licenses', multiple: true, tag: true) click_button I18n.t('admin.buttons.create_organization') - organization = Organization.find_by_name('new org') + organization = Organization.find_by(name: 'new org') expect(organization.licenses).to eq %w(first second) end end diff --git a/spec/features/admin/organizations/visit_organizations_spec.rb b/spec/features/admin/organizations/visit_organizations_spec.rb index d223597b2..b232e0286 100644 --- a/spec/features/admin/organizations/visit_organizations_spec.rb +++ b/spec/features/admin/organizations/visit_organizations_spec.rb @@ -17,7 +17,8 @@ it 'does not include a link to organizations in the navigation' do within '.navbar' do - expect(page).not_to have_link I18n.t('admin.buttons.organizations'), href: admin_organizations_path + expect(page). + not_to have_link I18n.t('admin.buttons.organizations'), href: admin_organizations_path end end end diff --git a/spec/features/admin/services/create_service_spec.rb b/spec/features/admin/services/create_service_spec.rb index 65318dcb5..772f7fb17 100644 --- a/spec/features/admin/services/create_service_spec.rb +++ b/spec/features/admin/services/create_service_spec.rb @@ -122,7 +122,7 @@ click_button I18n.t('admin.buttons.create_service') click_link 'New VRS Services service' - service = Service.find_by_name('New VRS Services service') + service = Service.find_by(name: 'New VRS Services service') expect(service.keywords).to eq %w(first second) end @@ -132,7 +132,7 @@ click_button I18n.t('admin.buttons.create_service') click_link 'New VRS Services service' - service = Service.find_by_name('New VRS Services service') + service = Service.find_by(name: 'New VRS Services service') expect(service.languages).to eq ['French'] expect(find('#service_languages', visible: false).value).to eq(['French']) end diff --git a/spec/features/admin/services/update_keywords_spec.rb b/spec/features/admin/services/update_keywords_spec.rb index 1aec93b4e..aabec342c 100644 --- a/spec/features/admin/services/update_keywords_spec.rb +++ b/spec/features/admin/services/update_keywords_spec.rb @@ -4,7 +4,8 @@ background do location = create(:location) @service = location.services.create!( - attributes_for(:service).merge(keywords: [])) + attributes_for(:service).merge(keywords: []) + ) login_super_admin visit '/admin/locations/vrs-services' click_link 'Literacy Program' diff --git a/spec/lib/address_extractor_spec.rb b/spec/lib/address_extractor_spec.rb index 5f17a39f4..4c41bd4ff 100644 --- a/spec/lib/address_extractor_spec.rb +++ b/spec/lib/address_extractor_spec.rb @@ -40,8 +40,7 @@ path = Rails.root.join('spec/support/fixtures/invalid_address.csv') expect(AddressExtractor.extract_addresses(path)). to eq [address_hash, - address_hash.merge(id: '2', location_id: '2', city: 'Fairfax') - ] + address_hash.merge(id: '2', location_id: '2', city: 'Fairfax')] end end end diff --git a/spec/lib/file_checker_spec.rb b/spec/lib/file_checker_spec.rb index ae469b9e0..4dc7668ad 100644 --- a/spec/lib/file_checker_spec.rb +++ b/spec/lib/file_checker_spec.rb @@ -190,7 +190,9 @@ with('CSV header alternate_name is required, but is missing.') allow_any_instance_of(Kernel).to receive(:abort). - with('invalid_program_headers.csv was not imported. Please fix the headers and try again.') + with( + 'invalid_program_headers.csv was not imported. Please fix the headers and try again.' + ) checker.validate end diff --git a/spec/lib/holiday_schedule_importer_spec.rb b/spec/lib/holiday_schedule_importer_spec.rb index 339d55178..942a1efd3 100644 --- a/spec/lib/holiday_schedule_importer_spec.rb +++ b/spec/lib/holiday_schedule_importer_spec.rb @@ -3,8 +3,12 @@ describe HolidayScheduleImporter do let(:invalid_content) { Rails.root.join('spec/support/fixtures/invalid_holiday_schedule.csv') } let(:invalid_date) { Rails.root.join('spec/support/fixtures/hs_with_invalid_date.csv') } - let(:valid_content) { Rails.root.join('spec/support/fixtures/valid_location_holiday_schedule.csv') } - let(:valid_service_holiday_schedule) { Rails.root.join('spec/support/fixtures/valid_service_holiday_schedule.csv') } + let(:valid_content) do + Rails.root.join('spec/support/fixtures/valid_location_holiday_schedule.csv') + end + let(:valid_service_holiday_schedule) do + Rails.root.join('spec/support/fixtures/valid_service_holiday_schedule.csv') + end let(:no_parent) { Rails.root.join('spec/support/fixtures/holiday_schedule_with_no_parent.csv') } let(:spelled_out_date) { Rails.root.join('spec/support/fixtures/hs_with_spelled_out_date.csv') } let(:org_with_2_digit_year) { Rails.root.join('spec/support/fixtures/hs_with_2_digit_year.csv') } @@ -39,7 +43,7 @@ let(:content) { invalid_content } errors = ["Line 2: Closes at can't be blank for Holiday Schedule when " \ - 'open on that day'] + "open on that day"] its(:errors) { is_expected.to eq(errors) } end @@ -56,7 +60,7 @@ context 'when the date is not valid' do let(:content) { invalid_date } - errors = ['Line 2: End date 13/27/2014 is not a valid date, ' \ + errors = ["Line 2: End date 13/27/2014 is not a valid date, " \ "End date can't be blank for Holiday Schedule"] its(:errors) { is_expected.to eq(errors) } diff --git a/spec/lib/mail_address_importer_spec.rb b/spec/lib/mail_address_importer_spec.rb index 81ccb4c6f..a79c8735e 100644 --- a/spec/lib/mail_address_importer_spec.rb +++ b/spec/lib/mail_address_importer_spec.rb @@ -2,7 +2,9 @@ describe MailAddressImporter do let(:invalid_content) { Rails.root.join('spec/support/fixtures/invalid_mail_address.csv') } - let(:invalid_location) { Rails.root.join('spec/support/fixtures/invalid_mail_address_location.csv') } + let(:invalid_location) do + Rails.root.join('spec/support/fixtures/invalid_mail_address_location.csv') + end let(:valid_content) { Rails.root.join('spec/support/fixtures/valid_mail_address.csv') } before(:all) do diff --git a/spec/lib/organization_importer_spec.rb b/spec/lib/organization_importer_spec.rb index 0bec4a0fc..89a8cb0a3 100644 --- a/spec/lib/organization_importer_spec.rb +++ b/spec/lib/organization_importer_spec.rb @@ -58,7 +58,7 @@ its(:accreditations) { is_expected.to eq ['BBB', 'State Board of Education'] } its(:alternate_name) { is_expected.to eq 'HFB' } its(:date_incorporated) { is_expected.to eq Date.parse('January 2, 1970') } - its(:description) { is_expected.to eq 'Harvest Food Bank provides fresh produce, dairy, and canned goods to food pantries throughout the city.' } + its(:description) { is_expected.to match 'Harvest Food Bank' } its(:email) { is_expected.to eq 'info@example.org' } its(:funding_sources) { is_expected.to eq %w(Donations Grants) } its(:legal_status) { is_expected.to eq 'Nonprofit' } diff --git a/spec/lib/regular_schedule_importer_spec.rb b/spec/lib/regular_schedule_importer_spec.rb index 1985dbda2..4cd5f3f50 100644 --- a/spec/lib/regular_schedule_importer_spec.rb +++ b/spec/lib/regular_schedule_importer_spec.rb @@ -2,8 +2,12 @@ describe RegularScheduleImporter do let(:invalid_content) { Rails.root.join('spec/support/fixtures/invalid_regular_schedule.csv') } - let(:valid_content) { Rails.root.join('spec/support/fixtures/valid_location_regular_schedule.csv') } - let(:valid_service_regular_schedule) { Rails.root.join('spec/support/fixtures/valid_service_regular_schedule.csv') } + let(:valid_content) do + Rails.root.join('spec/support/fixtures/valid_location_regular_schedule.csv') + end + let(:valid_service_regular_schedule) do + Rails.root.join('spec/support/fixtures/valid_service_regular_schedule.csv') + end let(:no_parent) { Rails.root.join('spec/support/fixtures/regular_schedule_with_no_parent.csv') } before(:all) do diff --git a/spec/models/address_spec.rb b/spec/models/address_spec.rb index d46f2a562..8c8e1fc58 100644 --- a/spec/models/address_spec.rb +++ b/spec/models/address_spec.rb @@ -20,7 +20,9 @@ is_expected.to validate_presence_of(:state_province). with_message(t('errors.messages.invalid_state_province')) end - it { is_expected.to validate_presence_of(:postal_code).with_message("can't be blank for Address") } + it do + is_expected.to validate_presence_of(:postal_code).with_message("can't be blank for Address") + end it { is_expected.to validate_presence_of(:country).with_message("can't be blank for Address") } it do diff --git a/spec/models/location_spec.rb b/spec/models/location_spec.rb index 7d11d00c3..48cd473f4 100644 --- a/spec/models/location_spec.rb +++ b/spec/models/location_spec.rb @@ -36,8 +36,13 @@ it { is_expected.to accept_nested_attributes_for(:holiday_schedules).allow_destroy(true) } it { is_expected.to validate_presence_of(:name).with_message("can't be blank for Location") } - it { is_expected.to validate_presence_of(:description).with_message("can't be blank for Location") } - it { is_expected.to validate_presence_of(:organization).with_message("can't be blank for Location") } + + it do + is_expected.to validate_presence_of(:description).with_message("can't be blank for Location") + end + it do + is_expected.to validate_presence_of(:organization).with_message("can't be blank for Location") + end # Validations it { is_expected.to allow_value('http://monfresh.com').for(:website) } diff --git a/spec/models/mail_address_spec.rb b/spec/models/mail_address_spec.rb index 2c1a5c600..f75087547 100644 --- a/spec/models/mail_address_spec.rb +++ b/spec/models/mail_address_spec.rb @@ -15,14 +15,27 @@ it { is_expected.to belong_to(:location).touch(true) } - it { is_expected.to validate_presence_of(:address_1).with_message("can't be blank for Mail Address") } - it { is_expected.to validate_presence_of(:city).with_message("can't be blank for Mail Address") } + it do + is_expected.to validate_presence_of(:address_1).with_message("can't be blank for Mail Address") + end + + it do + is_expected.to validate_presence_of(:city).with_message("can't be blank for Mail Address") + end + it do is_expected.to validate_presence_of(:state_province). with_message(t('errors.messages.invalid_state_province')) end - it { is_expected.to validate_presence_of(:postal_code).with_message("can't be blank for Mail Address") } - it { is_expected.to validate_presence_of(:country).with_message("can't be blank for Mail Address") } + + it do + is_expected.to validate_presence_of(:postal_code). + with_message("can't be blank for Mail Address") + end + + it do + is_expected.to validate_presence_of(:country).with_message("can't be blank for Mail Address") + end it do is_expected.to validate_length_of(:country). diff --git a/spec/models/program_spec.rb b/spec/models/program_spec.rb index 7c2584452..08dd82239 100644 --- a/spec/models/program_spec.rb +++ b/spec/models/program_spec.rb @@ -9,7 +9,9 @@ it { is_expected.to allow_mass_assignment_of(:alternate_name) } it { is_expected.to validate_presence_of(:name).with_message("can't be blank for Program") } - it { is_expected.to validate_presence_of(:organization).with_message("can't be blank for Program") } + it do + is_expected.to validate_presence_of(:organization).with_message("can't be blank for Program") + end it { is_expected.to belong_to(:organization) } it { is_expected.to have_many(:services).dependent(:destroy) } diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb index e06ae665a..c3156ab42 100644 --- a/spec/models/service_spec.rb +++ b/spec/models/service_spec.rb @@ -36,7 +36,14 @@ it { is_expected.to accept_nested_attributes_for(:phones).allow_destroy(true) } it { is_expected.to validate_presence_of(:name).with_message("can't be blank for Service") } - it { is_expected.to validate_presence_of(:description).with_message("can't be blank for Service") } + it do + is_expected.to validate_presence_of(:description). + with_message("can't be blank for Service") + end + it do + is_expected.to_not validate_presence_of(:application_process). + with_message("can't be blank for Service") + end it { is_expected.to validate_presence_of(:location).with_message("can't be blank for Service") } it { is_expected.to validate_presence_of(:status).with_message("can't be blank for Service") } @@ -71,7 +78,8 @@ describe 'array validations' do it 'raises an error when the attribute is not an array' do service = build( - :service, accepted_payments: 'AAA', required_documents: 'BBB', languages: 'CCC') + :service, accepted_payments: 'AAA', required_documents: 'BBB', languages: 'CCC' + ) service.save expect(service.errors[:accepted_payments].first).to eq('AAA is not an Array.') diff --git a/spec/requests/status_spec.rb b/spec/requests/status_spec.rb index 7654a82e7..b597d09b9 100644 --- a/spec/requests/status_spec.rb +++ b/spec/requests/status_spec.rb @@ -12,7 +12,7 @@ end it 'lists all dependencies' do - expect(json['dependencies']).to eq(%w(Mandrill Postgres)) + expect(json['dependencies']).to eq(%w(SendGrid Postgres)) end it "returns 'ok' status" do @@ -39,7 +39,7 @@ end it 'lists all dependencies' do - expect(json['dependencies']).to eq(%w(Mandrill Postgres)) + expect(json['dependencies']).to eq(%w(SendGrid Postgres)) end it "returns 'updated' attribute set to current time as integer" do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 98776411a..1295cca3a 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -24,6 +24,10 @@ end end + # allows you to run only the failures from the previous run: + # rspec --only-failures + config.example_status_persistence_file_path = './tmp/rspec-examples.txt' + # Print the 10 slowest examples and example groups at the # end of the spec run, to help surface which specs are running # particularly slow. diff --git a/spec/support/admin/controller_helpers.rb b/spec/support/admin/controller_helpers.rb index 89ba998ba..8328ca138 100644 --- a/spec/support/admin/controller_helpers.rb +++ b/spec/support/admin/controller_helpers.rb @@ -4,8 +4,3 @@ def log_in_as_admin(admin) sign_in FactoryGirl.create(admin) end end - -RSpec.configure do |config| - config.include Devise::TestHelpers, type: :controller - config.include ControllerHelpers, type: :controller -end diff --git a/spec/support/default_headers.rb b/spec/support/default_headers.rb index bd9399d35..b128e9123 100644 --- a/spec/support/default_headers.rb +++ b/spec/support/default_headers.rb @@ -3,21 +3,24 @@ def post(uri, params = {}, session = {}) super uri, params.to_json, { 'HTTP_USER_AGENT' => 'Rspec', 'HTTP_X_API_TOKEN' => ENV['ADMIN_APP_TOKEN'], - 'Content-Type' => 'application/json' }.merge(session) + 'Content-Type' => 'application/json' + }.merge(session) end def put(uri, params = {}, session = {}) super uri, params.to_json, { 'HTTP_USER_AGENT' => 'Rspec', 'HTTP_X_API_TOKEN' => ENV['ADMIN_APP_TOKEN'], - 'Content-Type' => 'application/json' }.merge(session) + 'Content-Type' => 'application/json' + }.merge(session) end def patch(uri, params = {}, session = {}) super uri, params.to_json, { 'HTTP_USER_AGENT' => 'Rspec', 'HTTP_X_API_TOKEN' => ENV['ADMIN_APP_TOKEN'], - 'Content-Type' => 'application/json' }.merge(session) + 'Content-Type' => 'application/json' + }.merge(session) end def get(uri, params = {}, session = {}) @@ -27,6 +30,7 @@ def get(uri, params = {}, session = {}) def delete(uri, params = {}, session = {}) super uri, params, { 'HTTP_USER_AGENT' => 'Rspec', - 'HTTP_X_API_TOKEN' => ENV['ADMIN_APP_TOKEN'] }.merge(session) + 'HTTP_X_API_TOKEN' => ENV['ADMIN_APP_TOKEN'] + }.merge(session) end end diff --git a/spec/support/devise.rb b/spec/support/devise.rb index 799989558..10294b81d 100644 --- a/spec/support/devise.rb +++ b/spec/support/devise.rb @@ -1,3 +1,4 @@ RSpec.configure do |config| - config.include Devise::TestHelpers, type: :controller + config.include Devise::Test::ControllerHelpers, type: :controller + config.include ControllerHelpers, type: :controller end diff --git a/spec/support/shared_contexts/rake.rb b/spec/support/shared_contexts/rake.rb index 3bfffea17..1b7564b09 100644 --- a/spec/support/shared_contexts/rake.rb +++ b/spec/support/shared_contexts/rake.rb @@ -12,7 +12,9 @@ def loaded_files_excluding_current_rake_file before do Rake.application = rake - Rake.application.rake_require(task_path, [Rails.root.to_s], loaded_files_excluding_current_rake_file) + Rake.application.rake_require( + task_path, [Rails.root.to_s], loaded_files_excluding_current_rake_file + ) Rake::Task.define_task(:environment) end