active_layer 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +2 -0
- data/LICENSE +20 -0
- data/README.md +149 -0
- data/lib/active_layer/active_record/persistence.rb +29 -0
- data/lib/active_layer/active_record.rb +16 -0
- data/lib/active_layer/attributes.rb +58 -0
- data/lib/active_layer/orm/active_record_hooks.rb +4 -0
- data/lib/active_layer/persistence.rb +68 -0
- data/lib/active_layer/proxy.rb +47 -0
- data/lib/active_layer/validations/each_validator.rb +32 -0
- data/lib/active_layer/validations/object_validator.rb +19 -0
- data/lib/active_layer/validations/validator.rb +64 -0
- data/lib/active_layer/validations.rb +54 -0
- data/lib/active_layer/version.rb +3 -0
- data/lib/active_layer.rb +12 -0
- metadata +117 -0
data/CHANGELOG.md
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Adam Cooper
|
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/README.md
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
# ActiveLayer
|
2
|
+
|
3
|
+
ActiveLayer provides validations, attribute filtering, and persistence in a layer sitting on top of a model.
|
4
|
+
|
5
|
+
This was born out of frustration with overly complex ActiveRecord validations and model contortions.
|
6
|
+
|
7
|
+
# Quick Example
|
8
|
+
|
9
|
+
class User < ActiveRecord::Base; end
|
10
|
+
# Every user field you want..
|
11
|
+
|
12
|
+
# This layer uses the ActiveRecord adapter which pulls in several other pieces
|
13
|
+
class UserLayer
|
14
|
+
include ActiveLayer::ActiveRecord
|
15
|
+
|
16
|
+
attr_accessible :name, :email, :address
|
17
|
+
|
18
|
+
validates :name, :email, :presence => true
|
19
|
+
validates :address_validation
|
20
|
+
|
21
|
+
before_validate :normalize_address
|
22
|
+
|
23
|
+
def normalize_address; end
|
24
|
+
def address_validation
|
25
|
+
errors.add(:address, :invalid) if address.blank?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Now how to use it:
|
30
|
+
user = User.find(1)
|
31
|
+
layer = UserLayer.new(user)
|
32
|
+
layer.update_attributes( {:name => '', :admin => true, :address => 'on a busy road'} ) # => false
|
33
|
+
layer.errors[:name].present # => true
|
34
|
+
user.errors[:name].present => true
|
35
|
+
user.admin # => false - was filtered out
|
36
|
+
|
37
|
+
# Some of the players
|
38
|
+
|
39
|
+
* ActiveLayer::Proxy
|
40
|
+
* ActiveLayer::Validations
|
41
|
+
* ActiveLayer::Attributes
|
42
|
+
* ActiveLayer::Persistence
|
43
|
+
|
44
|
+
# ActiveLayer::Proxy
|
45
|
+
|
46
|
+
This module provides the ability to delegate method calls down to the object and typically you would not use this element directly. However, it does provide one key method *active__layer__object* which provides access to the underlying object/model. This may be necessary in certain cases.
|
47
|
+
|
48
|
+
# ActiveLayer::Validations
|
49
|
+
|
50
|
+
Currently the majority of the functionality resides in this module and provides the ability for composable validation classes to be layered together. This module is completely compatible with the wonderful ActiveModel::Validation module and in fact just wraps it and provides extra functionality.
|
51
|
+
|
52
|
+
Currently the following is supported:
|
53
|
+
|
54
|
+
* Standard ActiveModel::Validators support (Each, With, Custom, etc.)
|
55
|
+
* Custom validation methods
|
56
|
+
* before_validation and after_validation hooks (Just like ActiveRecord)
|
57
|
+
* Nested ActiveLayer validations (This is neat!)
|
58
|
+
* All existing custom validators should 'just work'
|
59
|
+
|
60
|
+
## Examples
|
61
|
+
|
62
|
+
class AddressValidator
|
63
|
+
include ActiveLayer::Validations
|
64
|
+
|
65
|
+
before_validation :normalize_address
|
66
|
+
validates :address, :presence => true
|
67
|
+
validate :custom_method
|
68
|
+
|
69
|
+
def normalize_address; end
|
70
|
+
def custom_method; end
|
71
|
+
end
|
72
|
+
|
73
|
+
class EmailValidator
|
74
|
+
include ActiveLayer::Validations
|
75
|
+
|
76
|
+
validates :email, :presence => true
|
77
|
+
end
|
78
|
+
|
79
|
+
class UserValidator
|
80
|
+
include ActiveLayer::Validations
|
81
|
+
|
82
|
+
validates :name, :presence => true
|
83
|
+
validates_with EmailValidator
|
84
|
+
validates_with AddressValidator, :attributes => [:addresses]
|
85
|
+
end
|
86
|
+
|
87
|
+
# the EmailValidator will get passed the user object
|
88
|
+
# the AddressValidator will get passed each address of the user and merge the errors back up
|
89
|
+
user = User.find(1)
|
90
|
+
validator = UserValidator.new(user)
|
91
|
+
validator.valid? # => true/false
|
92
|
+
|
93
|
+
|
94
|
+
# ActiveLayer::Attributes
|
95
|
+
|
96
|
+
This module provides the ability to bulk assign attributes with attribute protection via att_accessible. By default all attributes are not assignable and you must declare which attributes are accessible. Note, each attribute is available for individual assigning or reading.
|
97
|
+
|
98
|
+
## Examples
|
99
|
+
|
100
|
+
class FlawedUserFilter
|
101
|
+
all_attributes_accessible!
|
102
|
+
# All attributes are now assignable
|
103
|
+
end
|
104
|
+
|
105
|
+
class UserFilter
|
106
|
+
attr_accessible :name, :address
|
107
|
+
end
|
108
|
+
|
109
|
+
user = User.find(1)
|
110
|
+
filter = UserFilter.new(user)
|
111
|
+
filter.attributes = {:name => 'Bob', 'admin' => true}
|
112
|
+
user.admin # => false
|
113
|
+
|
114
|
+
|
115
|
+
|
116
|
+
|
117
|
+
# ActiveLayer::Persistence
|
118
|
+
|
119
|
+
This layer is responsible for providing the save and update_attributes methods that function very similar to ActiveRecord. Both layers invoke the validations in the layer, if currently mixed in and ultimately delegate to the proxy object for saving. If the Attributes module is mixed in then the guards will be used however, if it is not mixed then active_layer_object.attributes=(hash) will be invoked.
|
120
|
+
|
121
|
+
Note: If you plan to use Persistence with Attributes then you must mix-in the Attributes module *after* the Persistence module
|
122
|
+
|
123
|
+
## Examples
|
124
|
+
|
125
|
+
class UserPersistor
|
126
|
+
include ActiveLayer::Persistence
|
127
|
+
end
|
128
|
+
|
129
|
+
user = User.find(1)
|
130
|
+
persistor = UserPersistor.new(user)
|
131
|
+
persistor.save
|
132
|
+
persistor.save! # will raise an ActiveLayer::RecordInvalidError with a #record method
|
133
|
+
persistor.update_attributes(:name => 'new')
|
134
|
+
persistor.update_attributes!(:name => 'new')
|
135
|
+
|
136
|
+
|
137
|
+
|
138
|
+
# TODO / Plans
|
139
|
+
|
140
|
+
* Ensure that the valid? method calls the underlying proxy object.valid?
|
141
|
+
* Nested attribute support - similar to Rails - but in an adaptable manner for use in other ORMs
|
142
|
+
* Add support for additional ORMs
|
143
|
+
* Ideas?
|
144
|
+
|
145
|
+
# License
|
146
|
+
|
147
|
+
ActiveLayer is available under the terms of the MIT license (see
|
148
|
+
LICENSE.txt for details).
|
149
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'activerecord'
|
2
|
+
|
3
|
+
module ActiveLayer
|
4
|
+
module ActiveRecord
|
5
|
+
# override the initialize because the submodels should handle their own translations
|
6
|
+
# This will allow drop in compatibility with existing functionality
|
7
|
+
class RecordInvalidError < ::ActiveRecord::RecordInvalidError
|
8
|
+
attr_reader :record
|
9
|
+
def initialize(record)
|
10
|
+
@record = record
|
11
|
+
super(@record.errors.full_messages.join(", "))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module Persistence
|
16
|
+
extend ActiveSupport::Concern
|
17
|
+
|
18
|
+
module InstanceMethods
|
19
|
+
|
20
|
+
def save!
|
21
|
+
unless save
|
22
|
+
raise RecordInvalidError.new(self)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ActiveLayer
|
2
|
+
# This is a helper module that is only responsible for pulling in all the modules
|
3
|
+
module ActiveRecord
|
4
|
+
autoload :Persistence, 'active_layer/active_record/persistence'
|
5
|
+
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
include ::ActiveLayer::Validations
|
9
|
+
include ::ActiveLayer::Persistence
|
10
|
+
include ::ActiveLayer::Attributes # hook in after the Persistence layer
|
11
|
+
|
12
|
+
# we only need this if ActiveRecord is actually defined.
|
13
|
+
include ::ActiveLayer::ActiveRecord::Persistence if defined?(::ActiveRecord)
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'active_support/core_ext/class/attribute'
|
2
|
+
require 'active_support/core_ext/hash/keys'
|
3
|
+
|
4
|
+
module ActiveLayer
|
5
|
+
class UnknownAttributeError < StandardError; end
|
6
|
+
|
7
|
+
# Adds the ability to pass attributes to the ActiveLayer Object.
|
8
|
+
# - Provides support for 'attr_accessible' class method to only allow certain attributes through
|
9
|
+
# - By default all attributes are filter out -> opt in model
|
10
|
+
# - You can enable all attributes passed through with 'all_attributes_accessible!'
|
11
|
+
# - Hooks into the ActiveLayer::Persistence module to tie in with the update_attributes
|
12
|
+
# - To enable this functionality, it must be inluded after the Persistence module
|
13
|
+
module Attributes
|
14
|
+
extend ActiveSupport::Concern
|
15
|
+
include ActiveLayer::Proxy
|
16
|
+
|
17
|
+
included do
|
18
|
+
class_attribute :accessible_attributes
|
19
|
+
self.accessible_attributes = []
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
def attr_accessible(*attributes)
|
24
|
+
self.accessible_attributes = Set.new(attributes.map(&:to_s)) + (accessible_attributes || [])
|
25
|
+
end
|
26
|
+
|
27
|
+
def all_attributes_accessible!
|
28
|
+
self.accessible_attributes = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
module InstanceMethods
|
34
|
+
|
35
|
+
def attributes=(new_attributes)
|
36
|
+
return if new_attributes.nil?
|
37
|
+
attributes = new_attributes.stringify_keys
|
38
|
+
|
39
|
+
safe_attributes = if accessible_attributes.nil?
|
40
|
+
attributes
|
41
|
+
else
|
42
|
+
attributes.reject { |key, value| !accessible_attributes.include?(key.gsub(/\(.+/, "")) }
|
43
|
+
end
|
44
|
+
|
45
|
+
safe_attributes.each do |k, v|
|
46
|
+
respond_to?(:"#{k}=") ? send(:"#{k}=", v) : raise(UnknownAttributeError, "unknown attribute: #{k}")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# override persistence saving to pull in the guard functionality
|
51
|
+
def active_layer_attributes_setting(new_attributes)
|
52
|
+
attributes = new_attributes
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
end # InstanceMethods
|
57
|
+
end # Attributes
|
58
|
+
end # ActiveLayer
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module ActiveLayer
|
2
|
+
# This module introduces save and update_attribute methods delegating to the proxy object
|
3
|
+
#
|
4
|
+
# This module provides two hook methods to allow the including class to control how the attributes get set on the proxy object
|
5
|
+
# and how the proxy object gets saved.
|
6
|
+
#
|
7
|
+
# Here are the defaults
|
8
|
+
#
|
9
|
+
# def active_layer_save
|
10
|
+
# active_layer_object.save
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# def active_layer_attributes_setting(new_attributes)
|
14
|
+
# active_layer_object.attributes = new_attributes
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
module Persistence
|
18
|
+
extend ActiveSupport::Concern
|
19
|
+
include ActiveLayer::Proxy
|
20
|
+
|
21
|
+
module InstanceMethods
|
22
|
+
def save
|
23
|
+
valid = self.respond_to?(:valid?, false) ? valid? : true
|
24
|
+
|
25
|
+
if valid
|
26
|
+
active_layer_save
|
27
|
+
else
|
28
|
+
false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def save!
|
33
|
+
unless save
|
34
|
+
raise RecordInvalidError.new(self)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def update_attributes(new_attributes)
|
39
|
+
active_layer_attributes_setting(new_attributes)
|
40
|
+
save
|
41
|
+
end
|
42
|
+
|
43
|
+
def update_attributes!(new_attributes)
|
44
|
+
active_layer_attributes_setting(new_attributes)
|
45
|
+
save!
|
46
|
+
end
|
47
|
+
|
48
|
+
# hook method to override saving behaviour
|
49
|
+
def active_layer_save
|
50
|
+
active_layer_object.save
|
51
|
+
end
|
52
|
+
|
53
|
+
# another hook method to control attributes=
|
54
|
+
def active_layer_attributes_setting(new_attributes)
|
55
|
+
active_layer_object.attributes = new_attributes
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class RecordInvalidError < RuntimeError
|
62
|
+
attr_reader :record
|
63
|
+
def initialize(record)
|
64
|
+
@record = record
|
65
|
+
super(@record.errors.full_messages.join(", "))
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module ActiveLayer
|
2
|
+
# This class provides the delegation to the actual object.
|
3
|
+
# You probably don't want to use this object directly but rather the other classes depend on it.
|
4
|
+
module Proxy
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
attr_writer :active_layer_object
|
9
|
+
end
|
10
|
+
|
11
|
+
module InstanceMethods
|
12
|
+
def initialize(*args, &block)
|
13
|
+
self.active_layer_object = args.first
|
14
|
+
super()
|
15
|
+
end
|
16
|
+
|
17
|
+
def active_layer_object
|
18
|
+
raise "active_layer_object was not set" if @active_layer_object.nil?
|
19
|
+
@active_layer_object
|
20
|
+
end
|
21
|
+
|
22
|
+
def method_missing(method, *args, &block)
|
23
|
+
# puts "passing: #{method} + #{args.inspect} to #{active_layer_object.inspect}"
|
24
|
+
unless @active_layer_object.nil?
|
25
|
+
active_layer_object.send(method, *args, &block)
|
26
|
+
else
|
27
|
+
super
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def read_attribute_for_validation(key)
|
32
|
+
if active_layer_object.respond_to?(:read_attribute_for_validation)
|
33
|
+
active_layer_object.read_attribute_for_validation(key)
|
34
|
+
else
|
35
|
+
active_layer_object.send(key)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def respond_to?(method, use_proxy = true)
|
40
|
+
super(method) || ( use_proxy && @active_layer_object && @active_layer_object.respond_to?(method) )
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module ActiveLayer
|
2
|
+
module Validations
|
3
|
+
#
|
4
|
+
# This class hooks into the standard validations and allows the new ActiveLayer::Validations to function
|
5
|
+
# as a NestedValidator
|
6
|
+
#
|
7
|
+
# class MyValidator
|
8
|
+
# include AciveLayer::Validations
|
9
|
+
# validates MyOtherValidator, :attributes => :sub_models
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# In the above case this class will be used to adapt the MyOtherValidator to look like an ActiveModel::Validator
|
13
|
+
#
|
14
|
+
class EachValidator < ActiveModel::EachValidator
|
15
|
+
attr_accessor :active_layer_validator
|
16
|
+
|
17
|
+
#
|
18
|
+
# The parent_validations will be the parent class that has mixed in the ActiveLayer::Validations module
|
19
|
+
#
|
20
|
+
def validate_each(parent_validations, attribute, value)
|
21
|
+
nested_attribute = parent_validations.read_attribute_for_validation(attribute)
|
22
|
+
|
23
|
+
Array.wrap(nested_attribute).each do |element|
|
24
|
+
active_layer_validator.active_layer_object = element
|
25
|
+
active_layer_validator.valid?
|
26
|
+
parent_validations.merge_errors(active_layer_validator.errors, "#{attribute}.")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#
|
2
|
+
# This class hooks into the standard validations and allows the new ModelValidator to function
|
3
|
+
# as a NestedValidator
|
4
|
+
#
|
5
|
+
module ActiveLayer
|
6
|
+
module Validations
|
7
|
+
class ObjectValidator < ActiveModel::Validator
|
8
|
+
attr_accessor :active_layer_validator
|
9
|
+
|
10
|
+
def validate(record)
|
11
|
+
# need to save the original errors because they get wiped during validation
|
12
|
+
record.keep_errors do
|
13
|
+
active_layer_validator.active_layer_object = record
|
14
|
+
active_layer_validator.valid?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module ActiveLayer
|
2
|
+
module Validations
|
3
|
+
# This module allows the ActiveLayer::Validations class to adapt to become
|
4
|
+
# an ActiveModel Validator
|
5
|
+
module Validator
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
attr_accessor :_validator
|
10
|
+
end
|
11
|
+
|
12
|
+
module InstanceMethods
|
13
|
+
|
14
|
+
def initialize(*args, &block)
|
15
|
+
if args.first.is_a?(Hash)
|
16
|
+
options = args.first
|
17
|
+
if options.has_key?(:attributes)
|
18
|
+
self._validator = EachValidator.new(options)
|
19
|
+
else
|
20
|
+
self._validator = ObjectValidator.new(options)
|
21
|
+
end
|
22
|
+
_validator.active_layer_validator = self
|
23
|
+
end
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
# adapter methods
|
28
|
+
def setup(record)
|
29
|
+
# nothing to do...
|
30
|
+
end
|
31
|
+
|
32
|
+
# adapter methods
|
33
|
+
def attributes
|
34
|
+
_validator && _validator.respond_to?(:attributes) ? _validator.attributes : []
|
35
|
+
end
|
36
|
+
|
37
|
+
def errors
|
38
|
+
if _validator
|
39
|
+
@errors ||= ActiveModel::Errors.new(self)
|
40
|
+
else
|
41
|
+
super
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# This method is called in two contexts, as part of the validation callbacks when it's setup
|
46
|
+
# as an adapter and to register a standard callback
|
47
|
+
#
|
48
|
+
def validate(*args, &block)
|
49
|
+
# puts "calling validate on #{self.class.name}"
|
50
|
+
if _validator
|
51
|
+
_validator.validate(*args, &block)
|
52
|
+
else
|
53
|
+
super
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module ActiveLayer
|
2
|
+
module Validations
|
3
|
+
autoload :Validator, 'active_layer/validations/validator'
|
4
|
+
autoload :EachValidator, 'active_layer/validations/each_validator'
|
5
|
+
autoload :ObjectValidator, 'active_layer/validations/object_validator'
|
6
|
+
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
include ActiveLayer::Proxy
|
9
|
+
include ActiveModel::Validations
|
10
|
+
include ActiveLayer::Validations::Validator
|
11
|
+
|
12
|
+
included do
|
13
|
+
extend ActiveModel::Callbacks
|
14
|
+
define_model_callbacks :validation
|
15
|
+
end
|
16
|
+
|
17
|
+
module InstanceMethods
|
18
|
+
|
19
|
+
# model validation methods
|
20
|
+
def errors
|
21
|
+
if active_layer_object.respond_to?(:errors)
|
22
|
+
active_layer_object.errors
|
23
|
+
else
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def keep_errors(prefix = "")
|
30
|
+
original_errors = errors.dup
|
31
|
+
result = yield
|
32
|
+
merge_errors(original_errors, prefix)
|
33
|
+
result
|
34
|
+
end
|
35
|
+
|
36
|
+
def merge_errors(other_errors, prefix = nil)
|
37
|
+
other_errors.each do |child_attribute, message|
|
38
|
+
attribute = "#{prefix}#{child_attribute}"
|
39
|
+
errors[attribute] << message
|
40
|
+
errors[attribute].uniq!
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def valid?(*)
|
45
|
+
_run_validation_callbacks do
|
46
|
+
super
|
47
|
+
#keep_errors { active_layer_object.valid? }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end # Validations
|
54
|
+
end # ActiveLayer
|
data/lib/active_layer.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'active_model'
|
3
|
+
require 'active_layer/version'
|
4
|
+
|
5
|
+
module ActiveLayer
|
6
|
+
autoload :ActiveRecord, 'active_layer/active_record'
|
7
|
+
autoload :Attributes, 'active_layer/attributes'
|
8
|
+
autoload :Persistence, 'active_layer/persistence'
|
9
|
+
autoload :Proxy, 'active_layer/proxy'
|
10
|
+
autoload :Validations, 'active_layer/validations'
|
11
|
+
end
|
12
|
+
|
metadata
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: active_layer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 13
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 9
|
10
|
+
version: 0.0.9
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Adam Cooper
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-06-12 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: activesupport
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: -1848230021
|
30
|
+
segments:
|
31
|
+
- 3
|
32
|
+
- 0
|
33
|
+
- 0
|
34
|
+
- beta3
|
35
|
+
version: 3.0.0.beta3
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id001
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: activemodel
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
hash: -1848230021
|
47
|
+
segments:
|
48
|
+
- 3
|
49
|
+
- 0
|
50
|
+
- 0
|
51
|
+
- beta3
|
52
|
+
version: 3.0.0.beta3
|
53
|
+
type: :runtime
|
54
|
+
version_requirements: *id002
|
55
|
+
description: Subscribing to single responsibility principility ActiveLayer aims to provide a layer of context over top a model.
|
56
|
+
email:
|
57
|
+
- adam.cooper@gmail.com
|
58
|
+
executables: []
|
59
|
+
|
60
|
+
extensions: []
|
61
|
+
|
62
|
+
extra_rdoc_files: []
|
63
|
+
|
64
|
+
files:
|
65
|
+
- lib/active_layer/active_record/persistence.rb
|
66
|
+
- lib/active_layer/active_record.rb
|
67
|
+
- lib/active_layer/attributes.rb
|
68
|
+
- lib/active_layer/orm/active_record_hooks.rb
|
69
|
+
- lib/active_layer/persistence.rb
|
70
|
+
- lib/active_layer/proxy.rb
|
71
|
+
- lib/active_layer/validations/each_validator.rb
|
72
|
+
- lib/active_layer/validations/object_validator.rb
|
73
|
+
- lib/active_layer/validations/validator.rb
|
74
|
+
- lib/active_layer/validations.rb
|
75
|
+
- lib/active_layer/version.rb
|
76
|
+
- lib/active_layer.rb
|
77
|
+
- LICENSE
|
78
|
+
- CHANGELOG.md
|
79
|
+
- README.md
|
80
|
+
has_rdoc: true
|
81
|
+
homepage: http://github.com/adamcooper/active_layer
|
82
|
+
licenses: []
|
83
|
+
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
|
87
|
+
require_paths:
|
88
|
+
- lib
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
hash: 3
|
95
|
+
segments:
|
96
|
+
- 0
|
97
|
+
version: "0"
|
98
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
|
+
none: false
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
hash: 23
|
104
|
+
segments:
|
105
|
+
- 1
|
106
|
+
- 3
|
107
|
+
- 6
|
108
|
+
version: 1.3.6
|
109
|
+
requirements: []
|
110
|
+
|
111
|
+
rubyforge_project: active_layer
|
112
|
+
rubygems_version: 1.3.7
|
113
|
+
signing_key:
|
114
|
+
specification_version: 3
|
115
|
+
summary: ActiveLayer provides validations, attribute filtering, and persistence in a layer sitting on top of any model.
|
116
|
+
test_files: []
|
117
|
+
|