validation_auditor 0.2.1 → 1.0.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: df3fdbc82541c85c7c13bddebe3a18a4a7b8d50e
4
- data.tar.gz: 698944970c971bf99d30eeec61782f75496e6c3d
3
+ metadata.gz: c2e09a496b0f32341947809d1ab6f87d2216472f
4
+ data.tar.gz: 8631c7538cde8a75ebc52520b00616e75d9c1805
5
5
  SHA512:
6
- metadata.gz: bf9fd4135a3a550911658e1670a1bfa16080503dbca7a683c0da183da04553149cb4a0d65267430dd2267b2e1a3e525ff659b88eeea7328e42dbdba7e5cae96a
7
- data.tar.gz: 0b93eba5ec3321b8fb09cf5b9e31ea695312a9daf08a31ceb637a083649c770a618b17f555d6adf4a299cbf18185154ca3c7ee63a543eda015de669724417352
6
+ metadata.gz: f41005ee1a54818d95c261d04f3531d36ab3011b89914d935e47bb19c3499120108e6618cb03fe2cf63db929914e50ea0f03c154e36c84b6ea178016dd627dd6
7
+ data.tar.gz: 35c20fbf0e1d8d00b86c8190107e0cbc7b6dd9bf605479bc60df49ec539b6cf4c781500b058644820ebb2c8f9ce68a2c666c879a13be9b4e5d5925e1e7bc263c
data/.travis.yml CHANGED
@@ -3,7 +3,13 @@ rvm:
3
3
  - "1.9.3"
4
4
  - "2.0.0"
5
5
  - "2.1.2"
6
+ - "2.1.3"
7
+ - "2.1.4"
6
8
  gemfile:
7
- - gemfiles/rails_3_2.Gemfile
8
- - gemfiles/rails_4_0.Gemfile
9
- - gemfiles/rails_4_1.Gemfile
9
+ - gemfiles/rails_3_2.gemfile
10
+ - gemfiles/rails_4_0.gemfile
11
+ - gemfiles/rails_4_1.gemfile
12
+ addons:
13
+ code_climate:
14
+ repo_token:
15
+ secure: "JmFIrG06+Df5MZoksMx/H/g1Z/oe8cZaJMP6zYSiZ5uz122t6NF6Rs1JPDJeXP2+YMwsuSp7Ge45arFytGwysSSvY2iGGlA+om2IDekMsqqhsVYbo1rFzbM+H/RfrPUU2mY6MYkAmHzIBQvYUAWQ4s3qbHaCXXsdEyoilc99uaU="
data/Appraisals ADDED
@@ -0,0 +1,19 @@
1
+ # Copyright © 2014, Watu
2
+
3
+ appraise "rails-3_2" do
4
+ gem "activerecord", "~> 3.2.0"
5
+ gem "actionpack", "~> 3.2.0"
6
+ gem "railties", "~> 3.2.0"
7
+ end
8
+
9
+ appraise "rails-4_0" do
10
+ gem "activerecord", "~> 4.0.0"
11
+ gem "actionpack", "~> 4.0.0"
12
+ gem "railties", "~> 4.0.0"
13
+ end
14
+
15
+ appraise "rails-4_1" do
16
+ gem "activerecord", "~> 4.1.0"
17
+ gem "actionpack", "~> 4.1.0"
18
+ gem "railties", "~> 4.1.0"
19
+ end
data/CHANGELOG.md CHANGED
@@ -1,15 +1,19 @@
1
- ## validation_auditor 0.2.1 (Sep 5, 2014) ##
1
+ Authoritative changelog in README.md.
2
2
 
3
- * When cleaning params to save them as yaml, also clean each element of arrays.
3
+ ## validation_auditor 1.0.0 (Nov 17, 2014)
4
+ - Started testing Ruby 2.1.3 and 2.1.4.
5
+ - Refactoring to make code more readable (increased code climate to 4.0).
6
+ - Marked internal methods as private.
7
+ - Improved documentation.
4
8
 
5
- ## validation_auditor 0.2.0 (Jul 23, 2014) ##
9
+ ## validation_auditor 0.2.1 (Sep 5, 2014) ##
10
+ - When cleaning params to save them as yaml, also clean each element of arrays.
6
11
 
7
- * Respect the filter_parameters configuration from Rails.
12
+ ## validation_auditor 0.2.0 (Jul 23, 2014) ##
13
+ - Respect the filter_parameters configuration from Rails.
8
14
 
9
15
  ## validation_auditor 0.1.1 (Jul 23, 2014) ##
10
-
11
- * Don't crash in the presence of file uploads when reporting validation errors.
16
+ - Don't crash in the presence of file uploads when reporting validation errors.
12
17
 
13
18
  ## validation_auditor 0.1.0 (January 8, 2014) ##
14
-
15
- * Everything
19
+ - Everything.
data/Gemfile CHANGED
@@ -3,16 +3,4 @@
3
3
 
4
4
  source "https://rubygems.org"
5
5
 
6
- gem "assert_difference"
7
- gem "bundler", "~> 1.3"
8
- gem "coveralls", require: false
9
- gem "minitest"
10
- gem "minitest-reporters"
11
- gem "minitest-rails"
12
- gem "rake"
13
- gem "simplecov"
14
- gem "shoulda"
15
- gem "sqlite3"
16
- gem "activerecord", "~> 3.2.0"
17
- gem "actionpack", "~> 3.2.0"
18
- gem "railties", "~> 3.2.0"
6
+ gemspec
data/README.md CHANGED
@@ -3,7 +3,9 @@
3
3
  [![Build Status](https://travis-ci.org/watu/validation_auditor.png?branch=master)](https://travis-ci.org/watu/validation_auditor)
4
4
  [![Coverage Status](https://coveralls.io/repos/watu/validation_auditor/badge.png?branch=master)](https://coveralls.io/r/watu/validation_auditor?branch=master)
5
5
  [![Code Climate](https://codeclimate.com/github/watu/validation_auditor.png)](https://codeclimate.com/github/watu/validation_auditor)
6
+ [![Inline docs](http://inch-ci.org/github/watu/validation_auditor.png?branch=master)](http://inch-ci.org/github/watu/validation_auditor)
6
7
  [![Gem Version](https://badge.fury.io/rb/validation_auditor.png)](http://badge.fury.io/rb/validation_auditor)
8
+ [![Dependency Status](https://gemnasium.com/watu/validation_auditor.svg)](https://gemnasium.com/watu/validation_auditor)
7
9
 
8
10
  A user visits your web app, tries to do something with it but it fails due to a validation error. Generally, the
9
11
  validation is stopping a user from doing something bad, but every now and then it's the validation that is bad. Don't
@@ -52,6 +54,43 @@ If you enable validation audit on the controller, by calling `audit_validation_e
52
54
  then you'll also get params, url and user agent in the validation audit. This breaks the model-controller separation, so
53
55
  it's optional.
54
56
 
57
+ If for some reason saving a validation audit fails, the exception will be left to propagate into your application so
58
+ that no exception is silently swallowed. You may want to not let a secondary system, like auditing, to stop your
59
+ application for working (depending on how critical auditing is for you). If that's the case, you can define an
60
+ exception handler that can report in whatever fashion you normally report exceptions to your dev team or silently
61
+ swallow the exception. This may or may not work in Rails < 4.
62
+
63
+ ValidationAuditor.exception_handler = lambda do |e, va|
64
+ puts "When trying to save validation audit #{va}, exception #{e} was encountered."
65
+ end
66
+
67
+ ## Users
68
+
69
+ This gem is being used by:
70
+
71
+ - [Watu](https://watuapp.com)
72
+ - You? please, let us know if you are using this gem.
73
+
74
+ ## Changelog
75
+
76
+ ### validation_auditor 1.0.0 (Nov 17, 2014)
77
+ - Started testing Ruby 2.1.3 and 2.1.4.
78
+ - Refactoring to make code more readable (increased code climate to 4.0).
79
+ - Marked internal methods as private.
80
+ - Improved documentation.
81
+
82
+ ### validation_auditor 0.2.1 (Sep 5, 2014)
83
+ - When cleaning params to save them as yaml, also clean each element of arrays.
84
+
85
+ ### validation_auditor 0.2.0 (Jul 23, 2014)
86
+ - Respect the filter_parameters configuration from Rails.
87
+
88
+ ### validation_auditor 0.1.1 (Jul 23, 2014)
89
+ - Don't crash in the presence of file uploads when reporting validation errors.
90
+
91
+ ### validation_auditor 0.1.0 (January 8, 2014)
92
+ - Everything.
93
+
55
94
  ## Contributing
56
95
 
57
96
  1. Fork it
data/Rakefile CHANGED
@@ -1,6 +1,8 @@
1
1
  # encoding: UTF-8
2
2
  # Copyright © 2014, Watu
3
3
 
4
+ require "rubygems"
5
+ require "bundler/setup"
4
6
  require "bundler/gem_tasks"
5
7
 
6
8
  require "rake/testtask"
@@ -0,0 +1,9 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 3.2.0"
6
+ gem "actionpack", "~> 3.2.0"
7
+ gem "railties", "~> 3.2.0"
8
+
9
+ gemspec :path => "../"
@@ -0,0 +1,141 @@
1
+ PATH
2
+ remote: ../
3
+ specs:
4
+ validation_auditor (1.0.0)
5
+ actionpack (>= 3.0.0)
6
+ activerecord (>= 3.0.0)
7
+ railties (>= 3.0.0)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ actionpack (3.2.19)
13
+ activemodel (= 3.2.19)
14
+ activesupport (= 3.2.19)
15
+ builder (~> 3.0.0)
16
+ erubis (~> 2.7.0)
17
+ journey (~> 1.0.4)
18
+ rack (~> 1.4.5)
19
+ rack-cache (~> 1.2)
20
+ rack-test (~> 0.6.1)
21
+ sprockets (~> 2.2.1)
22
+ activemodel (3.2.19)
23
+ activesupport (= 3.2.19)
24
+ builder (~> 3.0.0)
25
+ activerecord (3.2.19)
26
+ activemodel (= 3.2.19)
27
+ activesupport (= 3.2.19)
28
+ arel (~> 3.0.2)
29
+ tzinfo (~> 0.3.29)
30
+ activesupport (3.2.19)
31
+ i18n (~> 0.6, >= 0.6.4)
32
+ multi_json (~> 1.0)
33
+ ansi (1.4.3)
34
+ appraisal (1.0.2)
35
+ bundler
36
+ rake
37
+ thor (>= 0.14.0)
38
+ arel (3.0.3)
39
+ assert_difference (0.5.0)
40
+ builder (3.0.4)
41
+ codeclimate-test-reporter (0.4.1)
42
+ simplecov (>= 0.7.1, < 1.0.0)
43
+ coveralls (0.7.1)
44
+ multi_json (~> 1.3)
45
+ rest-client
46
+ simplecov (>= 0.7)
47
+ term-ansicolor
48
+ thor
49
+ docile (1.1.5)
50
+ erubis (2.7.0)
51
+ hashie (3.3.1)
52
+ hike (1.2.3)
53
+ i18n (0.6.11)
54
+ journey (1.0.4)
55
+ json (1.8.1)
56
+ metaclass (0.0.4)
57
+ mime-types (1.25.1)
58
+ minitest (4.7.5)
59
+ minitest-rails (1.0.1)
60
+ minitest (~> 4.7)
61
+ minitest-test (~> 1.0)
62
+ railties (>= 3.0, < 4.1)
63
+ minitest-reporters (0.14.24)
64
+ ansi
65
+ builder
66
+ minitest (>= 2.12, < 5.0)
67
+ powerbar
68
+ minitest-test (1.1.0)
69
+ minitest (~> 4.0)
70
+ mocha (1.1.0)
71
+ metaclass (~> 0.0.1)
72
+ multi_json (1.10.1)
73
+ netrc (0.7.7)
74
+ powerbar (1.0.11)
75
+ ansi (~> 1.4.0)
76
+ hashie (>= 1.1.0)
77
+ rack (1.4.5)
78
+ rack-cache (1.2)
79
+ rack (>= 0.4)
80
+ rack-ssl (1.3.4)
81
+ rack
82
+ rack-test (0.6.2)
83
+ rack (>= 1.0)
84
+ railties (3.2.19)
85
+ actionpack (= 3.2.19)
86
+ activesupport (= 3.2.19)
87
+ rack-ssl (~> 1.3.2)
88
+ rake (>= 0.8.7)
89
+ rdoc (~> 3.4)
90
+ thor (>= 0.14.6, < 2.0)
91
+ rake (10.3.2)
92
+ rdoc (3.12.2)
93
+ json (~> 1.4)
94
+ rest-client (1.7.2)
95
+ mime-types (>= 1.16, < 3.0)
96
+ netrc (~> 0.7)
97
+ shoulda (3.5.0)
98
+ shoulda-context (~> 1.0, >= 1.0.1)
99
+ shoulda-matchers (>= 1.4.1, < 3.0)
100
+ shoulda-context (1.2.1)
101
+ shoulda-matchers (2.7.0)
102
+ activesupport (>= 3.0.0)
103
+ simplecov (0.9.0)
104
+ docile (~> 1.1.0)
105
+ multi_json
106
+ simplecov-html (~> 0.8.0)
107
+ simplecov-html (0.8.0)
108
+ sprockets (2.2.2)
109
+ hike (~> 1.2)
110
+ multi_json (~> 1.0)
111
+ rack (~> 1.0)
112
+ tilt (~> 1.1, != 1.3.0)
113
+ sqlite3 (1.3.9)
114
+ term-ansicolor (1.3.0)
115
+ tins (~> 1.0)
116
+ thor (0.19.1)
117
+ tilt (1.4.1)
118
+ tins (1.3.2)
119
+ tzinfo (0.3.41)
120
+
121
+ PLATFORMS
122
+ ruby
123
+
124
+ DEPENDENCIES
125
+ actionpack (~> 3.2.0)
126
+ activerecord (~> 3.2.0)
127
+ appraisal
128
+ assert_difference
129
+ bundler
130
+ codeclimate-test-reporter
131
+ coveralls
132
+ minitest
133
+ minitest-rails
134
+ minitest-reporters
135
+ mocha
136
+ railties (~> 3.2.0)
137
+ rake
138
+ shoulda
139
+ simplecov
140
+ sqlite3
141
+ validation_auditor!
@@ -0,0 +1,9 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 4.0.0"
6
+ gem "actionpack", "~> 4.0.0"
7
+ gem "railties", "~> 4.0.0"
8
+
9
+ gemspec :path => "../"
@@ -0,0 +1,125 @@
1
+ PATH
2
+ remote: ../
3
+ specs:
4
+ validation_auditor (1.0.0)
5
+ actionpack (>= 3.0.0)
6
+ activerecord (>= 3.0.0)
7
+ railties (>= 3.0.0)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ actionpack (4.0.9)
13
+ activesupport (= 4.0.9)
14
+ builder (~> 3.1.0)
15
+ erubis (~> 2.7.0)
16
+ rack (~> 1.5.2)
17
+ rack-test (~> 0.6.2)
18
+ activemodel (4.0.9)
19
+ activesupport (= 4.0.9)
20
+ builder (~> 3.1.0)
21
+ activerecord (4.0.9)
22
+ activemodel (= 4.0.9)
23
+ activerecord-deprecated_finders (~> 1.0.2)
24
+ activesupport (= 4.0.9)
25
+ arel (~> 4.0.0)
26
+ activerecord-deprecated_finders (1.0.3)
27
+ activesupport (4.0.9)
28
+ i18n (~> 0.6, >= 0.6.9)
29
+ minitest (~> 4.2)
30
+ multi_json (~> 1.3)
31
+ thread_safe (~> 0.1)
32
+ tzinfo (~> 0.3.37)
33
+ ansi (1.4.3)
34
+ appraisal (1.0.2)
35
+ bundler
36
+ rake
37
+ thor (>= 0.14.0)
38
+ arel (4.0.2)
39
+ assert_difference (0.5.0)
40
+ builder (3.1.4)
41
+ codeclimate-test-reporter (0.4.1)
42
+ simplecov (>= 0.7.1, < 1.0.0)
43
+ coveralls (0.7.1)
44
+ multi_json (~> 1.3)
45
+ rest-client
46
+ simplecov (>= 0.7)
47
+ term-ansicolor
48
+ thor
49
+ docile (1.1.5)
50
+ erubis (2.7.0)
51
+ hashie (3.3.1)
52
+ i18n (0.6.11)
53
+ metaclass (0.0.4)
54
+ mime-types (1.25.1)
55
+ minitest (4.7.5)
56
+ minitest-rails (1.0.1)
57
+ minitest (~> 4.7)
58
+ minitest-test (~> 1.0)
59
+ railties (>= 3.0, < 4.1)
60
+ minitest-reporters (0.14.24)
61
+ ansi
62
+ builder
63
+ minitest (>= 2.12, < 5.0)
64
+ powerbar
65
+ minitest-test (1.1.0)
66
+ minitest (~> 4.0)
67
+ mocha (1.1.0)
68
+ metaclass (~> 0.0.1)
69
+ multi_json (1.10.1)
70
+ netrc (0.7.7)
71
+ powerbar (1.0.11)
72
+ ansi (~> 1.4.0)
73
+ hashie (>= 1.1.0)
74
+ rack (1.5.2)
75
+ rack-test (0.6.2)
76
+ rack (>= 1.0)
77
+ railties (4.0.9)
78
+ actionpack (= 4.0.9)
79
+ activesupport (= 4.0.9)
80
+ rake (>= 0.8.7)
81
+ thor (>= 0.18.1, < 2.0)
82
+ rake (10.3.2)
83
+ rest-client (1.7.2)
84
+ mime-types (>= 1.16, < 3.0)
85
+ netrc (~> 0.7)
86
+ shoulda (3.5.0)
87
+ shoulda-context (~> 1.0, >= 1.0.1)
88
+ shoulda-matchers (>= 1.4.1, < 3.0)
89
+ shoulda-context (1.2.1)
90
+ shoulda-matchers (2.7.0)
91
+ activesupport (>= 3.0.0)
92
+ simplecov (0.9.0)
93
+ docile (~> 1.1.0)
94
+ multi_json
95
+ simplecov-html (~> 0.8.0)
96
+ simplecov-html (0.8.0)
97
+ sqlite3 (1.3.9)
98
+ term-ansicolor (1.3.0)
99
+ tins (~> 1.0)
100
+ thor (0.19.1)
101
+ thread_safe (0.3.4)
102
+ tins (1.3.2)
103
+ tzinfo (0.3.41)
104
+
105
+ PLATFORMS
106
+ ruby
107
+
108
+ DEPENDENCIES
109
+ actionpack (~> 4.0.0)
110
+ activerecord (~> 4.0.0)
111
+ appraisal
112
+ assert_difference
113
+ bundler
114
+ codeclimate-test-reporter
115
+ coveralls
116
+ minitest
117
+ minitest-rails
118
+ minitest-reporters
119
+ mocha
120
+ railties (~> 4.0.0)
121
+ rake
122
+ shoulda
123
+ simplecov
124
+ sqlite3
125
+ validation_auditor!
@@ -0,0 +1,9 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 4.1.0"
6
+ gem "actionpack", "~> 4.1.0"
7
+ gem "railties", "~> 4.1.0"
8
+
9
+ gemspec :path => "../"
@@ -0,0 +1,122 @@
1
+ PATH
2
+ remote: ../
3
+ specs:
4
+ validation_auditor (1.0.0)
5
+ actionpack (>= 3.0.0)
6
+ activerecord (>= 3.0.0)
7
+ railties (>= 3.0.0)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ actionpack (4.1.5)
13
+ actionview (= 4.1.5)
14
+ activesupport (= 4.1.5)
15
+ rack (~> 1.5.2)
16
+ rack-test (~> 0.6.2)
17
+ actionview (4.1.5)
18
+ activesupport (= 4.1.5)
19
+ builder (~> 3.1)
20
+ erubis (~> 2.7.0)
21
+ activemodel (4.1.5)
22
+ activesupport (= 4.1.5)
23
+ builder (~> 3.1)
24
+ activerecord (4.1.5)
25
+ activemodel (= 4.1.5)
26
+ activesupport (= 4.1.5)
27
+ arel (~> 5.0.0)
28
+ activesupport (4.1.5)
29
+ i18n (~> 0.6, >= 0.6.9)
30
+ json (~> 1.7, >= 1.7.7)
31
+ minitest (~> 5.1)
32
+ thread_safe (~> 0.1)
33
+ tzinfo (~> 1.1)
34
+ ansi (1.4.3)
35
+ appraisal (1.0.2)
36
+ bundler
37
+ rake
38
+ thor (>= 0.14.0)
39
+ arel (5.0.1.20140414130214)
40
+ assert_difference (0.5.0)
41
+ builder (3.2.2)
42
+ codeclimate-test-reporter (0.4.1)
43
+ simplecov (>= 0.7.1, < 1.0.0)
44
+ coveralls (0.7.1)
45
+ multi_json (~> 1.3)
46
+ rest-client
47
+ simplecov (>= 0.7)
48
+ term-ansicolor
49
+ thor
50
+ docile (1.1.5)
51
+ erubis (2.7.0)
52
+ i18n (0.6.11)
53
+ json (1.8.1)
54
+ metaclass (0.0.4)
55
+ mime-types (1.25.1)
56
+ minitest (5.4.1)
57
+ minitest-rails (2.1.0)
58
+ minitest (~> 5.4)
59
+ railties (~> 4.1)
60
+ minitest-reporters (1.0.5)
61
+ ansi
62
+ builder
63
+ minitest (>= 5.0)
64
+ ruby-progressbar
65
+ mocha (1.1.0)
66
+ metaclass (~> 0.0.1)
67
+ multi_json (1.10.1)
68
+ netrc (0.7.7)
69
+ rack (1.5.2)
70
+ rack-test (0.6.2)
71
+ rack (>= 1.0)
72
+ railties (4.1.5)
73
+ actionpack (= 4.1.5)
74
+ activesupport (= 4.1.5)
75
+ rake (>= 0.8.7)
76
+ thor (>= 0.18.1, < 2.0)
77
+ rake (10.3.2)
78
+ rest-client (1.7.2)
79
+ mime-types (>= 1.16, < 3.0)
80
+ netrc (~> 0.7)
81
+ ruby-progressbar (1.5.1)
82
+ shoulda (3.5.0)
83
+ shoulda-context (~> 1.0, >= 1.0.1)
84
+ shoulda-matchers (>= 1.4.1, < 3.0)
85
+ shoulda-context (1.2.1)
86
+ shoulda-matchers (2.7.0)
87
+ activesupport (>= 3.0.0)
88
+ simplecov (0.9.0)
89
+ docile (~> 1.1.0)
90
+ multi_json
91
+ simplecov-html (~> 0.8.0)
92
+ simplecov-html (0.8.0)
93
+ sqlite3 (1.3.9)
94
+ term-ansicolor (1.3.0)
95
+ tins (~> 1.0)
96
+ thor (0.19.1)
97
+ thread_safe (0.3.4)
98
+ tins (1.3.2)
99
+ tzinfo (1.2.2)
100
+ thread_safe (~> 0.1)
101
+
102
+ PLATFORMS
103
+ ruby
104
+
105
+ DEPENDENCIES
106
+ actionpack (~> 4.1.0)
107
+ activerecord (~> 4.1.0)
108
+ appraisal
109
+ assert_difference
110
+ bundler
111
+ codeclimate-test-reporter
112
+ coveralls
113
+ minitest
114
+ minitest-rails
115
+ minitest-reporters
116
+ mocha
117
+ railties (~> 4.1.0)
118
+ rake
119
+ shoulda
120
+ simplecov
121
+ sqlite3
122
+ validation_auditor!
@@ -5,13 +5,14 @@ require "rails/generators"
5
5
  require "rails/generators/migration"
6
6
  require "rails/generators/active_record"
7
7
 
8
- # Extend the DelayedJobGenerator so that it creates an AR migration
9
8
  module ValidationAuditor
9
+ # Generator to be able to run `rails generate validation_auditor:install`
10
10
  class InstallGenerator < Rails::Generators::Base
11
11
  include Rails::Generators::Migration
12
12
 
13
13
  self.source_paths << File.join(File.dirname(__FILE__), "templates")
14
14
 
15
+ # Create migration files.
15
16
  def create_migration_file
16
17
  migration_template "migration.rb", "db/migrate/create_validation_audits.rb"
17
18
  end
@@ -1,4 +1,6 @@
1
+ # Create table to store validation errors.
1
2
  class CreateValidationAudits < ActiveRecord::Migration
3
+ # Create table to store validation errors.
2
4
  def up
3
5
  create_table :validation_audits do |t|
4
6
  t.integer :record_id
@@ -6,6 +6,9 @@ require "active_record"
6
6
  require "action_controller"
7
7
 
8
8
  module ValidationAuditor
9
+ mattr_accessor :exception_handler
10
+
11
+ # Validation audit model.
9
12
  class ValidationAudit < ActiveRecord::Base
10
13
  belongs_to :record, :polymorphic => true
11
14
 
@@ -14,33 +17,77 @@ module ValidationAuditor
14
17
  serialize :data, Hash
15
18
  serialize :params, Hash
16
19
 
17
-
18
20
  if respond_to? :attr_accessible # For Rails < 4 or Rails >= 4 with attr_accessible added by a third party library.
19
21
  begin
20
22
  attr_accessible
21
23
  rescue RuntimeError # Rails 4 raises a RuntimeError when you call attr_accessible, but we still want to call it in case you added attr_accessible gem.
22
24
  end
23
25
  end
26
+
27
+ # If available, add controller data to this validation audit. This will include:
28
+ # - params
29
+ # - url
30
+ # - user_agent
31
+ #
32
+ # @see ValidationAuditor::Controller::ClassMethods#audit_validation_errors
33
+ def add_controller
34
+ if ValidationAuditor::Controller.request.present?
35
+ request = ValidationAuditor::Controller.request
36
+ self.params = ValidationAuditor::Controller.clean_params(request.filtered_parameters)
37
+ self.url = request.url
38
+ self.user_agent = request.env["HTTP_USER_AGENT"]
39
+ end
40
+ end
24
41
  end
25
42
 
43
+ # Controller side of audit validations.
44
+ #
45
+ # @see ValidationAuditor::Controller::ClassMethods#audit_validation_errors
26
46
  module Controller
27
47
  extend ActiveSupport::Concern
28
48
 
49
+ # Class methods accessible in controllers (classes inheriting from ActionController::Base).
29
50
  module ClassMethods
51
+ # Enable validation audits for this controller. This is not essential to be able to audit validations, but it
52
+ # enhances the reports with:
53
+ # - params
54
+ # - url
55
+ # - user_agent
56
+ #
57
+ # For example:
58
+ #
59
+ # class BlogsController < ApplicationController
60
+ # audit_validation_errors
61
+ # end
62
+ #
63
+ # @see ValidationAuditor::Model::ClassMethods#audit_validation_errors
30
64
  def audit_validation_errors
31
65
  before_filter :make_request_auditable
32
66
  end
33
67
  end
34
68
 
69
+ private
70
+
71
+ # Make the request available for later adding some of its details to the validation audit. This method is
72
+ # automatically called as before_filter when you enable validation audits for a controller.
73
+ #
74
+ # @see ValidationAuditor::Controller::ClassMethods#audit_validation_errors
35
75
  def make_request_auditable
36
76
  Thread.current[:validation_auditor_request] = self.request
37
77
  end
38
78
 
79
+ # Getter for the request for the audit.
80
+ #
81
+ # @see ValidationAuditor::Controller::ClassMethods#audit_validation_errors
39
82
  def self.request
40
83
  Thread.current[:validation_auditor_request]
41
84
  end
42
85
 
43
86
  # Clean parameters before storing them in the database.
87
+ #
88
+ # This method gets sure we don't have unserializable values, like UploadedFiles.
89
+ # @param param [Hash] Hash of params as created by Rails
90
+ # @return [Hash] A hash without those problematic values.
44
91
  def self.clean_params(param)
45
92
  if param.is_a? Hash
46
93
  cleaned_params = {}
@@ -58,33 +105,50 @@ module ValidationAuditor
58
105
  end
59
106
  end
60
107
 
108
+ # Model side of audit validations.
109
+ #
110
+ # @see ValidationAuditor::Model::ClassMethods#audit_validation_errors
61
111
  module Model
62
112
  extend ActiveSupport::Concern
63
113
 
114
+ # Class methods accessible in models (classes inheriting from ActiveRecord::Base).
64
115
  module ClassMethods
116
+ # Enable validation audits for a model. For example:
117
+ #
118
+ # class Blog < ActiveRecord::Base
119
+ # audit_validation_errors
120
+ # end
121
+ #
122
+ # @see ValidationAuditor::Controller::ClassMethods#audit_validation_errors
65
123
  def audit_validation_errors
66
124
  after_rollback :audit_validation
67
125
  end
68
126
  end
69
127
 
128
+ private
129
+
130
+ # Perform the actual audit validation. This method is automatically called on rollback when you enable validation on
131
+ # a model.
132
+ #
133
+ # @see ValidationAuditor::Model::ClassMethods#audit_validation_errors
70
134
  def audit_validation
71
- if !errors.empty? # We don't use :valid? to avoid re-running validations
72
- va = ValidationAudit.new
73
- va.failures = self.errors.to_hash
74
- va.failure_messages = self.errors.full_messages.to_a
75
- va.data = self.attributes
76
- if self.new_record? # For new records
77
- va.record_type = self.class.name # we only store the class's name.
78
- else
79
- va.record = self
80
- end
81
- if ValidationAuditor::Controller.request.present?
82
- request = ValidationAuditor::Controller.request
83
- va.params = ValidationAuditor::Controller.clean_params(request.filtered_parameters)
84
- va.url = request.url
85
- va.user_agent = request.env["HTTP_USER_AGENT"]
86
- end
87
- va.save
135
+ return if errors.empty? # We don't use :valid? to avoid re-running validations
136
+ validatio_audit = ValidationAudit.new
137
+ validatio_audit.failures = self.errors.to_hash
138
+ validatio_audit.failure_messages = self.errors.full_messages.to_a
139
+ validatio_audit.data = self.attributes
140
+ if self.new_record? # For new records
141
+ validatio_audit.record_type = self.class.name # we only store the class's name.
142
+ else
143
+ validatio_audit.record = self
144
+ end
145
+ validatio_audit.add_controller
146
+ validatio_audit.save!
147
+ rescue Exception => e
148
+ if ValidationAuditor.exception_handler.nil?
149
+ raise # If there's no exception handler, just re-raise the exception.
150
+ else
151
+ ValidationAuditor.exception_handler.call(e, validatio_audit)
88
152
  end
89
153
  end
90
154
  end
@@ -2,5 +2,5 @@
2
2
  # Copyright © 2014, Watu
3
3
 
4
4
  module ValidationAuditor
5
- VERSION = "0.2.1"
5
+ VERSION = "1.0.0"
6
6
  end
data/test/model_test.rb CHANGED
@@ -2,6 +2,7 @@
2
2
  # Copyright © 2014, Watu
3
3
 
4
4
  require_relative "test_helper"
5
+ require "rails/version" # Required to access Rails::VERSION::MAJOR
5
6
 
6
7
  class ModelTest < ActiveSupport::TestCase
7
8
  should "not create a validation audit when no errors occurs" do
@@ -45,10 +46,52 @@ class ModelTest < ActiveSupport::TestCase
45
46
  end
46
47
  end
47
48
 
48
- should "not create a validation audit for non audited models" do
49
- assert_difference "ValidationAuditor::ValidationAudit.count" => 0 do
50
- NonAuditedRecord.create(name: "John Doe") # Missing email.
49
+ if Rails::VERSION::MAJOR >= 4 # Prior to Rails 4, it seems exceptions in after_rollback were silently swallowed: https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/6064-exceptions-from-after_commit-and-after_rollback-from-observers-are-quietly-swallowed
50
+ should "let exceptions propagate if no handler has been set up" do
51
+ ValidationAuditor::ValidationAudit.any_instance.expects(:save!).raises(Exception, "Something went wrong saving the audit")
52
+ assert_raises Exception do
53
+ AuditedRecord.create(name: "John Doe")
54
+ end
55
+ end
56
+ end
57
+
58
+ should "not let exceptions propagate when a handler has been set up" do
59
+ exception_message = "Something went wrong saving the audit"
60
+ exception_handler_called = false
61
+ ValidationAuditor.exception_handler = lambda do |e, va|
62
+ assert e.is_a?(Exception)
63
+ assert_equal e.message, exception_message
64
+ assert va.is_a?(ValidationAuditor::ValidationAudit)
65
+ exception_handler_called = true
66
+ end
67
+ ValidationAuditor::ValidationAudit.any_instance.stubs(:save!).raises(Exception, exception_message)
68
+
69
+ AuditedRecord.create(name: "John Doe")
70
+
71
+ assert exception_handler_called
72
+
73
+ # teardown
74
+ ValidationAuditor.exception_handler = nil
75
+ end
76
+
77
+ should "add controller information if possible" do
78
+ params = {"hello" => "world", "universe" => "42"}
79
+ url = "https://example.com/hello/world"
80
+ env = {"HTTP_USER_AGENT" => "NCSA_Mosaic/2.0"}
81
+ request = mock("request") do
82
+ stubs(:present?).returns(true)
83
+ stubs(:filtered_parameters).returns(params)
84
+ stubs(:url).returns(url)
85
+ stubs(:env).returns(env)
51
86
  end
87
+ ValidationAuditor::Controller.stubs(:request).returns(request)
88
+ assert_difference "ValidationAuditor::ValidationAudit.count" => +1 do
89
+ AuditedRecord.create(name: "John Doe") # Missing email.
90
+ end
91
+ audit = ValidationAuditor::ValidationAudit.order(:id).last
92
+ assert_equal params, audit.params
93
+ assert_equal url, audit.url
94
+ assert_equal env["HTTP_USER_AGENT"], audit.user_agent
52
95
  end
53
96
  end
54
97
 
data/test/test_helper.rb CHANGED
@@ -10,15 +10,15 @@ SimpleCov.start do
10
10
  add_filter "/test/"
11
11
  end
12
12
  Coveralls.wear! # Comment out this line to have the local coverage generated.
13
+ require "codeclimate-test-reporter"
14
+ CodeClimate::TestReporter.start
13
15
 
14
16
  require "minitest/autorun"
15
17
  require "minitest/reporters"
16
18
  MiniTest::Reporters.use!
17
-
18
19
  require "active_support/test_case"
19
20
  require "action_controller"
20
21
  require "action_controller/test_case"
21
-
22
22
  require "shoulda"
23
23
  require "shoulda-context"
24
24
  require "shoulda-matchers"
@@ -33,7 +33,7 @@ require "logger"
33
33
  ActiveRecord::Base.logger = Logger.new(STDERR)
34
34
  ActiveRecord::Base.logger.level = Logger::WARN
35
35
  ActiveRecord::Base.configurations = {"sqlite3" => {adapter: "sqlite3", database: ":memory:"}}
36
- ActiveRecord::Base.establish_connection("sqlite3")
36
+ ActiveRecord::Base.establish_connection(:sqlite3)
37
37
 
38
38
  # Models setup.
39
39
  require "validation_auditor"
@@ -21,7 +21,21 @@ Gem::Specification.new do |spec|
21
21
  spec.require_paths = ["lib"]
22
22
 
23
23
  spec.required_ruby_version = ">= 1.9.3"
24
- spec.add_dependency "activerecord", "> 3.2.0"
25
- spec.add_dependency "actionpack", "> 3.2.0"
26
- spec.add_dependency "railties", "> 3.2.0"
24
+ spec.add_dependency "activerecord", ">= 3.0.0"
25
+ spec.add_dependency "actionpack", ">= 3.0.0"
26
+ spec.add_dependency "railties", ">= 3.0.0"
27
+
28
+ spec.add_development_dependency "appraisal"
29
+ spec.add_development_dependency "assert_difference"
30
+ spec.add_development_dependency "bundler"
31
+ spec.add_development_dependency "codeclimate-test-reporter"
32
+ spec.add_development_dependency "coveralls" #, require: false
33
+ spec.add_development_dependency "minitest"
34
+ spec.add_development_dependency "minitest-reporters"
35
+ spec.add_development_dependency "minitest-rails"
36
+ spec.add_development_dependency "mocha"
37
+ spec.add_development_dependency "rake"
38
+ spec.add_development_dependency "simplecov"
39
+ spec.add_development_dependency "shoulda"
40
+ spec.add_development_dependency "sqlite3"
27
41
  end
metadata CHANGED
@@ -1,57 +1,239 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: validation_auditor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - J. Pablo Fernández
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-05 00:00:00.000000000 Z
11
+ date: 2014-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 3.2.0
19
+ version: 3.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 3.2.0
26
+ version: 3.0.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: actionpack
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 3.2.0
33
+ version: 3.0.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 3.2.0
40
+ version: 3.0.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: railties
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: 3.2.0
47
+ version: 3.0.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: 3.2.0
54
+ version: 3.0.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: appraisal
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: assert_difference
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: bundler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: codeclimate-test-reporter
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: coveralls
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: minitest
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: minitest-reporters
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: minitest-rails
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: mocha
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: rake
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: simplecov
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
209
+ - !ruby/object:Gem::Dependency
210
+ name: shoulda
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ">="
214
+ - !ruby/object:Gem::Version
215
+ version: '0'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
223
+ - !ruby/object:Gem::Dependency
224
+ name: sqlite3
225
+ requirement: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - ">="
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - ">="
235
+ - !ruby/object:Gem::Version
236
+ version: '0'
55
237
  description: Log validation errors to the database for later inspection.
56
238
  email:
57
239
  - pupeno@watuapp.com
@@ -61,14 +243,18 @@ extra_rdoc_files: []
61
243
  files:
62
244
  - ".gitignore"
63
245
  - ".travis.yml"
246
+ - Appraisals
64
247
  - CHANGELOG.md
65
248
  - Gemfile
66
249
  - LICENSE.txt
67
250
  - README.md
68
251
  - Rakefile
69
- - gemfiles/rails_3_2.Gemfile
70
- - gemfiles/rails_4_0.Gemfile
71
- - gemfiles/rails_4_1.Gemfile
252
+ - gemfiles/rails_3_2.gemfile
253
+ - gemfiles/rails_3_2.gemfile.lock
254
+ - gemfiles/rails_4_0.gemfile
255
+ - gemfiles/rails_4_0.gemfile.lock
256
+ - gemfiles/rails_4_1.gemfile
257
+ - gemfiles/rails_4_1.gemfile.lock
72
258
  - lib/generators/validation_auditor/install_generator.rb
73
259
  - lib/generators/validation_auditor/templates/migration.rb
74
260
  - lib/validation_auditor.rb
@@ -98,7 +284,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
284
  version: '0'
99
285
  requirements: []
100
286
  rubyforge_project:
101
- rubygems_version: 2.2.2
287
+ rubygems_version: 2.4.3
102
288
  signing_key:
103
289
  specification_version: 4
104
290
  summary: Log validation errors to the database for later inspection.
@@ -1,18 +0,0 @@
1
- # encoding: UTF-8
2
- # Copyright © 2013, 2014, Watu
3
-
4
- source "https://rubygems.org"
5
-
6
- gem "assert_difference"
7
- gem "bundler", "~> 1.3"
8
- gem "coveralls", require: false
9
- gem "minitest"
10
- gem "minitest-reporters"
11
- gem "minitest-rails"
12
- gem "rake"
13
- gem "simplecov"
14
- gem "shoulda"
15
- gem "sqlite3"
16
- gem "activerecord", "~> 3.2.0"
17
- gem "actionpack", "~> 3.2.0"
18
- gem "railties", "~> 3.2.0"
@@ -1,18 +0,0 @@
1
- # encoding: UTF-8
2
- # Copyright © 2014, Watu
3
-
4
- source "https://rubygems.org"
5
-
6
- gem "assert_difference"
7
- gem "bundler", "~> 1.3"
8
- gem "coveralls", require: false
9
- gem "minitest"
10
- gem "minitest-reporters"
11
- gem "minitest-rails"
12
- gem "rake"
13
- gem "simplecov"
14
- gem "shoulda"
15
- gem "sqlite3"
16
- gem "activerecord", "~> 4.0.0"
17
- gem "actionpack", "~> 4.0.0"
18
- gem "railties", "~> 4.0.0"
@@ -1,18 +0,0 @@
1
- # encoding: UTF-8
2
- # Copyright © 2014, Watu
3
-
4
- source "https://rubygems.org"
5
-
6
- gem "assert_difference"
7
- gem "bundler", "~> 1.3"
8
- gem "coveralls", require: false
9
- gem "minitest"
10
- gem "minitest-reporters"
11
- gem "minitest-rails"
12
- gem "rake"
13
- gem "simplecov"
14
- gem "shoulda"
15
- gem "sqlite3"
16
- gem "activerecord", "~> 4.1.0"
17
- gem "actionpack", "~> 4.1.0"
18
- gem "railties", "~> 4.1.0"