diff --git a/Makefile b/Makefile index f1ae74a5..872316a4 100644 --- a/Makefile +++ b/Makefile @@ -35,6 +35,10 @@ db_create: db_migrate: docker-compose run ${RAILS_CONTAINER} rake db:migrate +.PHONY: db_rollback +db_rollback: + docker-compose run ${RAILS_CONTAINER} rake db:rollback + .PHONY: test test: bg docker-compose run operationcode-psql bash -c "while ! psql --host=operationcode-psql --username=postgres -c 'SELECT 1'; do sleep 5; done;" diff --git a/app/controllers/api/v1/users_controller.rb b/app/controllers/api/v1/users_controller.rb index 3d481fa5..500ce84e 100644 --- a/app/controllers/api/v1/users_controller.rb +++ b/app/controllers/api/v1/users_controller.rb @@ -42,7 +42,7 @@ def by_location private def user_params - params.require(:user).permit(:email, :zip, :password, :first_name, :last_name, :mentor, :slack_name, :verified) + params.require(:user).permit(:email, :zip, :password, :first_name, :last_name, :mentor, :slack_name, :verified, :state) end end end diff --git a/app/models/user.rb b/app/models/user.rb index be299c94..f82ed42a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -3,7 +3,16 @@ class User < ApplicationRecord # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable - geocoded_by :zip + + geocoded_by :zip do |user, results| + geocoded_object = results.first + + if geocoded_object.present? + user.latitude = geocoded_object.latitude + user.longitude = geocoded_object.longitude + user.state = geocoded_object.state_code + end + end # These attributes are what we send to sendgrid as custom fields SENDGRID_ATTRIBUTES = %w[first_name last_name email] diff --git a/db/migrate/20170720215043_add_state_to_user.rb b/db/migrate/20170720215043_add_state_to_user.rb new file mode 100644 index 00000000..4bd96758 --- /dev/null +++ b/db/migrate/20170720215043_add_state_to_user.rb @@ -0,0 +1,5 @@ +class AddStateToUser < ActiveRecord::Migration[5.0] + def change + add_column :users, :state, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 1f994fa1..6b5e75d6 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170701194821) do +ActiveRecord::Schema.define(version: 20170720215043) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -154,6 +154,7 @@ t.string "timezone" t.text "bio" t.boolean "verified", default: false, null: false + t.string "state" t.index ["email"], name: "index_users_on_email", unique: true, using: :btree t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree end diff --git a/lib/tasks/users.rake b/lib/tasks/users.rake new file mode 100644 index 00000000..12245463 --- /dev/null +++ b/lib/tasks/users.rake @@ -0,0 +1,36 @@ +namespace :users do + desc "Sets the user's :state based on user's :zip, for any any where user.state == nil" + task populate_states: :environment do + # https://developers.google.com/maps/documentation/geocoding/usage-limits + GEOCODING_DAILY_MAX = 2500 + GEOCODING_PER_S_MAX = 50 + + users = User.where.not(latitude: nil, longitude: nil).where(state: nil).limit(GEOCODING_DAILY_MAX) + user_count = users.count + + return "0 eligible users to be updated" unless users.present? + p "#{user_count} users are eligible to be updated." + + users.in_batches(of: GEOCODING_PER_S_MAX).each_with_index do |batch, batch_index| + batch.each_with_index do |user, index| + p "Updating #{(batch_index * GEOCODING_PER_S_MAX) + index + 1} of #{user_count}" + + begin + results = Geocoder.search([user.latitude, user.longitude]).try(:first) + + raise "Could not geocode User id #{user.id}" unless results.present? + + user.update! state: results.state_code + rescue => e + p "When adding the :state for User id #{user.id}, experienced this error: #{e}" + Rails.logger.info "When adding the :state for User id #{user.id}, experienced this error: #{e}" + end + end + + sleep 2 + end + + remaining = User.where.not(latitude: nil, longitude: nil).where(state: nil).count + p "#{remaining} users left to be updated. Task can be reran in 24 hours." + end +end diff --git a/test/factories/users.rb b/test/factories/users.rb index bc2c8feb..4877285c 100644 --- a/test/factories/users.rb +++ b/test/factories/users.rb @@ -13,6 +13,7 @@ timezone 'EST' mentor false verified false + state { Faker::Address.state_abbr } factory :mentor do mentor true diff --git a/test/models/user_test.rb b/test/models/user_test.rb index 7e627916..b2dbb47d 100644 --- a/test/models/user_test.rb +++ b/test/models/user_test.rb @@ -41,6 +41,7 @@ def setup u.update_attributes(zip: '80203') assert_equal 20.7143528, u.latitude assert_equal -174.0059731, u.longitude + assert_equal 'CO', u.state end test 'only geocodes if zip is updated' do