ssn_validator 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/History.txt +41 -0
- data/LICENSE +20 -0
- data/PostInstall.txt +29 -0
- data/README.rdoc +98 -0
- data/Rakefile +60 -0
- data/VERSION.yml +5 -0
- data/generators/death_master_file_migration/death_master_file_migration_generator.rb +12 -0
- data/generators/death_master_file_migration/templates/migration.rb +26 -0
- data/generators/ssn_validator_migration/ssn_validator_migration_generator.rb +12 -0
- data/generators/ssn_validator_migration/templates/migration.rb +18 -0
- data/lib/ssn_validator.rb +12 -0
- data/lib/ssn_validator/models/death_master_file.rb +5 -0
- data/lib/ssn_validator/models/death_master_file_loader.rb +235 -0
- data/lib/ssn_validator/models/ssn_high_group_code.rb +5 -0
- data/lib/ssn_validator/models/ssn_high_group_code_loader.rb +87 -0
- data/lib/ssn_validator/models/ssn_validator.rb +94 -0
- data/lib/ssn_validator/ntis.rb +9 -0
- data/lib/tasks/ssn_validator.rake +24 -0
- data/rdoc/classes/DeathMasterFile.html +111 -0
- data/rdoc/classes/DeathMasterFileLoader.html +298 -0
- data/rdoc/classes/SsnHighGroupCode.html +111 -0
- data/rdoc/classes/SsnHighGroupCodeLoader.html +202 -0
- data/rdoc/classes/SsnValidator.html +116 -0
- data/rdoc/classes/SsnValidator/Ntis.html +111 -0
- data/rdoc/classes/SsnValidator/Ssn.html +315 -0
- data/rdoc/created.rid +1 -0
- data/rdoc/files/LICENSE.html +129 -0
- data/rdoc/files/README_rdoc.html +262 -0
- data/rdoc/files/lib/ssn_validator/models/death_master_file_loader_rb.html +112 -0
- data/rdoc/files/lib/ssn_validator/models/death_master_file_rb.html +108 -0
- data/rdoc/files/lib/ssn_validator/models/ssn_high_group_code_loader_rb.html +108 -0
- data/rdoc/files/lib/ssn_validator/models/ssn_high_group_code_rb.html +108 -0
- data/rdoc/files/lib/ssn_validator/models/ssn_validator_rb.html +101 -0
- data/rdoc/files/lib/ssn_validator/ntis_rb.html +101 -0
- data/rdoc/files/lib/ssn_validator_rb.html +113 -0
- data/rdoc/fr_class_index.html +33 -0
- data/rdoc/fr_file_index.html +35 -0
- data/rdoc/fr_method_index.html +37 -0
- data/rdoc/index.html +24 -0
- data/rdoc/rdoc-style.css +208 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/ssn_validator.gemspec +130 -0
- data/test/files/test_dmf_funky_data_load.txt +6 -0
- data/test/files/test_dmf_initial_load.txt +5 -0
- data/test/files/test_dmf_update_load.txt +5 -0
- data/test/files/valid_csv_from_funky_data_file.txt +6 -0
- data/test/mocks/test/death_master_file_loader.rb +40 -0
- data/test/test_death_master_file_loader.rb +113 -0
- data/test/test_helper.rb +62 -0
- data/test/test_ssn_high_group_code_loader.rb +22 -0
- data/test/test_ssn_validator.rb +85 -0
- metadata +145 -0
data/.gitignore
ADDED
data/History.txt
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
== 1.0.4 2010-02-05
|
2
|
+
|
3
|
+
* 1 bug fixes:
|
4
|
+
* The ssa website changed it's process for the most recent month. Modified the rake task
|
5
|
+
to determine the most recent month loaded and bring it up to date.
|
6
|
+
|
7
|
+
== 1.0.3 2009-04-24
|
8
|
+
|
9
|
+
* 2 minor enhancement:
|
10
|
+
* Added method #death_master_file_record to SsnValidator::Ssn to return the actual dmf record if the SSN exists
|
11
|
+
* Changed the method #death_master_file_hit? to simply return true or false.
|
12
|
+
|
13
|
+
== 1.0.2 2009-04-24
|
14
|
+
|
15
|
+
* 1 minor enhancement:
|
16
|
+
* Using jeweler gem to create gemspec and rdoc files
|
17
|
+
|
18
|
+
== 1.0.1 2009-04-23
|
19
|
+
|
20
|
+
* 2 bug fixes:
|
21
|
+
* Fixed dmf mysql load error when single quote is in a data file record.
|
22
|
+
* Fixed ssn_validator:update_data rake task that broke on the last build.
|
23
|
+
|
24
|
+
== 1.0.0 2009-04-22
|
25
|
+
|
26
|
+
* 1 major enhancement:
|
27
|
+
* Added the death master file to determine if the ssn belongs to the deceased.
|
28
|
+
|
29
|
+
* 1 bug fix:
|
30
|
+
* Fixed bug where an error was thrown if the ssn area has not been assigned yet.
|
31
|
+
|
32
|
+
== 0.1.2 2009-04-15
|
33
|
+
|
34
|
+
* 2 minor enhancements:
|
35
|
+
* Added rdoc files
|
36
|
+
* Updated documentation
|
37
|
+
|
38
|
+
== 0.1.0 2009-04-14
|
39
|
+
|
40
|
+
* 1 major enhancement:
|
41
|
+
* Initial release
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Kevin Tyll
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/PostInstall.txt
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
For more information on ssn_validator, see http://kevintyll.github.com/ssn_validator/
|
3
|
+
|
4
|
+
* To create the necessary db migration, from the command line, run:
|
5
|
+
script/generate ssn_validator_migration
|
6
|
+
* Require the gem in your environment.rb file in the Rails::Initializer block:
|
7
|
+
config.gem 'kevintyll-ssn_validator', :lib => 'ssn_validator'
|
8
|
+
* To load your table with the current SSN data, from the command line, run:
|
9
|
+
rake ssn_validator:update_data
|
10
|
+
* The SSN data is updated monthly, so you'll want to run this rake task monthly to keep your validations accurate.
|
11
|
+
* If you've purchased the death master file data, create the death_master_files migration:
|
12
|
+
script/generate death_master_file_migration
|
13
|
+
* To load the dmf files you receive from ntis:
|
14
|
+
rake ssn_validator:death_master_file:load_file PATH='path/to/file' AS_OF='2009-03-01'
|
15
|
+
* You'll need to pass in the full path to where the file is on disk. You'll also need
|
16
|
+
to pass in the date this file's data are as of in the format yyyy-mm-dd.
|
17
|
+
* This task must be used to load the initial file you receive from ntis on CD. It can optionally be used
|
18
|
+
to load the monthly update files you download from the website. If you manually download the update files,
|
19
|
+
you do not need to add your user name and password to the environment.rb file. For a more automated approach
|
20
|
+
to loading the update files, add your user name and password to the environment.rb file and use the 2nd rake task.
|
21
|
+
* To load the monthly updates from the ntis website:
|
22
|
+
* Add your user_name and password to the environment.rb file
|
23
|
+
SsnValidator::Ntis.user_name = 'REPLACE WITH YOUR dmf.ntis.gov USER NAME'
|
24
|
+
SsnValidator::Ntis.password = 'REPLACE WITH YOUR dmf.ntis.gov PASSWORD'
|
25
|
+
* Run the rake task:
|
26
|
+
rake ssn_validator:death_master_file:update_data
|
27
|
+
* This rake task will determine the most recent file that has been loaded, and loads all subsequent files in order
|
28
|
+
from the dmf.ntis.gov website.
|
29
|
+
* The death master file data is updated monthly, so you'll want to run this rake task monthly to keep your validations accurate.
|
data/README.rdoc
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
= ssn_validator
|
2
|
+
|
3
|
+
* http://kevintyll.github.com/ssn_validator
|
4
|
+
* http://www.drexel-labs.com
|
5
|
+
|
6
|
+
== DESCRIPTION:
|
7
|
+
|
8
|
+
ssn_validator is a ruby gem that validates whether an SSN has likely been issued or not.
|
9
|
+
What exactly does that mean "likely" been issued? We can't tell for sure if an SSN belongs
|
10
|
+
to a particular person, but knowing the "rules"[http://www.socialsecurity.gov/employer/ssnweb.htm]
|
11
|
+
on how the social security administration assigns numbers, we can determine whether a number
|
12
|
+
has ever been issued or not.
|
13
|
+
|
14
|
+
ssn_validator started as a need for the company I work for, Clarity Services Inc. Incredibly, we
|
15
|
+
couldn't find an existing gem or service that provided what we needed. Since we were going to have
|
16
|
+
to roll our own solution, we decided to create a gem out of it and share it with the community. Much
|
17
|
+
thanks goes to the management at Clarity Services Inc. for allowing this code to be open sourced.
|
18
|
+
|
19
|
+
|
20
|
+
== FEATURES/PROBLEMS:
|
21
|
+
|
22
|
+
* What it can do:
|
23
|
+
Validates the likelyhood that an SSN has been issued to someone.
|
24
|
+
Checks the Death Master File if the SSN belongs to a dead person. This will require you to purchase the dmf data from https://dmf.ntis.gov
|
25
|
+
|
26
|
+
* What it cannot do:
|
27
|
+
Validate that an SSN actually belongs to a particular person.
|
28
|
+
|
29
|
+
* What it's planned to do:
|
30
|
+
Determine when an SSN was issued...if i can find the historical data. This can be used to further validate an SSN by comparing it to a Date of Birth.
|
31
|
+
|
32
|
+
== SYNOPSIS:
|
33
|
+
|
34
|
+
* Just instantiate the object with an SSN.
|
35
|
+
ssn = SsnValidator::Ssn.new('123-45-6789')
|
36
|
+
|
37
|
+
* Then check if it's valid
|
38
|
+
ssn.valid?
|
39
|
+
ssn.death_master_file_hit?
|
40
|
+
|
41
|
+
ssn.valid? only checks to see if the number itself is valid. Check the death_master_file_hit? method
|
42
|
+
as well to verify the ssn does not belong the the deceased.
|
43
|
+
|
44
|
+
The death_master_file_hit? method will only return true of false if you have purchased the dmf data and
|
45
|
+
loaded it into your database. There is a generator and rake task to facilitate this, but you'll have
|
46
|
+
to purchase the data yourself at https://dmf.ntis.gov.
|
47
|
+
|
48
|
+
* You can check the errors array to see why it's not valid.
|
49
|
+
ssn.errors
|
50
|
+
|
51
|
+
== REQUIREMENTS:
|
52
|
+
|
53
|
+
* Rails 2.0.0 or greater
|
54
|
+
|
55
|
+
== INSTALL:
|
56
|
+
|
57
|
+
* To install the gem:
|
58
|
+
sudo gem install kevintyll-ssn_validator
|
59
|
+
* To create the necessary db migration, from the command line, run:
|
60
|
+
script/generate ssn_validator_migration
|
61
|
+
* Require the gem in your environment.rb file in the Rails::Initializer block:
|
62
|
+
config.gem 'kevintyll-ssn_validator', :lib => 'ssn_validator'
|
63
|
+
* To load your table with the current SSN data, from the command line, run:
|
64
|
+
rake ssn_validator:update_data
|
65
|
+
|
66
|
+
* The SSN data is updated monthly, so you'll want to run this rake task monthly to keep your validations accurate.
|
67
|
+
|
68
|
+
* If you've purchased the death master file data, create the death_master_files migration:
|
69
|
+
script/generate death_master_file_migration
|
70
|
+
* To load the dmf files you receive from ntis:
|
71
|
+
rake ssn_validator:death_master_file:load_file PATH='path/to/file' AS_OF='2009-03-01'
|
72
|
+
|
73
|
+
* You'll need to pass in the full path to where the file is on disk. You'll also need
|
74
|
+
to pass in the date this file's data are as of in the format yyyy-mm-dd.
|
75
|
+
|
76
|
+
* This task must be used to load the initial file you receive from ntis on CD. It can optionally be used
|
77
|
+
to load the monthly update files you download from the website. If you manually download the update files,
|
78
|
+
you do not need to add your user name and password to the environment.rb file. For a more automated approach
|
79
|
+
to loading the update files, add your user name and password to the environment.rb file and use the 2nd rake task.
|
80
|
+
|
81
|
+
* To load the monthly updates from the ntis website:
|
82
|
+
* Add your user_name and password to the environment.rb file
|
83
|
+
|
84
|
+
SsnValidator::Ntis.user_name = 'REPLACE WITH YOUR dmf.ntis.gov USER NAME'
|
85
|
+
SsnValidator::Ntis.password = 'REPLACE WITH YOUR dmf.ntis.gov PASSWORD'
|
86
|
+
|
87
|
+
* Run the rake task:
|
88
|
+
|
89
|
+
rake ssn_validator:death_master_file:update_data
|
90
|
+
|
91
|
+
* This rake task will determine the most recent file that has been loaded, and loads all subsequent files in order
|
92
|
+
from the dmf.ntis.gov website.
|
93
|
+
|
94
|
+
* The death master file data is updated monthly, so you'll want to run this rake task monthly to keep your validations accurate.
|
95
|
+
|
96
|
+
== Copyright
|
97
|
+
|
98
|
+
Copyright (c) 2009 Kevin Tyll. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gemspec|
|
7
|
+
gemspec.name = "ssn_validator"
|
8
|
+
gemspec.author = "Kevin Tyll"
|
9
|
+
gemspec.email = "kevintyll@gmail.com"
|
10
|
+
gemspec.homepage = %q{http://kevintyll.git.com/ssn_validator}
|
11
|
+
gemspec.summary = "Validates whether an SSN has likely been issued or not."
|
12
|
+
gemspec.description = "Validates whether an SSN has likely been issued or not."
|
13
|
+
gemspec.post_install_message = File.readlines("PostInstall.txt").join("")
|
14
|
+
end
|
15
|
+
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'rake/testtask'
|
23
|
+
Rake::TestTask.new(:test) do |test|
|
24
|
+
test.libs << 'test'
|
25
|
+
test.pattern = 'test/test_*.rb'
|
26
|
+
test.verbose = true
|
27
|
+
end
|
28
|
+
|
29
|
+
begin
|
30
|
+
require 'rcov/rcovtask'
|
31
|
+
Rcov::RcovTask.new do |test|
|
32
|
+
test.libs << 'test'
|
33
|
+
test.pattern = 'test/**/*_test.rb'
|
34
|
+
test.verbose = true
|
35
|
+
end
|
36
|
+
rescue LoadError
|
37
|
+
task :rcov do
|
38
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
if File.exist?('VERSION.yml')
|
48
|
+
config = YAML.load(File.read('VERSION.yml'))
|
49
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
50
|
+
else
|
51
|
+
version = ""
|
52
|
+
end
|
53
|
+
|
54
|
+
rdoc.rdoc_dir = 'rdoc'
|
55
|
+
rdoc.title = "ssn_validator #{version}"
|
56
|
+
rdoc.rdoc_files.include('README*')
|
57
|
+
rdoc.rdoc_files.include('LICENSE*')
|
58
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
59
|
+
end
|
60
|
+
|
data/VERSION.yml
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
class DeathMasterFileMigrationGenerator < Rails::Generator::Base
|
2
|
+
def manifest
|
3
|
+
record do |m|
|
4
|
+
#m.directory File.join('db')
|
5
|
+
m.migration_template 'migration.rb', 'db/migrate'
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def file_name
|
10
|
+
"create_death_master_file_table"
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class CreateDeathMasterFileTable < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
create_table :death_master_files do |t|
|
5
|
+
t.string :social_security_number
|
6
|
+
t.string :last_name
|
7
|
+
t.string :name_suffix
|
8
|
+
t.string :first_name
|
9
|
+
t.string :middle_name
|
10
|
+
t.string :verify_proof_code
|
11
|
+
t.date :date_of_death
|
12
|
+
t.date :date_of_birth
|
13
|
+
t.string :state_of_residence
|
14
|
+
t.string :last_known_zip_residence
|
15
|
+
t.string :last_known_zip_payment
|
16
|
+
t.time_stamps
|
17
|
+
t.date :as_of
|
18
|
+
end
|
19
|
+
add_index :death_master_files, :social_security_number, :unique => true
|
20
|
+
add_index :death_master_files, :as_of
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.down
|
24
|
+
drop_table :death_master_files
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class CreateSsnValidatorTables < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
create_table :ssn_high_group_codes do |t|
|
5
|
+
t.date :as_of
|
6
|
+
t.string :area
|
7
|
+
t.string :group
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
|
11
|
+
add_index :ssn_high_group_codes, [:area]
|
12
|
+
add_index :ssn_high_group_codes, [:area, :as_of]
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.down
|
16
|
+
drop_table :ssn_high_group_codes
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
require 'ssn_validator/models/ssn_high_group_code'
|
5
|
+
require 'ssn_validator/models/ssn_high_group_code_loader'
|
6
|
+
require 'ssn_validator/models/ssn_validator'
|
7
|
+
require 'ssn_validator/models/death_master_file'
|
8
|
+
require 'ssn_validator/models/death_master_file_loader'
|
9
|
+
require 'rake'
|
10
|
+
|
11
|
+
# Load rake file
|
12
|
+
import "#{File.dirname(__FILE__)}/tasks/ssn_validator.rake"
|
@@ -0,0 +1,235 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
require 'activerecord'
|
4
|
+
require 'active_record/connection_adapters/mysql_adapter'
|
5
|
+
require 'ssn_validator/ntis'
|
6
|
+
|
7
|
+
class DeathMasterFileLoader
|
8
|
+
|
9
|
+
# path_or_url is the full path to the file to load on disk, or the url of an update file.
|
10
|
+
# as_of is a string in the formatt YYYY-MM-DD for which the file data is accurate.
|
11
|
+
def initialize(path_or_url,file_as_of)
|
12
|
+
@file_path_or_url = path_or_url
|
13
|
+
@file_as_of = file_as_of
|
14
|
+
valid?
|
15
|
+
end
|
16
|
+
|
17
|
+
def valid?
|
18
|
+
raise(ArgumentError, "path_or_url not specified") unless @file_path_or_url
|
19
|
+
raise(ArgumentError, "as_of not specified") unless @file_as_of
|
20
|
+
max_as_of = DeathMasterFile.maximum(:as_of)
|
21
|
+
raise(ArgumentError, "A more recent file has already been processed. DB as_of date #{max_as_of}") if max_as_of && (max_as_of >= @file_as_of.to_date)
|
22
|
+
|
23
|
+
if File.exists?(@file_path_or_url)
|
24
|
+
@download_file = File.open(@file_path_or_url)
|
25
|
+
elsif URI.parse(@file_path_or_url).kind_of?(URI::HTTP)
|
26
|
+
@download_file = get_file_from_web
|
27
|
+
else
|
28
|
+
raise(Errno::ENOENT, @file_path_or_url)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def load_file
|
33
|
+
|
34
|
+
if DeathMasterFile.connection.kind_of?(ActiveRecord::ConnectionAdapters::MysqlAdapter)
|
35
|
+
puts "Converting file to csv format for Mysql import. This could take several minutes."
|
36
|
+
|
37
|
+
csv_file = convert_file_to_csv
|
38
|
+
|
39
|
+
bulk_mysql_update(csv_file)
|
40
|
+
else
|
41
|
+
active_record_file_load
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_file_from_web
|
47
|
+
uri = URI.parse(@file_path_or_url)
|
48
|
+
|
49
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
50
|
+
request.basic_auth(SsnValidator::Ntis.user_name,SsnValidator::Ntis.password)
|
51
|
+
|
52
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
53
|
+
http.use_ssl = (uri.port == 443)
|
54
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
55
|
+
|
56
|
+
response = http.request(request)
|
57
|
+
|
58
|
+
raise(ArgumentError, "Invalid URL: #{@file_path_or_url}") if response.kind_of?(Net::HTTPNotFound)
|
59
|
+
raise(ArgumentError, "Authorization Required: Invalid username or password. Set the variables SsnValidator::Ntis.user_name and SsnValidator::Ntis.password in your environment.rb file.") if response.kind_of?(Net::HTTPUnauthorized)
|
60
|
+
|
61
|
+
return response.body
|
62
|
+
end
|
63
|
+
|
64
|
+
#Loads all the update files from dmf.ntis.gov.
|
65
|
+
#It starts with the last file loaded, and loads each
|
66
|
+
#missing file in sequence up to the current file.
|
67
|
+
def self.load_update_files_from_web
|
68
|
+
max_as_of = DeathMasterFile.maximum(:as_of)
|
69
|
+
run_file_date = max_as_of.beginning_of_month.next_month
|
70
|
+
last_file_date = Date.today.beginning_of_month
|
71
|
+
while run_file_date <= last_file_date
|
72
|
+
url = "https://dmf.ntis.gov/dmldata/monthly/MA#{run_file_date.strftime("%y%m%d")}"
|
73
|
+
puts "Loading file #{url}"
|
74
|
+
DeathMasterFileLoader.new(url,run_file_date.strftime("%Y-%m-%d")).load_file
|
75
|
+
run_file_date += 1.month
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
# Processes 28 million rows in 23 minutes. Input file 2.6GB output: 2.9GB.
|
82
|
+
# Used to convert a packed fixed-length file into csv for mysql import.
|
83
|
+
def convert_file_to_csv
|
84
|
+
|
85
|
+
csv_file = Tempfile.new("dmf") # create temp file for converted csv formmat.
|
86
|
+
|
87
|
+
|
88
|
+
start = Time.now
|
89
|
+
timenow = start.to_s(:db)
|
90
|
+
|
91
|
+
@delete_ssns = []
|
92
|
+
|
93
|
+
@download_file.each_with_index do |line,i|
|
94
|
+
action = record_action(line)
|
95
|
+
attributes_hash = text_to_hash(line)
|
96
|
+
if action == 'D'
|
97
|
+
#keep track of all the records to delete. We'll delete at the end all at once.
|
98
|
+
@delete_ssns << attributes_hash[:social_security_number]
|
99
|
+
else
|
100
|
+
# empty field for id to be generated by mysql.
|
101
|
+
newline = "``," +
|
102
|
+
# social_security_number
|
103
|
+
"`#{attributes_hash[:social_security_number]}`," +
|
104
|
+
# last_name
|
105
|
+
"`#{attributes_hash[:last_name]}`," +
|
106
|
+
# name_suffix
|
107
|
+
"`#{attributes_hash[:name_suffix]}`," +
|
108
|
+
# first_name
|
109
|
+
"`#{attributes_hash[:first_name]}`," +
|
110
|
+
# middle_name
|
111
|
+
"`#{attributes_hash[:middle_name]}`," +
|
112
|
+
# verify_proof_code
|
113
|
+
"`#{attributes_hash[:verify_proof_code]}`," +
|
114
|
+
# date_of_death - need YYYY-MM-DD.
|
115
|
+
"`#{attributes_hash[:date_of_death]}`," +
|
116
|
+
# date_of_birth - need YYYY-MM-DD.
|
117
|
+
"`#{attributes_hash[:date_of_birth]}`," +
|
118
|
+
# state_of_residence - must be code between 01 and 65 or else nil.
|
119
|
+
"`#{attributes_hash[:state_of_residence]}`," +
|
120
|
+
# last_known_zip_residence
|
121
|
+
"`#{attributes_hash[:last_known_zip_residence]}`," +
|
122
|
+
# last_known_zip_payment
|
123
|
+
"`#{attributes_hash[:last_known_zip_payment]}`," +
|
124
|
+
# created_at
|
125
|
+
"`#{timenow}`," +
|
126
|
+
# updated_at
|
127
|
+
"`#{timenow}`," +
|
128
|
+
# as_of
|
129
|
+
"`#{attributes_hash[:as_of]}`" +"\n"
|
130
|
+
|
131
|
+
csv_file.syswrite newline
|
132
|
+
puts "#{i} records processed." if (i % 25000 == 0) && (i > 0)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
puts "File conversion ran for #{(Time.now - start) / 60} minutes."
|
136
|
+
return csv_file
|
137
|
+
end
|
138
|
+
|
139
|
+
#Uses active record to load the data.
|
140
|
+
#The benefit is it will work on any database.
|
141
|
+
#The downside is it's really slow.
|
142
|
+
def active_record_file_load
|
143
|
+
puts 'Importing file into database. This could take many minutes.'
|
144
|
+
|
145
|
+
@download_file.each_with_index do |line,i|
|
146
|
+
action = record_action(line)
|
147
|
+
attributes_hash = text_to_hash(line)
|
148
|
+
if action == 'D'
|
149
|
+
DeathMasterFile.destroy_all(['social_security_number = ?', attributes_hash[:social_security_number]])
|
150
|
+
else
|
151
|
+
|
152
|
+
# empty field for id to be generated by mysql.
|
153
|
+
# record_hash = {
|
154
|
+
# :as_of => @file_as_of.to_date.to_s(:db),
|
155
|
+
# :social_security_number => parse_record(line,:social_security_number),
|
156
|
+
# :last_name => parse_record(line,:last_name),
|
157
|
+
# :name_suffix => parse_record(line,:name_suffix),
|
158
|
+
# :first_name => parse_record(line,:first_name),
|
159
|
+
# :middle_name => parse_record(line,:middle_name),
|
160
|
+
# :verify_proof_code => parse_record(line,:verify_proof_code),
|
161
|
+
# :date_of_death => parse_record(line,:date_of_death),
|
162
|
+
# :date_of_birth => parse_record(line,:date_of_birth),
|
163
|
+
# # - must be code between 01 and 65 or else nil.
|
164
|
+
# :state_of_residence=> parse_record(line,:state_of_residence=),
|
165
|
+
# :last_known_zip_residence => parse_record(line,:last_known_zip_residence),
|
166
|
+
# :last_known_zip_payment => parse_record(line,:last_known_zip_payment)
|
167
|
+
# }
|
168
|
+
|
169
|
+
case action
|
170
|
+
when '',nil,' '
|
171
|
+
#the initial file leaves this field blank
|
172
|
+
DeathMasterFile.create(attributes_hash)
|
173
|
+
else
|
174
|
+
dmf = DeathMasterFile.find_by_social_security_number(attributes_hash[:social_security_number])
|
175
|
+
if dmf
|
176
|
+
#a record already exists, update this record
|
177
|
+
dmf.update_attributes(attributes_hash)
|
178
|
+
else
|
179
|
+
#create a new record
|
180
|
+
DeathMasterFile.create(attributes_hash)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
puts "#{i} records processed." if (i % 2500 == 0) && (i > 0)
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
puts "Import complete."
|
190
|
+
end
|
191
|
+
|
192
|
+
# For mysql, use:
|
193
|
+
# LOAD DATA LOCAL INFILE 'ssdm1.csv' INTO TABLE death_master_files FIELDS TERMINATED BY ',' ENCLOSED BY "'" LINES TERMINATED BY '\n';
|
194
|
+
# This is a much faster way of loading large amounts of data into mysql. For information on the LOAD DATA command
|
195
|
+
# see http://dev.mysql.com/doc/refman/5.1/en/load-data.html
|
196
|
+
def bulk_mysql_update(csv_file)
|
197
|
+
puts "Importing into Mysql..."
|
198
|
+
|
199
|
+
#delete all the 'D' records
|
200
|
+
DeathMasterFile.delete_all(:social_security_number => @delete_ssns)
|
201
|
+
|
202
|
+
#This will insert new records, and replace records with existing ssns.
|
203
|
+
#This only works because there is a unique index on social_security_number.
|
204
|
+
mysql_command = <<-TEXT
|
205
|
+
LOAD DATA LOCAL INFILE '#{csv_file.path}' REPLACE INTO TABLE death_master_files FIELDS TERMINATED BY ',' ENCLOSED BY "`" LINES TERMINATED BY '\n';
|
206
|
+
TEXT
|
207
|
+
|
208
|
+
DeathMasterFile.connection.execute(mysql_command)
|
209
|
+
puts "Mysql import complete."
|
210
|
+
|
211
|
+
end
|
212
|
+
|
213
|
+
def record_action(line)
|
214
|
+
line[0,1].to_s.strip
|
215
|
+
end
|
216
|
+
|
217
|
+
def text_to_hash(line)
|
218
|
+
|
219
|
+
{:as_of => @file_as_of.to_date.to_s(:db),
|
220
|
+
:social_security_number => line[1,9].to_s.strip,
|
221
|
+
:last_name => line[10,20].to_s.strip,
|
222
|
+
:name_suffix => line[30,4].to_s.strip,
|
223
|
+
:first_name => line[34,15].to_s.strip,
|
224
|
+
:middle_name => line[49,15].to_s.strip,
|
225
|
+
:verify_proof_code => line[64,1].to_s.strip,
|
226
|
+
:date_of_death => (Date.strptime(line[65,8].to_s.strip,'%m%d%Y') rescue nil),
|
227
|
+
:date_of_birth => (Date.strptime(line[73,8].to_s.strip,'%m%d%Y') rescue nil),
|
228
|
+
# - must be code between 01 and 65 or else nil.
|
229
|
+
:state_of_residence => (line[81,2].to_s.strip.between?('01', '65') ? line[81,2].to_s.strip : nil),
|
230
|
+
:last_known_zip_residence => line[83,5].to_s.strip,
|
231
|
+
:last_known_zip_payment => line[88,5].to_s.strip}
|
232
|
+
rescue Exception => e
|
233
|
+
puts '@@@@@@@@@ Error = ' + e.message + ': ' + line.inspect
|
234
|
+
end
|
235
|
+
end
|