context_validations 0.0.1
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 +7 -0
- data/.gitignore +18 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/README.md +118 -0
- data/Rakefile +12 -0
- data/lib/context_validations/controller.rb +79 -0
- data/lib/context_validations/model.rb +36 -0
- data/lib/context_validations/version.rb +3 -0
- data/lib/context_validations.rb +9 -0
- data/strong_validations.gemspec +26 -0
- data/test/controller_test.rb +45 -0
- data/test/model_test.rb +30 -0
- data/test/test_helper.rb +15 -0
- metadata +144 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c724b87e632a393002424843cee3cba7ebc3d9a4
|
4
|
+
data.tar.gz: dfae41788870a4f868a5788d862ffc9594cc8136
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 542d270b429d4a8411881c32d472bbc189fa0edae33d3adc2df2f02691621a9c89f05f94691ca74fa1bebd993f56111820a7f4ec64dc4cecfc800096160513a0
|
7
|
+
data.tar.gz: 6a168a33e2603811f8c594d3792df684cc4ba0396faf464ca952b86eeee389c9c8e1dee1206b6c022f076d162d5f104a8fd61d3e29fb281537ec37c9c97adc07
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
# ContextValidations #
|
2
|
+
|
3
|
+
[](http://travis-ci.org/dockyard/context_validations)
|
4
|
+
[](https://gemnasium.com/dockyard/context_validations)
|
5
|
+
[](https://codeclimate.com/github/dockyard/context_validations)
|
6
|
+
|
7
|
+
Rails exceptions automatically opened as issues on GitHub
|
8
|
+
|
9
|
+
## Looking for help? ##
|
10
|
+
|
11
|
+
If it is a bug [please open an issue on GitHub](https://github.com/dockyard/context_validations/issues).
|
12
|
+
|
13
|
+
## About ##
|
14
|
+
|
15
|
+
Context based validations for model instances.
|
16
|
+
|
17
|
+
## Example ##
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
class UserController < ApplicationController
|
21
|
+
include ContextValidations::Controller
|
22
|
+
|
23
|
+
def create
|
24
|
+
@user = User.new(user_params)
|
25
|
+
@user.validations = validations(:create)
|
26
|
+
|
27
|
+
if @user.save
|
28
|
+
# happy path
|
29
|
+
else
|
30
|
+
# sad path
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def create_validations
|
37
|
+
validates :password, :presence => true
|
38
|
+
end
|
39
|
+
|
40
|
+
def base_validations
|
41
|
+
validates :first_name, :last_name, :presence => true
|
42
|
+
validates :password, :confirmation => true
|
43
|
+
validates :email, :uniqueness => true, :format => EmailFormat
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class User < ActiveRecord::Base
|
48
|
+
include ContextValidations::Model
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
### Controllers ###
|
53
|
+
In the above example we just call `validations` and pass the context. We
|
54
|
+
set the result to `#validations=` on the model.
|
55
|
+
|
56
|
+
While this does introduce some complexity into our controllers it frees
|
57
|
+
us from the mental gymnastics of conditional validators and state flags.
|
58
|
+
|
59
|
+
The corresponding `#{context}_validations` method, in this case
|
60
|
+
`create_validations` defines the validations that will be used. Call the
|
61
|
+
`#validates` method just like you would in model validations, the API is
|
62
|
+
identical.
|
63
|
+
|
64
|
+
A `#base_validations` method is always called prior to
|
65
|
+
`#{context}_validations` that will allow you to group together common
|
66
|
+
validations. The result of these methods appends onto a `@validations`
|
67
|
+
array.
|
68
|
+
|
69
|
+
If you are using `Ruby 2.0+` you can use implicit contexts:
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
def create
|
73
|
+
@user = User.new(user_params)
|
74
|
+
# Notice we are only calling the #validations method and not passing
|
75
|
+
# context. In this example the context is derived from the calling
|
76
|
+
# method `create`
|
77
|
+
@user.validations = validations
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def create_validations
|
83
|
+
...
|
84
|
+
end
|
85
|
+
```
|
86
|
+
|
87
|
+
### Models ###
|
88
|
+
When the `ContextValidations::Model` module is mixed into the module all
|
89
|
+
of the validation callbacks are removed from that model.
|
90
|
+
|
91
|
+
Because we are setting the validations on the instance you should not
|
92
|
+
use `ActiveRecord::Base.create` as we do not want to allow the
|
93
|
+
validations to be set via mass-assignment. This does introduce an extra
|
94
|
+
step in some places but it shouldn't be that big of a deal.
|
95
|
+
|
96
|
+
## Authors ##
|
97
|
+
|
98
|
+
* [Brian Cardarella](http://twitter.com/bcardarella)
|
99
|
+
|
100
|
+
[We are very thankful for the many contributors](https://github.com/dockyard/context_validations/graphs/contributors)
|
101
|
+
|
102
|
+
## Versioning ##
|
103
|
+
|
104
|
+
This gem follows [Semantic Versioning](http://semver.org)
|
105
|
+
|
106
|
+
## Want to help? ##
|
107
|
+
|
108
|
+
Please do! We are always looking to improve this gem. Please see our
|
109
|
+
[Contribution Guidelines](https://github.com/dockyard/context_validations/blob/master/CONTRIBUTING.md)
|
110
|
+
on how to properly submit issues and pull requests.
|
111
|
+
|
112
|
+
## Legal ##
|
113
|
+
|
114
|
+
[DockYard](http://dockyard.com), LLC © 2013
|
115
|
+
|
116
|
+
[@dockyard](http://twitter.com/dockyard)
|
117
|
+
|
118
|
+
[Licensed under the MIT license](http://www.opensource.org/licenses/mit-license.php)
|
data/Rakefile
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
module ContextValidations::Controller
|
2
|
+
# Will build the validations used to assign to a model instance
|
3
|
+
#
|
4
|
+
# Passing a context will call the `#{context}_validations` method if available
|
5
|
+
# `#base_validations` will always be called prior to `#{context}_validations`
|
6
|
+
#
|
7
|
+
# If you are using Ruby 2.0+ not passing a context will force an implicit context call
|
8
|
+
# based upon the calling method name.
|
9
|
+
#
|
10
|
+
# examples:
|
11
|
+
# # Implicit method call will call `#base_validations` then `#create_validations`
|
12
|
+
# def create
|
13
|
+
# @user.validations = validations
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# # Will call `#base_validations` then `#create_validations`
|
17
|
+
# def other_create
|
18
|
+
# @user.validations = validations(:create)
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# # Will onliy call `#base_validations` because `#update_validations` does not exist
|
22
|
+
# def update
|
23
|
+
# @user.validations = validations
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# def create_validations
|
27
|
+
# ...
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# @param [String, Symbol]
|
31
|
+
def validations(context = nil)
|
32
|
+
if RUBY_VERSION > '2'
|
33
|
+
context ||= caller_locations(1, 1).first.label
|
34
|
+
end
|
35
|
+
@validations = []
|
36
|
+
base_validations
|
37
|
+
if respond_to?("#{context}_validations")
|
38
|
+
send("#{context}_validations")
|
39
|
+
end
|
40
|
+
@validations
|
41
|
+
end
|
42
|
+
|
43
|
+
# Instance level implementation of `ActiveModel::Validations.validates`
|
44
|
+
# Will accept all of the same options as the class-level model versions of the method
|
45
|
+
def validates(*attributes)
|
46
|
+
defaults = attributes.extract_options!
|
47
|
+
validations = defaults.slice!(*_validates_default_keys)
|
48
|
+
|
49
|
+
attributes.inject(@validations) do |validators, attribute|
|
50
|
+
defaults[:attributes] = [attribute]
|
51
|
+
validations.each do |key, options|
|
52
|
+
key = "#{key.to_s.camelize}Validator"
|
53
|
+
klass = key.include?('::') ? key.constantize : "ActiveModel::Validations::#{key}".constantize
|
54
|
+
validator = klass.new(defaults.merge(_parse_validates_options(options)))
|
55
|
+
validators << validator
|
56
|
+
end
|
57
|
+
validators
|
58
|
+
end.flatten.uniq
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def _validates_default_keys
|
64
|
+
[:if, :unless, :on, :allow_blank, :allow_nil , :strict]
|
65
|
+
end
|
66
|
+
|
67
|
+
def _parse_validates_options(options)
|
68
|
+
case options
|
69
|
+
when TrueClass
|
70
|
+
{}
|
71
|
+
when Hash
|
72
|
+
options
|
73
|
+
when Range, Array
|
74
|
+
{ :in => options }
|
75
|
+
else
|
76
|
+
{ :with => options }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module ContextValidations::Model
|
2
|
+
def self.included(base)
|
3
|
+
base.class_eval do
|
4
|
+
reset_callbacks(:validate)
|
5
|
+
end
|
6
|
+
|
7
|
+
base._validators.keys.each do |key|
|
8
|
+
base._validators.delete(key)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# The collection of validations assigned to this model instance
|
13
|
+
#
|
14
|
+
# @return [Array]
|
15
|
+
def validations
|
16
|
+
@validations ||= []
|
17
|
+
end
|
18
|
+
|
19
|
+
# Use to set the validations collection assigned to this model instance
|
20
|
+
#
|
21
|
+
# Pass an array of validator instances
|
22
|
+
#
|
23
|
+
# @param [[ActiveMode::Validations::Validator]]
|
24
|
+
def validations=(validations)
|
25
|
+
@validations = validations.flatten
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
def run_validations!
|
31
|
+
Array.wrap(validations).each do |validator|
|
32
|
+
validator.validate(self)
|
33
|
+
end
|
34
|
+
errors.empty?
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'context_validations/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'context_validations'
|
8
|
+
spec.version = ContextValidations::VERSION
|
9
|
+
spec.authors = ['Brian Cardarella']
|
10
|
+
spec.email = ['bcardarella@gmail.com']
|
11
|
+
spec.description = %q{Context based validations for ActiveRecord models}
|
12
|
+
spec.summary = %q{Context based validations for ActiveRecord models}
|
13
|
+
spec.license = 'MIT'
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
17
|
+
spec.require_paths = ['lib']
|
18
|
+
|
19
|
+
spec.add_dependency 'activesupport'
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
22
|
+
spec.add_development_dependency 'rake'
|
23
|
+
spec.add_development_dependency 'minitest'
|
24
|
+
spec.add_development_dependency 'm'
|
25
|
+
spec.add_development_dependency 'activemodel'
|
26
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class UsersController
|
4
|
+
include ContextValidations::Controller
|
5
|
+
|
6
|
+
def create
|
7
|
+
validations
|
8
|
+
end
|
9
|
+
|
10
|
+
def other_create
|
11
|
+
validations(:create)
|
12
|
+
end
|
13
|
+
|
14
|
+
def update
|
15
|
+
validations
|
16
|
+
end
|
17
|
+
|
18
|
+
def base_validations
|
19
|
+
validates :first_name, :presence => true
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_validations
|
23
|
+
validates :password, :presence => true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe 'Controller' do
|
28
|
+
before do
|
29
|
+
@controller = UsersController.new
|
30
|
+
end
|
31
|
+
|
32
|
+
if RUBY_VERSION >= '2'
|
33
|
+
it 'combines base and create validations for create action, context is implied' do
|
34
|
+
@controller.create.length.must_equal 2
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'combines base and create validations for other create action, context is forced' do
|
39
|
+
@controller.other_create.length.must_equal 2
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'uses base validations when context validations are not set for update action' do
|
43
|
+
@controller.update.length.must_equal 1
|
44
|
+
end
|
45
|
+
end
|
data/test/model_test.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'active_model'
|
3
|
+
|
4
|
+
EmailFormat = /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/
|
5
|
+
|
6
|
+
class User
|
7
|
+
include ActiveModel::Validations
|
8
|
+
include ContextValidations::Model
|
9
|
+
attr_accessor :first_name, :email
|
10
|
+
|
11
|
+
validates :first_name, :presence => true
|
12
|
+
validates :email, :format => EmailFormat
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'Model' do
|
16
|
+
before do
|
17
|
+
@user = User.new
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'ignores existing validations' do
|
21
|
+
@user.valid?.must_equal true
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'accepts validations set onto the instance' do
|
25
|
+
validations = [ActiveModel::Validations::PresenceValidator.new(:attributes => [:first_name]), ActiveModel::Validations::FormatValidator.new(:attributes => [:email], :with => EmailFormat)]
|
26
|
+
@user.validations = validations
|
27
|
+
@user.valid?.must_equal false
|
28
|
+
@user.errors.count.must_equal 2
|
29
|
+
end
|
30
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: context_validations
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brian Cardarella
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-05-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest
|
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: m
|
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: activemodel
|
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
|
+
description: Context based validations for ActiveRecord models
|
98
|
+
email:
|
99
|
+
- bcardarella@gmail.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- .gitignore
|
105
|
+
- .travis.yml
|
106
|
+
- Gemfile
|
107
|
+
- README.md
|
108
|
+
- Rakefile
|
109
|
+
- lib/context_validations.rb
|
110
|
+
- lib/context_validations/controller.rb
|
111
|
+
- lib/context_validations/model.rb
|
112
|
+
- lib/context_validations/version.rb
|
113
|
+
- strong_validations.gemspec
|
114
|
+
- test/controller_test.rb
|
115
|
+
- test/model_test.rb
|
116
|
+
- test/test_helper.rb
|
117
|
+
homepage:
|
118
|
+
licenses:
|
119
|
+
- MIT
|
120
|
+
metadata: {}
|
121
|
+
post_install_message:
|
122
|
+
rdoc_options: []
|
123
|
+
require_paths:
|
124
|
+
- lib
|
125
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - '>='
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '0'
|
130
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
|
+
requirements:
|
132
|
+
- - '>='
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
requirements: []
|
136
|
+
rubyforge_project:
|
137
|
+
rubygems_version: 2.0.3
|
138
|
+
signing_key:
|
139
|
+
specification_version: 4
|
140
|
+
summary: Context based validations for ActiveRecord models
|
141
|
+
test_files:
|
142
|
+
- test/controller_test.rb
|
143
|
+
- test/model_test.rb
|
144
|
+
- test/test_helper.rb
|