attribute-filters 1.4.0 → 2.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.
- data.tar.gz.sig +0 -0
- data/.yardopts +1 -0
- data/ChangeLog +501 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +7 -7
- data/Manifest.txt +7 -0
- data/README.md +59 -30
- data/Rakefile +1 -0
- data/attribute-filters.gemspec +4 -4
- data/docs/COMMON-FILTERS.md +1067 -0
- data/docs/HISTORY +42 -0
- data/docs/TODO +29 -12
- data/docs/USAGE.md +718 -818
- data/lib/attribute-filters.rb +4 -2
- data/lib/attribute-filters/attribute_set.rb +144 -73
- data/lib/attribute-filters/attribute_set_annotations.rb +110 -77
- data/lib/attribute-filters/attribute_set_attrquery.rb +51 -8
- data/lib/attribute-filters/attribute_set_enum.rb +44 -38
- data/lib/attribute-filters/attribute_set_query.rb +62 -12
- data/lib/attribute-filters/backports.rb +36 -4
- data/lib/attribute-filters/common_filters.rb +83 -37
- data/lib/attribute-filters/common_filters/bare.rb +29 -0
- data/lib/attribute-filters/common_filters/case.rb +34 -19
- data/lib/attribute-filters/common_filters/convert.rb +259 -0
- data/lib/attribute-filters/common_filters/join.rb +37 -30
- data/lib/attribute-filters/common_filters/order.rb +105 -0
- data/lib/attribute-filters/common_filters/pick.rb +90 -0
- data/lib/attribute-filters/common_filters/presence.rb +70 -0
- data/lib/attribute-filters/common_filters/split.rb +37 -21
- data/lib/attribute-filters/common_filters/squeeze.rb +28 -9
- data/lib/attribute-filters/common_filters/strip.rb +7 -3
- data/lib/attribute-filters/dsl_attr_virtual.rb +2 -1
- data/lib/attribute-filters/dsl_filters.rb +14 -61
- data/lib/attribute-filters/dsl_sets.rb +238 -88
- data/lib/attribute-filters/helpers.rb +7 -1
- data/lib/attribute-filters/meta_set.rb +38 -0
- data/lib/attribute-filters/version.rb +1 -1
- data/spec/attribute-filters_spec.rb +178 -16
- data/spec/spec_helper.rb +9 -4
- metadata +129 -69
- metadata.gz.sig +0 -0
data/docs/HISTORY
CHANGED
|
@@ -1,3 +1,45 @@
|
|
|
1
|
+
=== 2.0.0 / 2012-10-01
|
|
2
|
+
|
|
3
|
+
* major enhancements
|
|
4
|
+
|
|
5
|
+
* Operating speed increased by 100%
|
|
6
|
+
* API change:
|
|
7
|
+
* AttributeSet is now based on a Hash
|
|
8
|
+
* Added MetaSet for keeping sets of attribute sets
|
|
9
|
+
* Added DSL keyword for registering filtering methods
|
|
10
|
+
* DSL method `filter_attributes` is using filtering methods registered before
|
|
11
|
+
* Creation of duplicates for sets moved to class-level accessors
|
|
12
|
+
* Adding elements to sets improved, `AttributeSet` initializer uses the method `add`
|
|
13
|
+
* Common Filters seriously refactored (easily expandable and parametrizable now)
|
|
14
|
+
* Added common filters: Convert, Order, Pick, Presence
|
|
15
|
+
|
|
16
|
+
* minor enhancements
|
|
17
|
+
|
|
18
|
+
* DSL class methods for models have now aliases named in third person
|
|
19
|
+
* `AttributeSet#annotations` returns a hash containing annotated attributes only
|
|
20
|
+
* Documentation updated, common filters specific documentation moved to `COMMON-FILTERS`
|
|
21
|
+
* Added `AttributeSet::Enumerable#each_name_value` enumerator
|
|
22
|
+
* Added `AttributeSet::Enumerable#select_accessible` enumerator
|
|
23
|
+
* Added DSL for attribute name gethering from next method name in a chain
|
|
24
|
+
* Added `filtered_attribute_simple` DSL method
|
|
25
|
+
* Added `attribute_set_exists?` DSL class method
|
|
26
|
+
* Added `virtual?` and `semi_real?` to `AttributeSet::AttrQuery` and `AttributeSet::Query`
|
|
27
|
+
* Added `changed?` and `unchanged?` to `AttributeSet::AttrQuery` and `AttributeSet::Query`
|
|
28
|
+
* Added `AttributeSet#to_set`
|
|
29
|
+
* Improved DSL methods: `valid?`, `invalid?`, `accessible?`, `protected?`
|
|
30
|
+
* Improved `AttributeSet::Query` initializer (added error checking)
|
|
31
|
+
* Improved `attributes_to_filter` DLS method (removed redundant calls to duplicates of a set)
|
|
32
|
+
* Overriden `inspect` method in `AttributeSet`
|
|
33
|
+
|
|
34
|
+
* major bugfixes
|
|
35
|
+
|
|
36
|
+
* Fixed `AttributeSet::Query` wrapper calls (passing custom calls to next method was broken)
|
|
37
|
+
* Replaced `hash.merge(hash)` expressions with more `HashWithIndifferentAccess` compliant
|
|
38
|
+
|
|
39
|
+
* minor bugfixes
|
|
40
|
+
|
|
41
|
+
* Enumerators wrapped to return `AttributeSet::Enumerator` objects
|
|
42
|
+
|
|
1
43
|
=== 1.4.0 / 2012-08-24
|
|
2
44
|
|
|
3
45
|
* major enhancements
|
data/docs/TODO
CHANGED
|
@@ -1,20 +1,37 @@
|
|
|
1
|
-
* add more rspec examples (+ nil and boolean attributes)
|
|
2
1
|
|
|
3
|
-
* add
|
|
2
|
+
* attr_virtual - wrap method_defined? and add some gotchas into it that will wait for accessor to be added
|
|
3
|
+
there already is a hash for attr_virtual, all we need to do is to check any added accessor against that hash
|
|
4
|
+
that will only apply when there weren't accessors while using attr_virtual
|
|
4
5
|
|
|
5
|
-
* add: changed? all.changed? any.changed? one.changed? none.changed? to attrquery and query proxies
|
|
6
|
-
- they can use methods that internally are checking it
|
|
7
6
|
|
|
8
|
-
* add
|
|
9
|
-
* add numerize to common filters
|
|
10
|
-
* add booleanize to common filters
|
|
11
|
-
* add nullify to common filters
|
|
12
|
-
* add clear to common filters
|
|
13
|
-
* add reverse to common filters
|
|
14
|
-
* add sanitize to common filters (that calls needed)
|
|
15
|
-
-- sanitize_email
|
|
7
|
+
* add sanitize to common filters
|
|
16
8
|
-- sanitize_url
|
|
17
9
|
-- sanitize_string
|
|
18
10
|
-- sanitize_name
|
|
19
11
|
-- sanitize_country
|
|
20
12
|
-- sanitize_iban (future, in a gem attribute-filters-common-iban)
|
|
13
|
+
|
|
14
|
+
sanitize_the_attribute :name
|
|
15
|
+
sanitize_the_attribute :name => { :as => :name }
|
|
16
|
+
sanitize :name
|
|
17
|
+
the_attribute :name, :should_be_sanitized
|
|
18
|
+
the_attribute :name, :should_be_sanitized => { :as => :name }
|
|
19
|
+
|
|
20
|
+
before_save :sanitize_attributes
|
|
21
|
+
|
|
22
|
+
* one module for sanitizing - AttributeFilters::Sanitize
|
|
23
|
+
* possible submodules that enable certain/additional sanitizing methods
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class User
|
|
27
|
+
sanitize_attributes :name, :email, :home => { :as => :address }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
-> uses :should_be_sanitized same as filters do.
|
|
31
|
+
-> sanitization often uses each_element helper
|
|
32
|
+
-> sanitization methods taken from: Sanitize.instance_methods(false) [and aliases]
|
|
33
|
+
-> uses one main method for sanitization called sanitize_attributes
|
|
34
|
+
- for each attribute from a set the method checks the :as annotation (sanitize_attributes should add it)
|
|
35
|
+
- if there is no annotation it tries to guess it by the name
|
|
36
|
+
(uses global dictionary against name and its parts from the last one: e.g real_name takes 'name' first)
|
|
37
|
+
|
data/docs/USAGE.md
CHANGED
|
@@ -4,58 +4,62 @@ Usage of Attribute Filters
|
|
|
4
4
|
Attribute sets
|
|
5
5
|
--------------
|
|
6
6
|
|
|
7
|
-
Attribute set is a set of attribute names
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
Attribute set is a set of attribute names and optional annotations.
|
|
8
|
+
It's like a hash and internally it is a kind of Hash, but differs in
|
|
9
|
+
many places.
|
|
10
10
|
|
|
11
11
|
Attribute sets have simple function; **they group attribute names**. What can
|
|
12
12
|
you do with that? For example you can use it to perform some tasks
|
|
13
|
-
on all
|
|
13
|
+
on all attribute names that are stored in a set (or their values). You can also
|
|
14
|
+
combine sets, intersect, exclusively disjuct them, merge with other data, query them,
|
|
15
|
+
iterate through them, and so on.
|
|
14
16
|
|
|
15
17
|
### Data structures ###
|
|
16
18
|
|
|
17
19
|
Attribute sets are instances of
|
|
18
20
|
[`ActiveModel::AttributeSet`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeSet)
|
|
19
|
-
class. You can create and update sets freely and store them wherever you want
|
|
20
|
-
but when it comes to models then (at the class-level) you can (and you should) rely
|
|
21
|
-
on a storage that is already prepared to handle sets.
|
|
21
|
+
class. You can create and update sets freely and store in them wherever you want.
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
For your convenience Attribute Filters also provides globally created attribute sets that are bound to your models
|
|
24
|
+
(at the class-level). The binding is realized simply by using the hash of all these sets. The attribute sets
|
|
25
|
+
assigned to models are stored as
|
|
26
|
+
[class instance variable](http://blog.codegram.com/2011/4/understanding-class-instance-variables-in-ruby).
|
|
27
|
+
|
|
28
|
+
**You should interact with the global sets using dedicated DSL keywords** that are available in your models.
|
|
26
29
|
These methods will allow you to read or write some data from/to global attribute sets.
|
|
27
30
|
|
|
28
|
-
Attribute Filters are using `AttributeSet` instances
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
a set of set names, the returned value will probably
|
|
33
|
-
be an instance of the class `AttributeSet`.
|
|
31
|
+
Attribute Filters are using `AttributeSet` instances not just to store internal data
|
|
32
|
+
but also to interact with other parts of a program. So whenever there is a method
|
|
33
|
+
that returns a set of attributes or even a set of set names, the returned value
|
|
34
|
+
will probably be an instance of the `AttributeSet` class.
|
|
34
35
|
|
|
35
36
|
Note that when sets are returned the convention is that:
|
|
36
37
|
|
|
37
38
|
* **attribute names are strings**
|
|
38
39
|
* **set names are symbols**
|
|
40
|
+
* **annotations are hashes** attached to attribute names (strings)
|
|
41
|
+
* **annotation keys are symbols**
|
|
39
42
|
|
|
40
|
-
|
|
41
|
-
remove elements from it
|
|
42
|
-
|
|
43
|
-
a part of the interface
|
|
43
|
+
Once you create some set that is bound to your model (there is a class method `attribute_set` for it)
|
|
44
|
+
you cannot remove elements from it. Moreover, any query returning its contents will always
|
|
45
|
+
give you the deep copy. Such a separation is a consequence of the idea that **the model-bound attribute
|
|
46
|
+
sets should be a part of the interface**, which shouldn't change at runtime. This approach
|
|
47
|
+
enforces the declarative design (which is very concise and clear as you read the code).
|
|
44
48
|
|
|
45
|
-
### Defining the attribute sets ###
|
|
49
|
+
### Defining the model-level attribute sets ###
|
|
46
50
|
|
|
47
51
|
First thing that should be done when using the Attribute Filters
|
|
48
52
|
is defining the sets of attributes in models.
|
|
49
53
|
|
|
50
54
|
You can also create local sets (using `ActiveModel::AttributeSet.new`)
|
|
51
|
-
or a local sets with extra syntactic sugar (using `ActiveModel::AttributeSet.new`)
|
|
52
|
-
but in real-life scenarios you
|
|
53
|
-
|
|
55
|
+
or a local sets with extra syntactic sugar (using `ActiveModel::AttributeSet::Query.new`)
|
|
56
|
+
but in real-life scenarios you will use model-bound sets that can be later used
|
|
57
|
+
by common filters and by your own methods.
|
|
54
58
|
|
|
55
59
|
#### `attribute_set(set_name => attr_names)` ####
|
|
56
60
|
|
|
57
61
|
The [`attribute_set`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters/ClassMethods:attribute_set)
|
|
58
|
-
(a.k.a `
|
|
62
|
+
(a.k.a `has_attributes_that`) class method allows to **create or update a set** that will be
|
|
59
63
|
tied to a model.
|
|
60
64
|
|
|
61
65
|
Example:
|
|
@@ -63,18 +67,18 @@ Example:
|
|
|
63
67
|
```ruby
|
|
64
68
|
class User < ActiveRecord::Base
|
|
65
69
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
has_attributes_that should_be_stripped: [ :username, :email, :real_name ]
|
|
71
|
+
has_attributes_that should_be_downcased: [ :username, :email ]
|
|
72
|
+
has_attributes_that should_be_capitalized: [ :real_name ]
|
|
69
73
|
|
|
70
74
|
end
|
|
71
75
|
```
|
|
72
76
|
|
|
73
77
|
Instead of `attribute_set` you may also use one of the aliases:
|
|
74
78
|
|
|
75
|
-
* `
|
|
76
|
-
`
|
|
77
|
-
`
|
|
79
|
+
* `attributes_set`, `attributes_that_are`, `attributes_that`, `properties_that`,
|
|
80
|
+
`has_attribute_set`, `has_attribute_that`, `has_attribute_that_is`, `has_attributes`,
|
|
81
|
+
`has_attributes_set`, `has_attributes_that_are`, `has_attributes_that`, `has_properties_that`
|
|
78
82
|
|
|
79
83
|
#### `filter_attribute(attr => set_names)` ####
|
|
80
84
|
|
|
@@ -90,17 +94,18 @@ Example:
|
|
|
90
94
|
```ruby
|
|
91
95
|
class User < ActiveRecord::Base
|
|
92
96
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
97
|
+
its_attribute real_name: [ :should_be_stripped, :should_be_capitalized ]
|
|
98
|
+
its_attribute username: [ :should_be_stripped, :should_be_downcased ]
|
|
99
|
+
its_attribute email: [ :should_be_stripped, :should_be_downcased ]
|
|
96
100
|
|
|
97
101
|
end
|
|
98
102
|
```
|
|
99
103
|
|
|
100
104
|
Instead of `filter_attribute` you may also use one of the aliases:
|
|
101
105
|
|
|
102
|
-
* `
|
|
103
|
-
`
|
|
106
|
+
* `the_attribute`, `attribute_to_set`, `filtered_attribute`, `filtered_attributes`,
|
|
107
|
+
`filters_attribute`, `filters_attributes`, `its_attribute`, `has_attribute`,
|
|
108
|
+
`has_the_attribute`, `has_filtered_attribute`, `has_filtered_attributes`
|
|
104
109
|
|
|
105
110
|
#### Mixing the syntaxes ####
|
|
106
111
|
|
|
@@ -110,11 +115,11 @@ You can also use regular arguments instead of hashes to create sets:
|
|
|
110
115
|
```ruby
|
|
111
116
|
class User < ActiveRecord::Base
|
|
112
117
|
|
|
113
|
-
|
|
118
|
+
has_attributes_that :should_be_stripped, :username, :email, :real_name
|
|
114
119
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
120
|
+
its_attribute :real_name, :should_be_capitalized
|
|
121
|
+
its_attribute :username, :should_be_downcased
|
|
122
|
+
its_attribute :email, :should_be_downcased
|
|
118
123
|
|
|
119
124
|
end
|
|
120
125
|
```
|
|
@@ -128,8 +133,12 @@ of class methods to query them.
|
|
|
128
133
|
|
|
129
134
|
The [`attribute_set`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters/ClassMethods:attribute_set)
|
|
130
135
|
(a.k.a `attributes_that`) class method called with a single argument **returns the attribute set
|
|
131
|
-
of the given name**.
|
|
132
|
-
|
|
136
|
+
of the given name**.
|
|
137
|
+
|
|
138
|
+
It will always return the instance of `AttributeSet` class, even if there is no set registered under
|
|
139
|
+
the given name (in that case the resulting set will be empty). To know if the returned set is a stub
|
|
140
|
+
(placed instead of the missing one) you can use `frozen?` on it or you can call the DSL method
|
|
141
|
+
`attribute_set_exists?(set_name)` before querying the global sets for a model.
|
|
133
142
|
|
|
134
143
|
Example:
|
|
135
144
|
|
|
@@ -140,16 +149,23 @@ Example:
|
|
|
140
149
|
|
|
141
150
|
Note that the returned set will be a copy of the original set stored within your model.
|
|
142
151
|
|
|
152
|
+
Alternative syntax:
|
|
153
|
+
|
|
154
|
+
```ruby
|
|
155
|
+
User.attributes_that.should_be_stripped - User.attributes_that.should_be_downcased
|
|
156
|
+
# => #<ActiveModel::AttributeSet: {"real_name"}>
|
|
157
|
+
```
|
|
158
|
+
|
|
143
159
|
Instead of `attribute_set` you may also use one of the aliases:
|
|
144
160
|
|
|
145
|
-
* `
|
|
146
|
-
`
|
|
147
|
-
`
|
|
161
|
+
* `attributes_set`, `attributes_that_are`, `attributes_that`, `properties_that`,
|
|
162
|
+
`has_attribute_set`, `has_attribute_that`, `has_attribute_that_is`, `has_attributes`,
|
|
163
|
+
`has_attributes_set`, `has_attributes_that_are`, `has_attributes_that`, `has_properties_that`
|
|
148
164
|
|
|
149
165
|
#### `attribute_sets` ####
|
|
150
166
|
|
|
151
167
|
The [`attribute_sets`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters/ClassMethods:attribute_sets)
|
|
152
|
-
class method returns a
|
|
168
|
+
class method returns a MetaSet kind of value containing **all the defined attribute sets** indexed by their names.
|
|
153
169
|
|
|
154
170
|
Example:
|
|
155
171
|
|
|
@@ -174,8 +190,15 @@ Note that the returned sets will be copies of the original sets stored within yo
|
|
|
174
190
|
#### `attribute_set` ####
|
|
175
191
|
|
|
176
192
|
The [`attribute_set`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters/ClassMethods:attribute_set)
|
|
177
|
-
(a.k.a `attributes_that`) class method called without any arguments is a wrapper that calls `
|
|
178
|
-
|
|
193
|
+
(a.k.a `attributes_that`) class method called without any arguments is a DSL wrapper that calls `attribute_set(set_name)`
|
|
194
|
+
with `set_name` taken from next method call.
|
|
195
|
+
|
|
196
|
+
Example:
|
|
197
|
+
|
|
198
|
+
```ruby
|
|
199
|
+
User.attributes_that.should_be_downcased
|
|
200
|
+
# => #<ActiveModel::AttributeSet: {"username", "email"}>
|
|
201
|
+
```
|
|
179
202
|
|
|
180
203
|
#### `filter_attribute(attribute_name)` ####
|
|
181
204
|
|
|
@@ -200,9 +223,8 @@ Instead of `filter_attribute` you may also use one of the aliases:
|
|
|
200
223
|
#### `attributes_to_sets` ####
|
|
201
224
|
|
|
202
225
|
The [`attributes_to_sets`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters/ClassMethods:attributes_to_sets)
|
|
203
|
-
class method returns a
|
|
204
|
-
|
|
205
|
-
(Filtered means that they belong to some sets.)
|
|
226
|
+
class method returns a MetaSet kind of value containing **all filtered attributes and sets that the attributes
|
|
227
|
+
belong to**. The meta set is indexed by attribute names.
|
|
206
228
|
|
|
207
229
|
Example:
|
|
208
230
|
|
|
@@ -223,8 +245,8 @@ Instead of `attributes_to_sets` you may also use one of the aliases:
|
|
|
223
245
|
The [`filter_attribute`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters/ClassMethods:filter_attribute)
|
|
224
246
|
(a.k.a `the_attribute`) class method called without any arguments
|
|
225
247
|
is a wrapper that calls `attributes_to_sets` which returns
|
|
226
|
-
a
|
|
227
|
-
|
|
248
|
+
a returns a MetaSet kind of value containing **all filtered attributes and sets that the attributes
|
|
249
|
+
belong to**.
|
|
228
250
|
|
|
229
251
|
### Querying sets in model objects ###
|
|
230
252
|
|
|
@@ -234,7 +256,8 @@ To do that you may use instance methods that are designed for that purpose.
|
|
|
234
256
|
#### `attribute_set` ####
|
|
235
257
|
|
|
236
258
|
The [`attribute_set`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters:attribute_set)
|
|
237
|
-
instance method called withount an argument **returns the attribute set object containing all attributes known
|
|
259
|
+
instance method called withount an argument **returns the attribute set object containing all attributes known
|
|
260
|
+
in a current model**.
|
|
238
261
|
|
|
239
262
|
Example:
|
|
240
263
|
|
|
@@ -280,15 +303,21 @@ There are also variants of this method that differ in a kind of taken argument:
|
|
|
280
303
|
|
|
281
304
|
Instead of `attribute_set` you may also use one of the aliases:
|
|
282
305
|
|
|
283
|
-
* `
|
|
284
|
-
`
|
|
285
|
-
`
|
|
286
|
-
|
|
306
|
+
* `attributes_set`, `attributes_that_are`, `attributes_that`, `properties_that`,
|
|
307
|
+
`has_attribute_set`, `has_attribute_that`, `has_attribute_that_is`, `has_attributes`,
|
|
308
|
+
`has_attributes_set`, `has_attributes_that_are`, `has_attributes_that`, `has_properties_that`
|
|
309
|
+
|
|
310
|
+
Instead of `attribute_set` you may also use:
|
|
311
|
+
|
|
312
|
+
* `attribute_set_simple(set_name)`
|
|
313
|
+
|
|
314
|
+
It works same way as `attribute_set(set_name)` but doesn't wrap the result in a transparent proxy
|
|
315
|
+
object that brings some syntactic sugar (explained later).
|
|
287
316
|
|
|
288
317
|
#### `attribute_sets` ####
|
|
289
318
|
|
|
290
319
|
The [`attribute_sets`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters:attribute_sets)
|
|
291
|
-
method returns a
|
|
320
|
+
method returns a meta set containing **all the defined attribute sets** indexed by their names.
|
|
292
321
|
It won't return the exact internal hash but a duplicate and every set within it will also be a duplicate
|
|
293
322
|
of the original one.
|
|
294
323
|
|
|
@@ -303,7 +332,7 @@ Example:
|
|
|
303
332
|
```
|
|
304
333
|
|
|
305
334
|
Note that the returned hash will have a default value set to instance of the `AttributeSet`.
|
|
306
|
-
If you'll try to get the value of an element that doesn't exist **the empty set will be returned**.
|
|
335
|
+
If you'll try to get the value of an element that doesn't exist **the empty, frozen set will be returned**.
|
|
307
336
|
|
|
308
337
|
Instead of `attribute_sets` you may also use one of the aliases:
|
|
309
338
|
|
|
@@ -312,7 +341,10 @@ Instead of `attribute_sets` you may also use one of the aliases:
|
|
|
312
341
|
#### `all_attributes` ####
|
|
313
342
|
|
|
314
343
|
The [`all_attributes`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters:all_attributes)
|
|
315
|
-
method **returns the attribute set containing all known attributes**.
|
|
344
|
+
method **returns the attribute set containing all known attributes**. It combines many other sets,
|
|
345
|
+
including the sets containing attributes marked as semi-real and virtual (explained later)
|
|
346
|
+
and temporary sets obtained by calling various Rails methods. It just tries to collect as many
|
|
347
|
+
known attribute names as possible.
|
|
316
348
|
|
|
317
349
|
Example:
|
|
318
350
|
|
|
@@ -321,14 +353,25 @@ Example:
|
|
|
321
353
|
# => #<ActiveModel::AttributeSet: {"id", "username", "email", "password", "language", "created_at", "updated_at"}>
|
|
322
354
|
```
|
|
323
355
|
|
|
324
|
-
Be aware that this method requires that the used ORM has `attributes`
|
|
356
|
+
Be aware that this method requires that the used ORM has `attributes` method available for a model object.
|
|
325
357
|
|
|
326
358
|
Instead of `all_attributes` you may also use the alias:
|
|
327
359
|
|
|
328
360
|
* `all_attributes_set`
|
|
329
|
-
|
|
361
|
+
|
|
330
362
|
or call the instance method `attribute_set` without arguments.
|
|
331
363
|
|
|
364
|
+
The `all_attributes` synopsis is really:
|
|
365
|
+
|
|
366
|
+
* `all_attributes(simple = false, no_presence_check = true)`
|
|
367
|
+
|
|
368
|
+
First argument (`simple`) causes the method to not wrap the result in a transparent proxy
|
|
369
|
+
object that brings some syntactic sugar (explained later).
|
|
370
|
+
|
|
371
|
+
Second argument (`no_presence_check`) causes the method to not
|
|
372
|
+
check if each attribute exists by verifying presence of its accessor
|
|
373
|
+
in case of semi-real attributes set that is merged into the resulting set.
|
|
374
|
+
|
|
332
375
|
#### `all_accessible_attributes` ####
|
|
333
376
|
|
|
334
377
|
The [`all_accessible_attributes`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters:all_accessible_attributes)
|
|
@@ -340,12 +383,57 @@ Example:
|
|
|
340
383
|
User.first.all_accessible_attributes
|
|
341
384
|
# => #<ActiveModel::AttributeSet: {"username", "email", "language"}>
|
|
342
385
|
```
|
|
343
|
-
|
|
344
|
-
|
|
386
|
+
Be aware that this method requires that the used ORM has `accessible_attributes` method available for a model
|
|
387
|
+
class. This method works only if your Rails application supoorts accessible attributes (versions up to 3 support it).
|
|
345
388
|
|
|
346
389
|
Instead of `all_accessible_attributes` you may also use the alias:
|
|
347
390
|
|
|
348
391
|
* `accessible_attributes_set`
|
|
392
|
+
|
|
393
|
+
Instead of `all_accessible_attributes` you may also use:
|
|
394
|
+
|
|
395
|
+
* `all_accessible_attributes(true)`
|
|
396
|
+
|
|
397
|
+
It works the same way but doesn't wrap the result in a transparent proxy
|
|
398
|
+
object that brings some syntactic sugar (explained later).
|
|
399
|
+
|
|
400
|
+
#### `all_inaccessible_attributes` ####
|
|
401
|
+
|
|
402
|
+
The [`all_inaccessible_attributes`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters:all_inaccessible_attributes)
|
|
403
|
+
method **returns the attribute set containing all inaccessible attributes**.
|
|
404
|
+
|
|
405
|
+
Example:
|
|
406
|
+
|
|
407
|
+
```ruby
|
|
408
|
+
User.first.all_inaccessible_attributes
|
|
409
|
+
# => #<ActiveModel::AttributeSet: {"id", "confirmation_token", "encrypted_password", "deleted_at"}>
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
Be aware that this method requires that the used ORM has `accessible_attributes` and `protected_attributes`
|
|
413
|
+
method available in a model. This method works only if your Rails application supoorts accessible
|
|
414
|
+
attributes (versions up to 3 support it).
|
|
415
|
+
|
|
416
|
+
Instead of `all_inaccessible_attributes` you may also use the alias:
|
|
417
|
+
|
|
418
|
+
* `inaccessible_attributes_set`
|
|
419
|
+
|
|
420
|
+
Instead of `all_inaccessible_attributes` you may also use:
|
|
421
|
+
|
|
422
|
+
* `all_inaccessible_attributes(true)`
|
|
423
|
+
|
|
424
|
+
It works the same way but doesn't wrap the result in a transparent proxy
|
|
425
|
+
object that brings some syntactic sugar (explained later).
|
|
426
|
+
|
|
427
|
+
The `all_inaccessible_attributes` synopsis is really:
|
|
428
|
+
|
|
429
|
+
* `all_inaccessible_attributes(simple = false, no_presence_check = true)`
|
|
430
|
+
|
|
431
|
+
First argument (`simple`) causes the method to not wrap the result in a transparent proxy
|
|
432
|
+
object that brings some syntactic sugar (explained later).
|
|
433
|
+
|
|
434
|
+
Second argument (`no_presence_check`) causes the method to not
|
|
435
|
+
check if each attribute exists by verifying presence of its accessor
|
|
436
|
+
in case of semi-real attributes set that is used to compute the resulting set.
|
|
349
437
|
|
|
350
438
|
#### `all_protected_attributes` ####
|
|
351
439
|
|
|
@@ -356,34 +444,80 @@ Example:
|
|
|
356
444
|
|
|
357
445
|
```ruby
|
|
358
446
|
User.first.all_protected_attributes
|
|
359
|
-
# => #<ActiveModel::AttributeSet: {"id"}>
|
|
447
|
+
# => #<ActiveModel::AttributeSet: {"id", "type"}>
|
|
360
448
|
```
|
|
361
449
|
|
|
362
|
-
Be aware that this method requires that the used ORM has `protected_attributes`
|
|
450
|
+
Be aware that this method requires that the used ORM has `protected_attributes` method available for a model
|
|
451
|
+
class. This method works only if your Rails application supoorts accessible attributes (versions up to 3 support it).
|
|
363
452
|
|
|
364
453
|
Instead of `all_protected_attributes` you may also use the alias:
|
|
365
454
|
|
|
366
455
|
* `protected_attributes_set`
|
|
367
456
|
|
|
368
|
-
|
|
457
|
+
Instead of `all_protected_attributes` you may also use:
|
|
369
458
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
459
|
+
* `all_protected_attributes(true)`
|
|
460
|
+
|
|
461
|
+
It works the same way but doesn't wrap the result in a transparent proxy
|
|
462
|
+
object that brings some syntactic sugar (explained later).
|
|
463
|
+
|
|
464
|
+
#### `all_semi_real_attributes` ####
|
|
465
|
+
|
|
466
|
+
The [`all_semi_real_attributes`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters:all_semi_real_attributes)
|
|
467
|
+
method **returns the attribute set containing all attributes marked as semi-real**. This is the concept
|
|
468
|
+
of Attribute Filters used to handle attributes that aren't stored in a database (a.k.a virtual attributes, explained later).
|
|
374
469
|
|
|
375
470
|
Example:
|
|
376
471
|
|
|
377
472
|
```ruby
|
|
378
|
-
User
|
|
379
|
-
|
|
473
|
+
class User
|
|
474
|
+
treats_as_real :trololo
|
|
475
|
+
end
|
|
476
|
+
User.first.all_semi_real_attributes
|
|
477
|
+
# => #<ActiveModel::AttributeSet: {"trololo"}>
|
|
380
478
|
```
|
|
381
479
|
|
|
382
|
-
|
|
480
|
+
Instead of `all_semi_real_attributes` you may also use one of the aliases:
|
|
383
481
|
|
|
384
|
-
|
|
482
|
+
* `semi_real_attributes_set`
|
|
483
|
+
* `treat_as_real` (without arguments)
|
|
385
484
|
|
|
386
|
-
|
|
485
|
+
The `all_semi_real_attributes` synopsis is really:
|
|
486
|
+
|
|
487
|
+
* `all_semi_real_attributes(simple = false, no_presence_check = true)`
|
|
488
|
+
|
|
489
|
+
First argument (`simple`) causes the method to not wrap the result in a transparent proxy
|
|
490
|
+
object that brings some syntactic sugar (explained later).
|
|
491
|
+
|
|
492
|
+
Second argument (`no_presence_check`) causes the method to not
|
|
493
|
+
check if each attribute exists in order to include its name into set.
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
#### `all_virtual_attributes` ####
|
|
497
|
+
|
|
498
|
+
The [`all_virtual_attributes`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters:all_virtual_attributes)
|
|
499
|
+
method **returns the attribute set containing all virtual attributes**.
|
|
500
|
+
|
|
501
|
+
Example:
|
|
502
|
+
|
|
503
|
+
```ruby
|
|
504
|
+
class User
|
|
505
|
+
attr_virtual :lol
|
|
506
|
+
end
|
|
507
|
+
User.first.all_virtual_attributes
|
|
508
|
+
# => #<ActiveModel::AttributeSet: {"lol"}>
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
Instead of `all_virtual_attributes` you may also use the alias:
|
|
512
|
+
|
|
513
|
+
* `virtual_attributes_set`
|
|
514
|
+
|
|
515
|
+
Instead of `all_virtual_attributes` you may also use:
|
|
516
|
+
|
|
517
|
+
* `all_virtual_attributes(true)`
|
|
518
|
+
|
|
519
|
+
It works the same way but doesn't wrap the result in a transparent proxy
|
|
520
|
+
object that brings some syntactic sugar (explained later).
|
|
387
521
|
|
|
388
522
|
#### `filtered_attribute(attribute_name)` ####
|
|
389
523
|
|
|
@@ -391,7 +525,10 @@ The [`filtered_attribute`](http://rubydoc.info/gems/attribute-filters/ActiveMode
|
|
|
391
525
|
(a.k.a `the_attribute`) method called with a single argument is used for checking
|
|
392
526
|
**what are the sets that the attribute belongs to**. It won't return the exact set object but a duplicate.
|
|
393
527
|
It will always return AttributeSet object, even if there is no attribute of the given name
|
|
394
|
-
(in that case the resulting set will be empty).
|
|
528
|
+
(in that case the resulting set will be empty and frozen).
|
|
529
|
+
|
|
530
|
+
If the attribute name is not given or it's +nil+ then the name of an attribute is taken from the
|
|
531
|
+
name of a next method in the chain call.
|
|
395
532
|
|
|
396
533
|
Example:
|
|
397
534
|
|
|
@@ -405,11 +542,16 @@ Instead of `filtered_attribute` you may also use one of the aliases:
|
|
|
405
542
|
* `the_attribute`, `is_the_attribute`, `are_attributes`,
|
|
406
543
|
`are_the_attributes`
|
|
407
544
|
|
|
545
|
+
#### `filtered_attribute_simple(attribute_name)` ####
|
|
546
|
+
|
|
547
|
+
The `filtered_attribute_simple` method is a version of ``filtered_attribute` method that doesn't wrap the resulting
|
|
548
|
+
object in a proxy object. The attribute name must be given.
|
|
549
|
+
|
|
408
550
|
#### `attributes_to_sets` ####
|
|
409
551
|
|
|
410
552
|
The [`attributes_to_sets`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters:attributes_to_sets)
|
|
411
|
-
method returns a
|
|
412
|
-
|
|
553
|
+
method returns a meta set containing **all filtered attributes and sets that the attributes belong to**.
|
|
554
|
+
The meta set is indexed by attribute names.
|
|
413
555
|
|
|
414
556
|
Example:
|
|
415
557
|
|
|
@@ -448,6 +590,61 @@ Example:
|
|
|
448
590
|
# => false
|
|
449
591
|
```
|
|
450
592
|
|
|
593
|
+
You can also use one of the aliases:
|
|
594
|
+
|
|
595
|
+
* `invalid?`, `is_not_valid?`, `any_invalid?`, `are_not_valid?`, `not_valid?`, `is_any_invalid?`
|
|
596
|
+
* `valid?`, `is_valid?`, `are_valid?`, `all_valid?`, `are_all_valid?`
|
|
597
|
+
|
|
598
|
+
#### `changed?` and `unchanged?` ####
|
|
599
|
+
|
|
600
|
+
The `changed?` and `unchanged?` helpers allow you to test if **any** attribute listed in the set
|
|
601
|
+
has changed its value (`changed?`) or if **all** attributes from a set remain unchanged (`unchanged?`).
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
```ruby
|
|
605
|
+
u = User.first
|
|
606
|
+
u.username = ' '
|
|
607
|
+
# => " "
|
|
608
|
+
|
|
609
|
+
u.all_attributes.any_changed?
|
|
610
|
+
# => true
|
|
611
|
+
|
|
612
|
+
u.all_attributes.unchanged?
|
|
613
|
+
# => false
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
You can also use one of the aliases:
|
|
617
|
+
|
|
618
|
+
* `changed?`, `any_changed?`, `have_changed?`, `have_any_changed?`, `is_any_changed?`, `has_any_changed?`, `has_changed?`
|
|
619
|
+
* `unchanged?`, `none_changed?`, `nothing_changed?`, `is_unchanged?`, `are_all_unchanged?`, `all_unchanged?`,
|
|
620
|
+
`havent_changed?`, `arent_changed?`, `are_not_changed?`, `none_changed?`, `not_changed?`
|
|
621
|
+
|
|
622
|
+
#### `values` ####
|
|
623
|
+
|
|
624
|
+
This method simply returns the values of all attributes in a set as an array.
|
|
625
|
+
|
|
626
|
+
#### `to_set` ####
|
|
627
|
+
|
|
628
|
+
This method simply produces an object that is a kind of Set and contains all attribute names.
|
|
629
|
+
|
|
630
|
+
### `AttributeSet` enumerators ###
|
|
631
|
+
|
|
632
|
+
The `AttributeSet` class is derived from `Hash` class. The keys are attributes,
|
|
633
|
+
the values are usually `true` (`TrueClass`) or hashes (`Hash`) if there are any annotations attached
|
|
634
|
+
to attribute name. All overriden enumerators are kind of `AttributeSet::Enumerator`.
|
|
635
|
+
|
|
636
|
+
Let's see what are the differences from standard enumerators that can be found in the Hash class.
|
|
637
|
+
|
|
638
|
+
* `each` – works on keys and values (behaves like `each_pair`) but usable with just one argument in a block (key)
|
|
639
|
+
* `each_pair` – iterates throught key => value pairs
|
|
640
|
+
* `each_name_value(active_model_object, no_presence_check = false)` – iterates throught key => attribute value pairs
|
|
641
|
+
* `collect` (`map`) – produces array containg keys that may be altered by the given block
|
|
642
|
+
* `select` – selects new hash with elements for which the given block evaluates to +true+ (yields: keys, values)
|
|
643
|
+
* `select_accessible(active_model_object)` – same as `select` but picks the attributes which have accessors
|
|
644
|
+
* `reject` – reversed `select`
|
|
645
|
+
* `sort` – sorts AttributeSet object by keys
|
|
646
|
+
* `sort_by` – sorts AttributeSet object using the comparison method from a block
|
|
647
|
+
|
|
451
648
|
### Syntactic sugar for queries ###
|
|
452
649
|
|
|
453
650
|
Querying attribute sets may be even more sweet when you add some syntactic sugar
|
|
@@ -493,6 +690,25 @@ in order to help you in creating nice looking method call chains like:
|
|
|
493
690
|
User.first.attributes_that(:should_be_stripped).sort.list.present?
|
|
494
691
|
```
|
|
495
692
|
|
|
693
|
+
##### Set & attribute names as methods #####
|
|
694
|
+
|
|
695
|
+
It's possible to enter a set name or an attribute name as a name
|
|
696
|
+
of next method in a call chain instead of passing them as a symbolic argument.
|
|
697
|
+
It works with DSL instance methods `attribute_set(set_name)`
|
|
698
|
+
and `filtered_attribute(attribute_name)`.
|
|
699
|
+
|
|
700
|
+
Examples:
|
|
701
|
+
|
|
702
|
+
```ruby
|
|
703
|
+
User.first.attributes_that.should_be_stripped # same as User.first.attributes_that(:should_be_stripped)
|
|
704
|
+
User.first.attributes_that_are.required_to_use_app.present?
|
|
705
|
+
User.first.attributes_that.should_be_stripped.sort.list.present?
|
|
706
|
+
|
|
707
|
+
User.first.the_attribute.username # same as User.first.the_attribute(:username)
|
|
708
|
+
User.first.the_attribute.username.list.sets
|
|
709
|
+
User.first.the_attribute.username.valid?
|
|
710
|
+
```
|
|
711
|
+
|
|
496
712
|
##### Neutral methods #####
|
|
497
713
|
|
|
498
714
|
* **`are`**
|
|
@@ -557,7 +773,7 @@ Just imagine that:
|
|
|
557
773
|
becomes:
|
|
558
774
|
|
|
559
775
|
```ruby
|
|
560
|
-
attributes_that(:should_be_stripped).all? { |attribute| attribute
|
|
776
|
+
attributes_that(:should_be_stripped).all? { |attribute| attribute.METHOD(ARGUMENTS) }
|
|
561
777
|
```
|
|
562
778
|
|
|
563
779
|
Another example, but with `any`:
|
|
@@ -567,6 +783,13 @@ Another example, but with `any`:
|
|
|
567
783
|
# => true
|
|
568
784
|
```
|
|
569
785
|
|
|
786
|
+
You also do:
|
|
787
|
+
|
|
788
|
+
```ruby
|
|
789
|
+
User.first.attributes_that(:should_be_stripped).any.changed?
|
|
790
|
+
# => false
|
|
791
|
+
```
|
|
792
|
+
|
|
570
793
|
##### Elements selectors #####
|
|
571
794
|
|
|
572
795
|
* **`list`**
|
|
@@ -612,12 +835,72 @@ Examples:
|
|
|
612
835
|
|
|
613
836
|
u.attributes_that(:should_be_stripped).list.valid?
|
|
614
837
|
# => #<ActiveModel::AttributeSet: {"username", "email"}>
|
|
838
|
+
|
|
839
|
+
User.first.attributes_that(:should_be_stripped).is.any.valid?
|
|
840
|
+
# => true
|
|
841
|
+
|
|
842
|
+
User.first.are_attributes_that(:should_be_stripped).all.valid?
|
|
843
|
+
# => true
|
|
615
844
|
```
|
|
616
845
|
|
|
617
846
|
Be aware that calling these methods causes model object to be validated. The required condition
|
|
618
847
|
to use these methods is the ORM that has `errors` hash (Active Record has it).
|
|
619
848
|
|
|
620
|
-
|
|
849
|
+
##### Changes tracking helpers #####
|
|
850
|
+
|
|
851
|
+
* **`changed?`**
|
|
852
|
+
* **`unchanged?`**
|
|
853
|
+
|
|
854
|
+
Syntactic sugar for changes tracking is used when calls to these methods
|
|
855
|
+
are combined with selectors described above (presence selectors and elements selectors).
|
|
856
|
+
|
|
857
|
+
Examples:
|
|
858
|
+
|
|
859
|
+
```ruby
|
|
860
|
+
u = User.first
|
|
861
|
+
u.username = " "
|
|
862
|
+
|
|
863
|
+
u.attributes_that(:should_be_stripped).all.changed?
|
|
864
|
+
# => false
|
|
865
|
+
|
|
866
|
+
u.attributes_that(:should_be_stripped).any.changed?
|
|
867
|
+
# => true
|
|
868
|
+
|
|
869
|
+
u.attributes_that(:should_be_stripped).list.changed?
|
|
870
|
+
# => #<ActiveModel::AttributeSet: {"username"}>
|
|
871
|
+
|
|
872
|
+
User.first.all_attributes.is.any.unchanged?
|
|
873
|
+
# => true
|
|
874
|
+
|
|
875
|
+
User.first.all_attributes.are.none.unchanged?
|
|
876
|
+
# => false
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
Be aware that the required condition to use these methods is the ORM that
|
|
880
|
+
has `changes` hash (Active Record has it).
|
|
881
|
+
|
|
882
|
+
##### Calling custom methods #####
|
|
883
|
+
|
|
884
|
+
It's possible to call any other methods using selectors.
|
|
885
|
+
Note that te method next to the given selector will be called **on a value** of each tested attribute.
|
|
886
|
+
|
|
887
|
+
Examples:
|
|
888
|
+
|
|
889
|
+
```ruby
|
|
890
|
+
u = User.first
|
|
891
|
+
|
|
892
|
+
u.attributes_that(:should_be_stripped).all.is_a?(String)
|
|
893
|
+
# => false
|
|
894
|
+
|
|
895
|
+
u.attributes_that(:should_be_stripped).any.is_a?(String)
|
|
896
|
+
# => false
|
|
897
|
+
|
|
898
|
+
u.attributes_that(:should_be_stripped).list.is_a?(String)
|
|
899
|
+
# => #<ActiveModel::AttributeSet: {"username", "email"}>
|
|
900
|
+
```
|
|
901
|
+
|
|
902
|
+
|
|
903
|
+
#### Querying attributes ####
|
|
621
904
|
|
|
622
905
|
Querying attributes to know sets they belong to uses one
|
|
623
906
|
instance method available in your models:
|
|
@@ -655,10 +938,14 @@ Example:
|
|
|
655
938
|
|
|
656
939
|
```ruby
|
|
657
940
|
User.first.the_attribute(:username).list.sets
|
|
658
|
-
# =>
|
|
941
|
+
# => {:should_be_downcased => true, :should_be_stripped => true}
|
|
942
|
+
|
|
943
|
+
User.first.the_attribute(:username).list.sets.to_a
|
|
944
|
+
# => [:should_be_downcased, :should_be_stripped]
|
|
945
|
+
|
|
659
946
|
```
|
|
660
947
|
|
|
661
|
-
#####
|
|
948
|
+
##### Attribute membership querying #####
|
|
662
949
|
|
|
663
950
|
* **`belongs_to?`**
|
|
664
951
|
* **`in?`**
|
|
@@ -686,7 +973,7 @@ Example:
|
|
|
686
973
|
# => true
|
|
687
974
|
```
|
|
688
975
|
|
|
689
|
-
#####
|
|
976
|
+
##### Attribute membership testing #####
|
|
690
977
|
|
|
691
978
|
Membership querying has different syntax from simple testing.
|
|
692
979
|
It uses set name with the question mark attached to it.
|
|
@@ -704,7 +991,7 @@ with question mark. Otherwise you may get false positives
|
|
|
704
991
|
or a strange errors when trying to test if attribute belongs
|
|
705
992
|
to a set. The real method call will override your check.
|
|
706
993
|
|
|
707
|
-
#####
|
|
994
|
+
##### Attribute accessibility testing #####
|
|
708
995
|
|
|
709
996
|
* **`accessible?`**
|
|
710
997
|
* **`inaccessible?`**
|
|
@@ -727,6 +1014,91 @@ Examples:
|
|
|
727
1014
|
# => true
|
|
728
1015
|
```
|
|
729
1016
|
|
|
1017
|
+
Be aware that this method requires that the used ORM has `accessible_attributes` and `protected_attributes` methods
|
|
1018
|
+
available in a model. This method works only if your Rails application supoorts accessible attributes (versions up to 3 support it).
|
|
1019
|
+
|
|
1020
|
+
##### Attribute validity testing #####
|
|
1021
|
+
|
|
1022
|
+
* **`valid?`**
|
|
1023
|
+
* **`invalid?`**
|
|
1024
|
+
* **`is_valid?`**
|
|
1025
|
+
* **`is_invalid?`**
|
|
1026
|
+
|
|
1027
|
+
The methods above allow you to test if certain attribute that changed is valid or invalid.
|
|
1028
|
+
|
|
1029
|
+
Examples:
|
|
1030
|
+
|
|
1031
|
+
```ruby
|
|
1032
|
+
u = User.first
|
|
1033
|
+
u.username = ' '
|
|
1034
|
+
u.the_attribute(:username).is.valid?
|
|
1035
|
+
# => false
|
|
1036
|
+
u.the_attribute(:username).is_valid?
|
|
1037
|
+
# => false
|
|
1038
|
+
u.the_attribute(:username).invalid?
|
|
1039
|
+
# => true
|
|
1040
|
+
```
|
|
1041
|
+
|
|
1042
|
+
Be aware that this method requires that the used ORM has `valid?` and `errors` methods that allow to validate
|
|
1043
|
+
model on demand. Also note that validations will run when using that methods.
|
|
1044
|
+
|
|
1045
|
+
##### Attribute change testing #####
|
|
1046
|
+
|
|
1047
|
+
* **`changed?`**
|
|
1048
|
+
* **`unchanged?`**
|
|
1049
|
+
* **`is_changed?`**
|
|
1050
|
+
* **`is_unchanged?`**
|
|
1051
|
+
* **`has_changed?`**
|
|
1052
|
+
* **`hasnt_changed?`**
|
|
1053
|
+
* **`not_changed?`**
|
|
1054
|
+
|
|
1055
|
+
The methods above allow you to test if certain attribute changed recently or not.
|
|
1056
|
+
|
|
1057
|
+
Examples:
|
|
1058
|
+
|
|
1059
|
+
```ruby
|
|
1060
|
+
u = User.first
|
|
1061
|
+
u.username = ' '
|
|
1062
|
+
u.the_attribute(:username).has_changed?
|
|
1063
|
+
# => true
|
|
1064
|
+
u.the_attribute(:id).unchanged?
|
|
1065
|
+
# => true
|
|
1066
|
+
```
|
|
1067
|
+
|
|
1068
|
+
Be aware that this method requires that the used ORM has `changes` method that allows to query a model for
|
|
1069
|
+
all changed attributes.
|
|
1070
|
+
|
|
1071
|
+
##### Attribute virtuality testing #####
|
|
1072
|
+
|
|
1073
|
+
* **`semi_real?`**
|
|
1074
|
+
* **`virtual?`**
|
|
1075
|
+
* **`is_semi_real?`**
|
|
1076
|
+
* **`is_virtual?`**
|
|
1077
|
+
|
|
1078
|
+
The methods above allow to you to test if certain attribute is virtual or semi-real (explained later).
|
|
1079
|
+
|
|
1080
|
+
```ruby
|
|
1081
|
+
u = User.first
|
|
1082
|
+
u.the_attribute(:id).is.virtual?
|
|
1083
|
+
# => false
|
|
1084
|
+
u.the_attribute(:id).is.semi_real?
|
|
1085
|
+
# => false
|
|
1086
|
+
```
|
|
1087
|
+
|
|
1088
|
+
##### Attribute value querying #####
|
|
1089
|
+
|
|
1090
|
+
* `value`
|
|
1091
|
+
|
|
1092
|
+
Using the `value` method you can get the current value of an attribute.
|
|
1093
|
+
|
|
1094
|
+
Example:
|
|
1095
|
+
|
|
1096
|
+
```ruby
|
|
1097
|
+
u = User.first
|
|
1098
|
+
u.the_attribute.username.value
|
|
1099
|
+
# => "admin"
|
|
1100
|
+
```
|
|
1101
|
+
|
|
730
1102
|
Attribute filters
|
|
731
1103
|
-----------------
|
|
732
1104
|
|
|
@@ -748,9 +1120,9 @@ class User < ActiveRecord::Base
|
|
|
748
1120
|
|
|
749
1121
|
# Defining attribute sets
|
|
750
1122
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
1123
|
+
its_attribute real_name: [ :should_be_stripped, :should_be_capitalized ]
|
|
1124
|
+
its_attribute username: [ :should_be_stripped, :should_be_downcased ]
|
|
1125
|
+
its_attribute email: [ :should_be_stripped, :should_be_downcased ]
|
|
754
1126
|
|
|
755
1127
|
# Registering filtering callback methods
|
|
756
1128
|
|
|
@@ -760,6 +1132,10 @@ class User < ActiveRecord::Base
|
|
|
760
1132
|
|
|
761
1133
|
# Defining filtering methods
|
|
762
1134
|
|
|
1135
|
+
has_filtering_method :downcase_names, :should_be_downcased
|
|
1136
|
+
has_filtering_method :capitalize_names, :should_be_capitalized
|
|
1137
|
+
has_filtering_method :strip_names, :should_be_stripped
|
|
1138
|
+
|
|
763
1139
|
def downcase_names
|
|
764
1140
|
filter_attributes_that :should_be_downcased do |atr|
|
|
765
1141
|
atr.mb_chars.downcase.to_s
|
|
@@ -805,7 +1181,7 @@ The evaluated block can make use of the following arguments that are passed to i
|
|
|
805
1181
|
* `set_name` [Symbol] - a name of the processed attribute set
|
|
806
1182
|
* `args` [Array] - an optional arguments passed to the method
|
|
807
1183
|
|
|
808
|
-
By default only existing, changed and non-blank attributes are processed.
|
|
1184
|
+
By default only **existing, changed and non-blank** attributes are processed.
|
|
809
1185
|
You can change that behavior by adding a flags as the first arguments:
|
|
810
1186
|
|
|
811
1187
|
* `:process_blank` – tells to also process attributes that are blank (empty or `nil`)
|
|
@@ -813,11 +1189,15 @@ You can change that behavior by adding a flags as the first arguments:
|
|
|
813
1189
|
* `:no_presence_check` – tells not to check for existence of each processed attribute when processing
|
|
814
1190
|
all attributes; increases performance but you must care about putting only the existing attributes into sets
|
|
815
1191
|
|
|
1192
|
+
The checking mentioned in `:no_presence_check` flag description is done by querying internal Rails hashes
|
|
1193
|
+
containing known attributes and internal sets containing virtual attributes added by `attr_virtual` or
|
|
1194
|
+
`treats_as_real` keywords (described later).
|
|
1195
|
+
|
|
816
1196
|
Example:
|
|
817
1197
|
|
|
818
1198
|
```ruby
|
|
819
1199
|
class User
|
|
820
|
-
|
|
1200
|
+
has_attribute_that should_be_lolized: :username
|
|
821
1201
|
before_validation :lolize
|
|
822
1202
|
|
|
823
1203
|
def lolize
|
|
@@ -825,6 +1205,7 @@ Example:
|
|
|
825
1205
|
[attribute_value, set_name.to_s, attribute_name, *args.flatten].join('-')
|
|
826
1206
|
end
|
|
827
1207
|
end
|
|
1208
|
+
filtering_method :lolize, :should_be_lolized
|
|
828
1209
|
end
|
|
829
1210
|
|
|
830
1211
|
u = User.new
|
|
@@ -869,12 +1250,18 @@ You can change that behavior by adding a flags as the first arguments:
|
|
|
869
1250
|
* `:process_all` - tells to process all attributes, not just the ones that has changed
|
|
870
1251
|
* `:no_presence_check` – tells not to check for existence of each processed attribute when processing
|
|
871
1252
|
all attributes; increases performance but you must care about putting only the existing attributes into sets
|
|
1253
|
+
* `:include_missing` – includes attributes that does not exist in a resulting iteration (their values are
|
|
1254
|
+
always `nil`); has the effect only when `:process_blank` and `:no_presence_check` are present
|
|
1255
|
+
|
|
1256
|
+
The checking mentioned in `:no_presence_check` flag description is done by querying internal Rails hashes
|
|
1257
|
+
containing known attributes and internal sets containing virtual attributes added by `attr_virtual` or
|
|
1258
|
+
`treats_as_real` keywords (described later).
|
|
872
1259
|
|
|
873
1260
|
Example:
|
|
874
1261
|
|
|
875
1262
|
```ruby
|
|
876
1263
|
class User
|
|
877
|
-
|
|
1264
|
+
has_attribute_that should_be_lolized: :username
|
|
878
1265
|
before_validation :lolize
|
|
879
1266
|
|
|
880
1267
|
def lolize
|
|
@@ -882,6 +1269,7 @@ Example:
|
|
|
882
1269
|
attribute_object << '-' << [set_name.to_s, attribute_name, *args.flatten].join('-')
|
|
883
1270
|
end
|
|
884
1271
|
end
|
|
1272
|
+
filtering_method :lolize, :should_be_lolized
|
|
885
1273
|
end
|
|
886
1274
|
|
|
887
1275
|
u = User.new
|
|
@@ -936,226 +1324,177 @@ if the filtering operation occured.
|
|
|
936
1324
|
|
|
937
1325
|
There are cases that virtual attributes (the ones that does not really exist in a database)
|
|
938
1326
|
are to be filtered. By default it won't happen since all the filtering methods assume
|
|
939
|
-
the presence of any processed attribute as 'a real' attribute. There are
|
|
940
|
-
to overcome that problem.
|
|
941
|
-
|
|
942
|
-
#### Unconditional filtering ####
|
|
1327
|
+
the presence of any processed attribute as 'a real' attribute. There are different ways
|
|
1328
|
+
to overcome that problem. First two methods described below are recommended.
|
|
943
1329
|
|
|
944
|
-
|
|
945
|
-
That causes filter to be executed for each attribute from a set without any conditions (no checking
|
|
946
|
-
for presence of setter/getter method and no checking for changes).
|
|
1330
|
+
#### Marking as virtual ####
|
|
947
1331
|
|
|
948
|
-
|
|
949
|
-
|
|
1332
|
+
Since version 1.4.0 of Attribute Filters the **recommended way of dealing with
|
|
1333
|
+
virtual attributes** is to make use of Active Model's changes tracking.
|
|
1334
|
+
To do that look at your ORM's documentation and see
|
|
1335
|
+
[`ActiveModel::Dirty`](http://api.rubyonrails.org/classes/ActiveModel/Dirty.html)
|
|
1336
|
+
and a method `attribute_will_change` that it contains. Just call that method from within
|
|
1337
|
+
your setter and you're done.
|
|
950
1338
|
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
to be executed more often than needed, since the changes tracking is disabled (`process_all`).
|
|
1339
|
+
This approach can be easily used with predefined filters. The benefit of it,
|
|
1340
|
+
contrary to other methods, is that a filter will never be called redundantly.
|
|
954
1341
|
|
|
955
|
-
|
|
1342
|
+
You should use the built-in DSL keyword **`attr_virtual`** that will create
|
|
1343
|
+
setter and getter for you.
|
|
956
1344
|
|
|
957
1345
|
```ruby
|
|
958
|
-
class User
|
|
1346
|
+
class User < ActiveRecord::Base
|
|
959
1347
|
|
|
960
1348
|
# declare a virtual attribute
|
|
961
|
-
|
|
1349
|
+
attr_virtual :real_name
|
|
962
1350
|
|
|
963
1351
|
# define a set
|
|
964
|
-
|
|
1352
|
+
has_attributes_that :should_be_splitted => [ :real_name ]
|
|
965
1353
|
|
|
966
1354
|
# register a callback method
|
|
967
1355
|
before_validation :split_attributes
|
|
968
1356
|
|
|
969
1357
|
# create a filtering method
|
|
970
1358
|
def split_attributes
|
|
971
|
-
for_attributes_that(:should_be_splitted
|
|
1359
|
+
for_attributes_that(:should_be_splitted) do |value|
|
|
972
1360
|
names = value.split(' ')
|
|
973
|
-
self.first_name = names[0]
|
|
974
|
-
self.last_name = names[1]
|
|
1361
|
+
self.first_name = names[0]
|
|
1362
|
+
self.last_name = names[1]
|
|
975
1363
|
end
|
|
976
1364
|
end
|
|
1365
|
+
filtering_method :split_attributes, :should_be_splitted
|
|
977
1366
|
|
|
978
1367
|
end
|
|
979
1368
|
```
|
|
980
1369
|
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
The second way is to use `treat_attributes_as_real` (or simply `treat_as_real`) clause in your model
|
|
984
|
-
(available from version 1.2.0 of Attribute Filters). That approach may be applied to attributes
|
|
985
|
-
that aren't (may not or should not be) tracked for changes and aren't (may not or should not be) accessible
|
|
986
|
-
(to a controller) nor marked as protected.
|
|
987
|
-
|
|
988
|
-
There are two main differences from the unconditional filtering. First is that marking attribute
|
|
989
|
-
as real causes it to be added to the list of all known attributes that is returned by `all_attributes_set`
|
|
990
|
-
(a.k.a `all_attributes`). The second is that nothing ugly will happen if there will be non-existent
|
|
991
|
-
attributes in a set when filtering method kicks in. That's because the filtering method doesn't require
|
|
992
|
-
`:no_presence_check` flag to pick up such attributes. Attributes that could not be handled are simply ignored.
|
|
993
|
-
|
|
994
|
-
The `:process_all` flag is also not needed since all virtual attributes marked as real are by default
|
|
995
|
-
not checked for changes.
|
|
1370
|
+
Note that for Rails version 3 you may need to declare attribute as accessible using `attr_accessible`
|
|
1371
|
+
if you want controllers to be able to update its value through assignment passed to model.
|
|
996
1372
|
|
|
997
|
-
|
|
1373
|
+
You may change the setter and getter for vitrtual attribute on you own, but it should be done
|
|
1374
|
+
somewhere in the code **before** the `attr_virtual` clause. That will allow `attr_virtual`
|
|
1375
|
+
to wrap you methods and enable tracking of changes for the attribute.
|
|
998
1376
|
|
|
999
1377
|
```ruby
|
|
1000
|
-
class User
|
|
1001
|
-
|
|
1002
|
-
# declare a virtual attribute
|
|
1003
|
-
attr_accessor :real_name
|
|
1004
|
-
|
|
1005
|
-
# mark the attribute as real
|
|
1006
|
-
treat_as_real :real_name
|
|
1378
|
+
class User < ActiveRecord::Base
|
|
1007
1379
|
|
|
1008
1380
|
# define a set
|
|
1009
|
-
|
|
1381
|
+
has_attributes_that :should_be_splitted => [ :real_name ]
|
|
1010
1382
|
|
|
1011
1383
|
# register a callback method
|
|
1012
|
-
before_validation :split_attributes
|
|
1384
|
+
before_validation :split_attributes # you could also use :filter_attributes here
|
|
1013
1385
|
|
|
1014
1386
|
# create a filtering method
|
|
1015
1387
|
def split_attributes
|
|
1016
1388
|
for_attributes_that(:should_be_splitted) do |value|
|
|
1017
1389
|
names = value.split(' ')
|
|
1018
|
-
self.first_name = names[0]
|
|
1019
|
-
self.last_name = names[1]
|
|
1390
|
+
self.first_name = names[0]
|
|
1391
|
+
self.last_name = names[1]
|
|
1020
1392
|
end
|
|
1021
1393
|
end
|
|
1394
|
+
filtering_method :split_attributes, :should_be_splitted
|
|
1022
1395
|
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
That may lead to strange results under some circumstances, e.g. in case of
|
|
1029
|
-
cutting some part of a string stored in a virtual attribute by using a filter
|
|
1030
|
-
registered with `before_save`; if such operation will be performed
|
|
1031
|
-
more than once then the filtering will be performed more than once too.
|
|
1032
|
-
|
|
1033
|
-
The presence of virtual attributes is tested by checking if both, a setter and a getter,
|
|
1034
|
-
methods exist, unless the `no_presence_check` flag is passed to a filtering method.
|
|
1035
|
-
If both accessors don't exist then the attribute is not processed.
|
|
1396
|
+
# own setter
|
|
1397
|
+
def real_name=(val)
|
|
1398
|
+
# do somehing specific here (or not)
|
|
1399
|
+
@real_name = val
|
|
1400
|
+
end
|
|
1036
1401
|
|
|
1037
|
-
|
|
1402
|
+
# own getter
|
|
1403
|
+
def real_name
|
|
1404
|
+
# do somehing specific here (or not)
|
|
1405
|
+
@real_name
|
|
1406
|
+
end
|
|
1038
1407
|
|
|
1039
|
-
|
|
1408
|
+
attr_virtual :real_name
|
|
1040
1409
|
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
To do that look at your ORM's documentation and see
|
|
1044
|
-
[`ActiveModel::Dirty`](http://api.rubyonrails.org/classes/ActiveModel/Dirty.html)
|
|
1045
|
-
and a method `attribute_will_change` that it contains. Just call that method from within
|
|
1046
|
-
your setter and you're done.
|
|
1410
|
+
end
|
|
1411
|
+
```
|
|
1047
1412
|
|
|
1048
|
-
|
|
1413
|
+
#### Unconditional filtering ####
|
|
1049
1414
|
|
|
1050
|
-
|
|
1415
|
+
The next way to filter virtual attribute is to pass the `:no_presence_check` and `:process_all` flags
|
|
1416
|
+
to the filtering method. That causes filter to be executed for each attribute from a set without
|
|
1417
|
+
any conditions (no checking for presence of setter/getter method and no checking for changes).
|
|
1051
1418
|
|
|
1052
|
-
|
|
1053
|
-
|
|
1419
|
+
Be aware that by doing that you take full responsibility for attribute set names added to your set.
|
|
1420
|
+
If you put a name of nonexistent attribute then you may get ugly error later.
|
|
1054
1421
|
|
|
1055
|
-
|
|
1056
|
-
|
|
1422
|
+
With that approach you can filter virtual attributes that are inaccessible to controllers
|
|
1423
|
+
and don't show up when model is queried for known attributes. Using it may also cause some filters
|
|
1424
|
+
to be executed more often than needed, since the changes tracking is disabled (`process_all`).
|
|
1057
1425
|
|
|
1058
1426
|
Example:
|
|
1059
1427
|
|
|
1060
1428
|
```ruby
|
|
1061
|
-
class User
|
|
1062
|
-
|
|
1063
|
-
# declare a virtual attribute
|
|
1064
|
-
attr_reader :real_name
|
|
1065
|
-
attr_accessible :real_name
|
|
1429
|
+
class User
|
|
1066
1430
|
|
|
1067
1431
|
# define a set
|
|
1068
|
-
|
|
1432
|
+
has_attributes_that :should_be_splitted => [ :real_name ]
|
|
1069
1433
|
|
|
1070
1434
|
# register a callback method
|
|
1071
|
-
before_validation :split_attributes
|
|
1072
|
-
|
|
1073
|
-
# create writer that notifies Active Model about changes
|
|
1074
|
-
def real_name=(val)
|
|
1075
|
-
attribute_will_change!('real_name') if val != real_name
|
|
1076
|
-
@real_name = val
|
|
1077
|
-
end
|
|
1435
|
+
before_validation :split_attributes # you could also use :filter_attributes here
|
|
1078
1436
|
|
|
1079
1437
|
# create a filtering method
|
|
1080
1438
|
def split_attributes
|
|
1081
|
-
for_attributes_that(:should_be_splitted) do |value|
|
|
1439
|
+
for_attributes_that(:should_be_splitted, :no_presence_check, :process_all) do |value|
|
|
1082
1440
|
names = value.split(' ')
|
|
1083
1441
|
self.first_name = names[0] # assuming first_name exists in a database
|
|
1084
1442
|
self.last_name = names[1] # assuming last_name exists in a database
|
|
1085
1443
|
end
|
|
1086
1444
|
end
|
|
1445
|
+
filtering_method :split_attributes, :should_be_splitted
|
|
1087
1446
|
|
|
1088
1447
|
end
|
|
1089
1448
|
```
|
|
1090
1449
|
|
|
1091
|
-
|
|
1092
|
-
for you:
|
|
1093
|
-
|
|
1094
|
-
```ruby
|
|
1095
|
-
class User < ActiveRecord::Base
|
|
1096
|
-
|
|
1097
|
-
# declare a virtual attribute
|
|
1098
|
-
attr_virtual :real_name
|
|
1099
|
-
attr_accessible :real_name
|
|
1100
|
-
|
|
1101
|
-
# define a set
|
|
1102
|
-
attributes_that :should_be_splitted => [ :real_name ]
|
|
1103
|
-
|
|
1104
|
-
# register a callback method
|
|
1105
|
-
before_validation :split_attributes
|
|
1106
|
-
|
|
1107
|
-
# create a filtering method
|
|
1108
|
-
def split_attributes
|
|
1109
|
-
for_attributes_that(:should_be_splitted) do |value|
|
|
1110
|
-
names = value.split(' ')
|
|
1111
|
-
self.first_name = names[0]
|
|
1112
|
-
self.last_name = names[1]
|
|
1113
|
-
end
|
|
1114
|
-
end
|
|
1450
|
+
#### Marking as semi-real ####
|
|
1115
1451
|
|
|
1116
|
-
|
|
1117
|
-
|
|
1452
|
+
There is also a way that bases on using `treats_attributes_as_real` (or simply `treats_as_real`) clause in your model
|
|
1453
|
+
(available from version 1.2.0 of Attribute Filters). That approach may be applied to attributes
|
|
1454
|
+
that aren't (may not or should not be) tracked for changes and aren't (may not or should not be) accessible
|
|
1455
|
+
(to a controller) nor marked as protected (if using Rails version <= 3).
|
|
1118
1456
|
|
|
1119
|
-
|
|
1457
|
+
There are two main differences from the unconditional filtering. First is that marking attribute
|
|
1458
|
+
as real causes it to be added to the list of all known attributes that is returned by `all_attributes_set`
|
|
1459
|
+
(a.k.a `all_attributes`). The second is that nothing ugly will happen if there will be non-existent
|
|
1460
|
+
attributes in a set when filtering method kicks in. That's because the filtering method doesn't require
|
|
1461
|
+
`:no_presence_check` flag to pick up such attributes. Attributes that cannot be handled are simply ignored.
|
|
1120
1462
|
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
or `attr_protected`.
|
|
1463
|
+
The `:process_all` flag is also not needed since all attributes marked as semi-real are by default
|
|
1464
|
+
not checked for changes.
|
|
1124
1465
|
|
|
1125
1466
|
Example:
|
|
1126
1467
|
|
|
1127
1468
|
```ruby
|
|
1128
|
-
class User
|
|
1129
|
-
|
|
1130
|
-
# declare a virtual attribute
|
|
1131
|
-
attr_virtual :real_name
|
|
1469
|
+
class User
|
|
1132
1470
|
|
|
1133
1471
|
# mark the attribute as real
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
# tell the engine that all virtual attributes
|
|
1137
|
-
# are tracked for changes and it should pick from changed
|
|
1138
|
-
# not from all
|
|
1139
|
-
virtual_attributes_are_tracked
|
|
1472
|
+
treats_as_real :real_name
|
|
1140
1473
|
|
|
1141
1474
|
# define a set
|
|
1142
|
-
|
|
1475
|
+
has_attributes_that :should_be_splitted => [ :real_name ]
|
|
1143
1476
|
|
|
1144
1477
|
# register a callback method
|
|
1145
|
-
before_validation :split_attributes
|
|
1478
|
+
before_validation :split_attributes # you could also use :filter_attributes here
|
|
1146
1479
|
|
|
1147
1480
|
# create a filtering method
|
|
1148
1481
|
def split_attributes
|
|
1149
1482
|
for_attributes_that(:should_be_splitted) do |value|
|
|
1150
1483
|
names = value.split(' ')
|
|
1151
|
-
self.first_name = names[0]
|
|
1152
|
-
self.last_name = names[1]
|
|
1484
|
+
self.first_name = names[0] # assuming first_name exists in a database
|
|
1485
|
+
self.last_name = names[1] # assuming last_name exists in a database
|
|
1153
1486
|
end
|
|
1154
1487
|
end
|
|
1488
|
+
filtering_method :split_attributes, :should_be_splitted
|
|
1155
1489
|
|
|
1156
1490
|
end
|
|
1157
1491
|
```
|
|
1158
1492
|
|
|
1493
|
+
Instead of `treat_as_real` you may also use one of its aliases:
|
|
1494
|
+
|
|
1495
|
+
* `attribute_filters_semi_real`, `treat_attribute_as_real`, `treat_attributes_as_real`,
|
|
1496
|
+
`treats_attribute_as_real`, `treats_attributes_as_real`, `treats_as_real`,
|
|
1497
|
+
|
|
1159
1498
|
Annotations
|
|
1160
1499
|
-----------
|
|
1161
1500
|
|
|
@@ -1189,7 +1528,7 @@ Example:
|
|
|
1189
1528
|
# Annotation key: some_key
|
|
1190
1529
|
# Annotation value: some value
|
|
1191
1530
|
|
|
1192
|
-
|
|
1531
|
+
has_attributes_that_are cool: { :email => { :some_key => "some value" } }
|
|
1193
1532
|
end
|
|
1194
1533
|
```
|
|
1195
1534
|
|
|
@@ -1198,7 +1537,7 @@ You can mix annotated attributes with unannotated; just put the last ones in fro
|
|
|
1198
1537
|
|
|
1199
1538
|
```ruby
|
|
1200
1539
|
class User
|
|
1201
|
-
|
|
1540
|
+
has_attributes_that_are cool: [ :some_unannotated, { :email => { :some_key => "some value" } } ]
|
|
1202
1541
|
end
|
|
1203
1542
|
```
|
|
1204
1543
|
|
|
@@ -1206,7 +1545,7 @@ or
|
|
|
1206
1545
|
|
|
1207
1546
|
```ruby
|
|
1208
1547
|
class User
|
|
1209
|
-
|
|
1548
|
+
has_attributes_that_are :cool => [ :some_unannotated, { :email => { :some_key => "some value" } } ]
|
|
1210
1549
|
end
|
|
1211
1550
|
```
|
|
1212
1551
|
|
|
@@ -1220,15 +1559,23 @@ To create annotations for class-level sets use the [`annotate_attribute_set`](ht
|
|
|
1220
1559
|
* **`annotate_attributes_for`**
|
|
1221
1560
|
* **`annotate_attributes_set`**
|
|
1222
1561
|
* **`annotate_properties_that`**
|
|
1223
|
-
* **`annotate_attributes`**
|
|
1562
|
+
* **`annotate_attributes`**
|
|
1563
|
+
* **`annotates_attributes_that_are`**
|
|
1564
|
+
* **`annotates_attributes_that`**
|
|
1565
|
+
* **`annotates_attributes_are`**
|
|
1566
|
+
* **`annotates_attributes_for`**
|
|
1567
|
+
* **`annotates_attributes_set`**
|
|
1568
|
+
* **`annotates_properties_that`**
|
|
1569
|
+
* **`annotates_attributes`**
|
|
1570
|
+
* **`attribute_set_annotate`**
|
|
1224
1571
|
|
|
1225
1572
|
Example:
|
|
1226
1573
|
|
|
1227
1574
|
```ruby
|
|
1228
1575
|
class User
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1576
|
+
has_attributes_that_are cool: [ :some_unannotated, :email, :username ]
|
|
1577
|
+
annotates_attributes_that_are cool: [ :email, :some_key, "some value" ]
|
|
1578
|
+
annotates_attributes_that_are :cool => { :username => { :some_key => "some value", :other_k => 'other v' } }
|
|
1232
1579
|
end
|
|
1233
1580
|
```
|
|
1234
1581
|
|
|
@@ -1262,48 +1609,52 @@ Be aware that using these method to delete annotations from class-level sets won
|
|
|
1262
1609
|
That's because you'll always get a copy when querying these sets. However there are methods that
|
|
1263
1610
|
will work in a model:
|
|
1264
1611
|
|
|
1265
|
-
* **`
|
|
1266
|
-
* **`
|
|
1267
|
-
* **`
|
|
1268
|
-
* **`
|
|
1612
|
+
* **`delete_annotation_from_set(set_name, attribute, *annotation_keys)`** - to delete annotation keys for the given attribute
|
|
1613
|
+
* **`delete_annotation_from_set(set_name, attribute)`** - to delete all annotation keys for the given attribute
|
|
1614
|
+
* **`delete_annotation_from_set(set_name => *attributes)`** - to delete all annotation keys for the given attribute
|
|
1615
|
+
* **`delete_annotation_from_set(set_name => { attribute => keys})`** - to delete specified annotation keys for the given attributes
|
|
1616
|
+
|
|
1617
|
+
Instead of `delete_annotation_from_set` you may use the aliases:
|
|
1618
|
+
|
|
1619
|
+
* `delete_annotations_from_set`, `delete_annotation_from_set`, `deletes_annotations_from_set`
|
|
1269
1620
|
|
|
1270
1621
|
Example:
|
|
1271
1622
|
|
|
1272
1623
|
```ruby
|
|
1273
1624
|
class User
|
|
1274
|
-
|
|
1625
|
+
has_attributes_that_are cool: [ :some_unannotated, :email ]
|
|
1275
1626
|
|
|
1276
1627
|
# That will work
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1628
|
+
deletes_annotations_from_set cool: :email
|
|
1629
|
+
deletes_annotations_from_set cool: [ :email, :key_one ]
|
|
1630
|
+
deletes_annotation_from_set cool: { :email => [:key_one, :other_key], :name => :some_key }
|
|
1280
1631
|
|
|
1281
1632
|
# That won't affect the global set called 'cool'
|
|
1282
|
-
# since we have its copy
|
|
1633
|
+
# since we have its copy, not the original.
|
|
1283
1634
|
def some_method
|
|
1284
1635
|
attributes_that_are(:cool).delete_annotation(:email)
|
|
1285
1636
|
end
|
|
1286
1637
|
|
|
1287
1638
|
# That won't affect the global set called 'cool'
|
|
1288
|
-
# since
|
|
1639
|
+
# since the method returns its copy, not the original.
|
|
1289
1640
|
attributes_that_are(:cool).delete_annotation(:email)
|
|
1290
1641
|
end
|
|
1291
1642
|
```
|
|
1292
1643
|
|
|
1293
1644
|
### Updating annotations ###
|
|
1294
1645
|
|
|
1295
|
-
Calling `annotate` method again on a set or redefining set at
|
|
1296
|
-
or modify their keys.
|
|
1646
|
+
Calling `annotate` method again on a set or redefining set at the class-level allows to add annotations
|
|
1647
|
+
or to modify their keys.
|
|
1297
1648
|
|
|
1298
1649
|
Example:
|
|
1299
1650
|
|
|
1300
1651
|
```ruby
|
|
1301
1652
|
class User
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1653
|
+
has_attributes_that_are :cool => { :email => { :some_key => "some value" } }
|
|
1654
|
+
has_attributes_that_are cool: { :email => { :other_key => "other_value" } }
|
|
1655
|
+
has_attributes_that_are cool: { :email => { :some_key => "another_value" } }
|
|
1656
|
+
annotates_attributes_that_are :cool, :email, :some_key => "x"
|
|
1657
|
+
deletes_annotation_from_set :cool => { :email => :other_key }
|
|
1307
1658
|
end
|
|
1308
1659
|
|
|
1309
1660
|
# In the result there will be only one annotation key left;
|
|
@@ -1319,7 +1670,7 @@ a copy when querying these sets.
|
|
|
1319
1670
|
|
|
1320
1671
|
```ruby
|
|
1321
1672
|
class User
|
|
1322
|
-
|
|
1673
|
+
has_attributes_that_are :cool => { :email => { :some_key => "some value" } }
|
|
1323
1674
|
|
|
1324
1675
|
# Calling `some_method` won't work on 'cool' global set.
|
|
1325
1676
|
def some_method
|
|
@@ -1339,8 +1690,8 @@ To check if a set has any annotations you can use one of the methods:
|
|
|
1339
1690
|
|
|
1340
1691
|
To read annotations you can use :
|
|
1341
1692
|
|
|
1342
|
-
* **`annotation(attribute_name)`** - gets a hash of annotations or returns nil
|
|
1343
|
-
* **`annotation(attribute_name, *keys)`** - gets an array annotation values for the given keys (puts
|
|
1693
|
+
* **`annotation(attribute_name)`** - gets a hash of annotations or returns `nil`
|
|
1694
|
+
* **`annotation(attribute_name, *keys)`** - gets an array annotation values for the given keys (puts `nil`s if key is missing) or returns `nil`
|
|
1344
1695
|
|
|
1345
1696
|
Example:
|
|
1346
1697
|
|
|
@@ -1362,38 +1713,51 @@ Example:
|
|
|
1362
1713
|
end
|
|
1363
1714
|
```
|
|
1364
1715
|
|
|
1716
|
+
To read **all annotations** use `annotations` method called on an attribute set. For instance:
|
|
1717
|
+
|
|
1718
|
+
```ruby
|
|
1719
|
+
User.first.attributes_that(:should_be_splitted).annotations
|
|
1720
|
+
# => {"some_name"=>{:split_into=>[:first_part, :second_part]}}
|
|
1721
|
+
```
|
|
1722
|
+
|
|
1723
|
+
As you can see it returns a hash with attribute names as keys and annotations as values.
|
|
1724
|
+
If some attribute from a set doesn't have any annotations then it's not included in the results.
|
|
1725
|
+
|
|
1365
1726
|
Predefined filters
|
|
1366
1727
|
------------------
|
|
1367
1728
|
|
|
1368
|
-
Predefined filters are ready-to-use methods
|
|
1369
|
-
for filtering attributes. You just have to call them
|
|
1729
|
+
Predefined filters are ready-to-use methods for filtering attributes. You just have to call them
|
|
1370
1730
|
or register them as [callbacks](http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html).
|
|
1371
1731
|
|
|
1372
1732
|
To use all predefined filters you have to manually
|
|
1373
1733
|
include the [`ActiveModel::AttributeFilters::Common`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters/Common)
|
|
1374
1734
|
module. That will include **all available filtering methods** into your model.
|
|
1375
1735
|
|
|
1736
|
+
Predefined filters work by utilizing global attribute sets with predetermined names. For example,
|
|
1737
|
+
a common filter that downcases attributes will use the set called `:should_be_downcased`.
|
|
1738
|
+
|
|
1376
1739
|
Example:
|
|
1377
1740
|
|
|
1378
1741
|
```ruby
|
|
1379
1742
|
class User < ActiveRecord::Base
|
|
1380
1743
|
include ActiveModel::AttributeFilters::Common
|
|
1381
1744
|
|
|
1382
|
-
|
|
1745
|
+
its_attribute name: [:should_be_downcased, :should_be_titleized ]
|
|
1383
1746
|
|
|
1384
1747
|
before_validation :downcase_attributes
|
|
1385
1748
|
before_validation :titleize_attributes
|
|
1386
1749
|
end
|
|
1387
1750
|
```
|
|
1388
1751
|
|
|
1389
|
-
If you don't want to include portions of code that you'll never use
|
|
1752
|
+
If you don't want to include portions of code that you'll never use in your model classes, you may
|
|
1753
|
+
want to include some filters selectively. To do that just include a submodule containing needed filtering method:
|
|
1390
1754
|
|
|
1391
1755
|
```ruby
|
|
1392
1756
|
class User < ActiveRecord::Base
|
|
1393
1757
|
include ActiveModel::AttributeFilters::Common::Downcase
|
|
1394
1758
|
include ActiveModel::AttributeFilters::Common::Titleize
|
|
1395
1759
|
|
|
1396
|
-
|
|
1760
|
+
its_attribute name: [:should_be_downcased, :should_be_titleized ]
|
|
1397
1761
|
|
|
1398
1762
|
before_validation :downcase_attributes
|
|
1399
1763
|
before_validation :titleize_attributes
|
|
@@ -1411,28 +1775,36 @@ For example, to squeeze attributes `name` and `email` you can write:
|
|
|
1411
1775
|
```ruby
|
|
1412
1776
|
class User < ActiveRecord::Base
|
|
1413
1777
|
include ActiveModel::AttributeFilters::Common::Squeeze
|
|
1414
|
-
|
|
1778
|
+
has_attributes_that should_be_squeezed: [:email, :name]
|
|
1415
1779
|
before_validation :squeeze_attributes
|
|
1416
1780
|
end
|
|
1417
1781
|
```
|
|
1418
1782
|
|
|
1783
|
+
### Filtering keywords ###
|
|
1784
|
+
|
|
1419
1785
|
The filtering methods usually come with class-level DSL methods
|
|
1420
|
-
that are
|
|
1421
|
-
|
|
1786
|
+
that are helpful wrappers. They are simply calling `the_attribute`
|
|
1787
|
+
method to add some attributes to a proper set for you.
|
|
1788
|
+
|
|
1789
|
+
So you can also write:
|
|
1422
1790
|
|
|
1423
1791
|
```ruby
|
|
1424
1792
|
class User < ActiveRecord::Base
|
|
1425
1793
|
include ActiveModel::AttributeFilters::Common::Squeeze
|
|
1426
|
-
|
|
1427
|
-
before_validation
|
|
1794
|
+
squeezes_attributes :email, :name
|
|
1795
|
+
before_validation :squeeze_attributes
|
|
1428
1796
|
end
|
|
1429
1797
|
```
|
|
1430
1798
|
|
|
1431
|
-
|
|
1799
|
+
Some of these helpers are doing some extra work to make things syntactically easier
|
|
1800
|
+
than with using pure sets. Check the list if common filters for more information.
|
|
1801
|
+
|
|
1802
|
+
### Calling all filters ###
|
|
1432
1803
|
|
|
1433
1804
|
There is a special method called
|
|
1434
|
-
[`filter_attributes`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters.html#filter_attributes-instance_method) that can be registered as a callback. It will call all
|
|
1435
|
-
|
|
1805
|
+
[`filter_attributes`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters.html#filter_attributes-instance_method) that can be registered as a callback. It will call all filtering methods which sets (that they're assigned to)
|
|
1806
|
+
are non-empty. In other words it will run specific filtering method for each global attribute set if the set exists
|
|
1807
|
+
and contains at least one element. The calling order is the same as the order of adding sets in your model class.
|
|
1436
1808
|
|
|
1437
1809
|
Example:
|
|
1438
1810
|
|
|
@@ -1441,615 +1813,143 @@ class User < ActiveRecord::Base
|
|
|
1441
1813
|
include ActiveModel::AttributeFilters::Common::Squeeze
|
|
1442
1814
|
include ActiveModel::AttributeFilters::Common::Capitalize
|
|
1443
1815
|
|
|
1444
|
-
|
|
1445
|
-
|
|
1816
|
+
squeezes_attributes :email, :name
|
|
1817
|
+
capitalizes_attribute :name
|
|
1446
1818
|
|
|
1447
1819
|
before_validation :filter_attributes
|
|
1448
1820
|
end
|
|
1449
1821
|
```
|
|
1450
1822
|
|
|
1451
|
-
|
|
1452
|
-
You can also create your own method like that and call all needed filters there:
|
|
1453
|
-
|
|
1454
|
-
```ruby
|
|
1455
|
-
class User < ActiveRecord::Base
|
|
1456
|
-
include ActiveModel::AttributeFilters::Common::Squeeze
|
|
1457
|
-
include ActiveModel::AttributeFilters::Common::Capitalize
|
|
1458
|
-
|
|
1459
|
-
squeeze_attributes :email, :name
|
|
1460
|
-
capitalize_attributes :name
|
|
1461
|
-
|
|
1462
|
-
before_validation :my_total_filtering_method
|
|
1463
|
-
|
|
1464
|
-
def my_total_filtering_method
|
|
1465
|
-
squeeze_attributes
|
|
1466
|
-
capitalize_attributes
|
|
1467
|
-
end
|
|
1468
|
-
end
|
|
1469
|
-
```
|
|
1470
|
-
|
|
1471
|
-
But to increase readability you should go with the old-fashion way and register
|
|
1472
|
-
each filtering callback method separately.
|
|
1473
|
-
|
|
1474
|
-
### Data types ###
|
|
1475
|
-
|
|
1476
|
-
The common filters are aware and can operate on attributes that
|
|
1477
|
-
are arrays or hashes. If an array or a hash is detected then
|
|
1478
|
-
the filtering is made **recursively** for each element (or for each value in case
|
|
1479
|
-
of a hash) and the produced structure is returned. If the attribute has an
|
|
1480
|
-
unknown type then its value is not altered at all and left intact.
|
|
1481
|
-
|
|
1482
|
-
Some of the common filters may treat arrays and hashes in a slight different
|
|
1483
|
-
way (e.g. joining and splitting filters do that).
|
|
1484
|
-
|
|
1485
|
-
The common filters are aware of multibyte strings so string
|
|
1486
|
-
operations should handle diacritics properly.
|
|
1487
|
-
|
|
1488
|
-
### List of filters ###
|
|
1489
|
-
|
|
1490
|
-
* **`capitalize_attributes`**
|
|
1491
|
-
* **`fully_capitalize_attributes`**
|
|
1492
|
-
* **`titleize_attributes`**
|
|
1493
|
-
* **`downcase_attributes`**
|
|
1494
|
-
* **`upcase_attributes`**
|
|
1495
|
-
* **`strip_attributes`**
|
|
1496
|
-
* **`squeeze_attributes`**
|
|
1497
|
-
* **`squish_attributes`**
|
|
1498
|
-
|
|
1499
|
-
See the
|
|
1500
|
-
[`ActiveModel::AttributeFilters::Common`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters/Common)
|
|
1501
|
-
for detailed descriptions.
|
|
1502
|
-
|
|
1503
|
-
#### Case ####
|
|
1504
|
-
|
|
1505
|
-
* Submodule: [`Case`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters/Common/Case.html)
|
|
1506
|
-
|
|
1507
|
-
##### `capitalize_attributes` #####
|
|
1508
|
-
|
|
1509
|
-
Capitalizes attributes.
|
|
1510
|
-
|
|
1511
|
-
* Callback method: `capitalize_attributes`
|
|
1512
|
-
* Class-level helper: `capitalize_attributes(*attribute_names)`
|
|
1513
|
-
* Uses set: `:should_be_capitalized`
|
|
1514
|
-
* Operates on: strings, arrays of strings, hashes of strings (as values)
|
|
1515
|
-
* Uses annotations: no
|
|
1516
|
-
|
|
1517
|
-
Example:
|
|
1518
|
-
|
|
1519
|
-
```ruby
|
|
1520
|
-
class User < ActiveRecord::Base
|
|
1521
|
-
include ActiveModel::AttributeFilters::Common::Case
|
|
1522
|
-
|
|
1523
|
-
capitalize_attributes :name
|
|
1524
|
-
before_validation :capitalize_attributes
|
|
1525
|
-
end
|
|
1526
|
-
```
|
|
1527
|
-
|
|
1528
|
-
or
|
|
1529
|
-
|
|
1530
|
-
```ruby
|
|
1531
|
-
class User < ActiveRecord::Base
|
|
1532
|
-
include ActiveModel::AttributeFilters::Common::Case
|
|
1533
|
-
|
|
1534
|
-
attributes_that :should_be_capitalized => [ :name ]
|
|
1535
|
-
before_validation :capitalize_attributes
|
|
1536
|
-
end
|
|
1537
|
-
```
|
|
1538
|
-
|
|
1539
|
-
Then:
|
|
1540
|
-
|
|
1541
|
-
> `"some name"`
|
|
1542
|
-
|
|
1543
|
-
will become:
|
|
1544
|
-
|
|
1545
|
-
> `"Some name"`
|
|
1546
|
-
|
|
1547
|
-
##### `fully_capitalize_attributes` #####
|
|
1548
|
-
|
|
1549
|
-
Capitalizes attributes and squeezes spaces that separate strings.
|
|
1550
|
-
|
|
1551
|
-
* Callback method: `fully_capitalize_attributes`
|
|
1552
|
-
* Class-level helper: `fully_capitalize_attributes(*attribute_names)`
|
|
1553
|
-
* Uses set: `:should_be_fully_capitalized` and `:should_be_titleized`
|
|
1554
|
-
* Operates on: strings, arrays of strings, hashes of strings (as values)
|
|
1555
|
-
* Uses annotations: no
|
|
1556
|
-
|
|
1557
|
-
Example:
|
|
1558
|
-
|
|
1559
|
-
```ruby
|
|
1560
|
-
class User < ActiveRecord::Base
|
|
1561
|
-
include ActiveModel::AttributeFilters::Common::Case
|
|
1562
|
-
|
|
1563
|
-
fully_capitalize_attributes :name
|
|
1564
|
-
before_validation :fully_capitalize_attributes
|
|
1565
|
-
end
|
|
1566
|
-
```
|
|
1567
|
-
|
|
1568
|
-
or
|
|
1569
|
-
|
|
1570
|
-
```ruby
|
|
1571
|
-
class User < ActiveRecord::Base
|
|
1572
|
-
include ActiveModel::AttributeFilters::Common::Case
|
|
1573
|
-
|
|
1574
|
-
attributes_that :should_be_fully_capitalized => [ :name ]
|
|
1575
|
-
before_validation :fully_capitalize_attributes
|
|
1576
|
-
end
|
|
1577
|
-
```
|
|
1578
|
-
|
|
1579
|
-
Then:
|
|
1580
|
-
|
|
1581
|
-
> `"some name"`
|
|
1582
|
-
|
|
1583
|
-
will become:
|
|
1584
|
-
|
|
1585
|
-
> `"Some Name"`
|
|
1586
|
-
|
|
1587
|
-
##### `titleize_attributes` #####
|
|
1588
|
-
|
|
1589
|
-
Titleizes attributes.
|
|
1590
|
-
|
|
1591
|
-
* Callback method: `titleize_attributes`
|
|
1592
|
-
* Class-level helper: `titleize_attributes(*attribute_names)`
|
|
1593
|
-
* Uses set: `:should_be_titleized`
|
|
1594
|
-
* Operates on: strings, arrays of strings, hashes of strings (as values)
|
|
1595
|
-
* Uses annotations: no
|
|
1596
|
-
|
|
1597
|
-
Example:
|
|
1598
|
-
|
|
1599
|
-
```ruby
|
|
1600
|
-
class User < ActiveRecord::Base
|
|
1601
|
-
include ActiveModel::AttributeFilters::Common::Case
|
|
1602
|
-
|
|
1603
|
-
titleize_attributes :name
|
|
1604
|
-
before_validation :titleize_attributes
|
|
1605
|
-
end
|
|
1606
|
-
```
|
|
1607
|
-
|
|
1608
|
-
or
|
|
1823
|
+
Or even more simpler (but it will include all common filters):
|
|
1609
1824
|
|
|
1610
1825
|
```ruby
|
|
1611
1826
|
class User < ActiveRecord::Base
|
|
1612
|
-
include ActiveModel::AttributeFilters::Common
|
|
1613
|
-
|
|
1614
|
-
attributes_that :should_be_titleized => [ :name ]
|
|
1615
|
-
before_validation :titleize_attributes
|
|
1616
|
-
end
|
|
1617
|
-
```
|
|
1618
|
-
|
|
1619
|
-
Then:
|
|
1620
|
-
|
|
1621
|
-
> `"some name"`
|
|
1622
|
-
|
|
1623
|
-
will become:
|
|
1624
|
-
|
|
1625
|
-
> `"Some Name"`
|
|
1626
|
-
|
|
1627
|
-
##### `upcase_attributes` #####
|
|
1628
|
-
|
|
1629
|
-
Upcases attributes.
|
|
1630
|
-
|
|
1631
|
-
* Callback method: `upcase_attributes`
|
|
1632
|
-
* Class-level helper: `upcase_attributes(*attribute_names)`
|
|
1633
|
-
* Uses set: `:should_be_upcased`
|
|
1634
|
-
* Operates on: strings, arrays of strings, hashes of strings (as values)
|
|
1635
|
-
* Uses annotations: no
|
|
1636
|
-
|
|
1637
|
-
Example:
|
|
1638
|
-
|
|
1639
|
-
```ruby
|
|
1640
|
-
class User < ActiveRecord::Base
|
|
1641
|
-
include ActiveModel::AttributeFilters::Common::Case
|
|
1642
|
-
|
|
1643
|
-
upcase_attributes :name
|
|
1644
|
-
before_validation :upcase_attributes
|
|
1645
|
-
end
|
|
1646
|
-
```
|
|
1647
|
-
|
|
1648
|
-
or
|
|
1827
|
+
include ActiveModel::AttributeFilters::Common
|
|
1649
1828
|
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
include ActiveModel::AttributeFilters::Common::Case
|
|
1829
|
+
squeezes_attributes :email, :name
|
|
1830
|
+
capitalizes_attribute :name
|
|
1653
1831
|
|
|
1654
|
-
|
|
1655
|
-
before_validation :upcase_attributes
|
|
1832
|
+
before_validation :filter_attributes
|
|
1656
1833
|
end
|
|
1657
1834
|
```
|
|
1658
1835
|
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
> `"some name"`
|
|
1662
|
-
|
|
1663
|
-
will become:
|
|
1664
|
-
|
|
1665
|
-
> `"SOME NAME"`
|
|
1666
|
-
|
|
1667
|
-
##### `downcase_attributes` #####
|
|
1668
|
-
|
|
1669
|
-
Downcases attributes.
|
|
1836
|
+
The method of using common filters presented in he example above
|
|
1837
|
+
is the easiest and the most consistent one.
|
|
1670
1838
|
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
* Uses set: `:should_be_downcased`
|
|
1674
|
-
* Operates on: strings, arrays of strings, hashes of strings (as values)
|
|
1675
|
-
* Uses annotations: no
|
|
1676
|
-
|
|
1677
|
-
Example:
|
|
1839
|
+
Of course the `filter_attributes` will also work if the sets are
|
|
1840
|
+
specified explicitly:
|
|
1678
1841
|
|
|
1679
1842
|
```ruby
|
|
1680
1843
|
class User < ActiveRecord::Base
|
|
1681
|
-
include ActiveModel::AttributeFilters::Common
|
|
1682
|
-
|
|
1683
|
-
downcase_attributes :name
|
|
1684
|
-
before_validation :downcase_attributes
|
|
1685
|
-
end
|
|
1686
|
-
```
|
|
1687
|
-
|
|
1688
|
-
or
|
|
1844
|
+
include ActiveModel::AttributeFilters::Common
|
|
1689
1845
|
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
include ActiveModel::AttributeFilters::Common::Case
|
|
1846
|
+
has_attributes_that :should_be_squeezed => [ :email, :name ]
|
|
1847
|
+
has_attributes_that :should_be_capitalized => :name
|
|
1693
1848
|
|
|
1694
|
-
|
|
1695
|
-
before_validation :downcase_attributes
|
|
1849
|
+
before_validation :filter_attributes
|
|
1696
1850
|
end
|
|
1697
1851
|
```
|
|
1698
1852
|
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
> `"some name"`
|
|
1706
|
-
|
|
1707
|
-
#### Strip ####
|
|
1708
|
-
|
|
1709
|
-
* Submodule: [`Strip`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters/Common/Strip.html)
|
|
1710
|
-
|
|
1711
|
-
##### `strip_attributes` #####
|
|
1853
|
+
To know which methods are known to `filter_attributes`
|
|
1854
|
+
use the `filtering_methods` instance method
|
|
1855
|
+
available in your model. It returns a meta set containing
|
|
1856
|
+
attributes set names as keys and the methods assigned
|
|
1857
|
+
to them as values (both are symbols).
|
|
1712
1858
|
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
* Operates on: strings, arrays of strings, hashes of strings (as values)
|
|
1719
|
-
* Uses annotations: no
|
|
1720
|
-
|
|
1721
|
-
Example:
|
|
1722
|
-
|
|
1723
|
-
```ruby
|
|
1724
|
-
class User < ActiveRecord::Base
|
|
1725
|
-
include ActiveModel::AttributeFilters::Common::Strip
|
|
1726
|
-
|
|
1727
|
-
strip_attributes :name
|
|
1728
|
-
before_validation :strip_attributes
|
|
1729
|
-
end
|
|
1730
|
-
```
|
|
1731
|
-
|
|
1732
|
-
or
|
|
1859
|
+
Note that the method above returns **all** known
|
|
1860
|
+
methods marked as filtering methods, including those
|
|
1861
|
+
that might not be called until a proper set will
|
|
1862
|
+
be defined. To check what methods will actually be
|
|
1863
|
+
called (at a given time) use:
|
|
1733
1864
|
|
|
1734
1865
|
```ruby
|
|
1735
|
-
|
|
1736
|
-
include ActiveModel::AttributeFilters::Common::Strip
|
|
1737
|
-
|
|
1738
|
-
attributes_that :should_be_stripped => [ :name ]
|
|
1739
|
-
before_validation :strip_attributes
|
|
1740
|
-
end
|
|
1866
|
+
(attribute_sets & filtering_methods).values
|
|
1741
1867
|
```
|
|
1742
1868
|
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
> `" Some Name "`
|
|
1746
|
-
|
|
1747
|
-
will become:
|
|
1748
|
-
|
|
1749
|
-
> `"Some Name"`
|
|
1869
|
+
### Custom filtering order ###
|
|
1750
1870
|
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
##### `squeeze_attributes` #####
|
|
1756
|
-
|
|
1757
|
-
Squeezes attributes (squeezes repeating spaces into one).
|
|
1758
|
-
|
|
1759
|
-
* Callback method: `squeeze_attributes`
|
|
1760
|
-
* Class-level helper: `squeeze_attributes(*attribute_names)`
|
|
1761
|
-
* Uses set: `:should_be_squeezed`
|
|
1762
|
-
* Operates on: strings, arrays of strings, hashes of strings (as values)
|
|
1763
|
-
* Uses annotations: no
|
|
1764
|
-
|
|
1765
|
-
Example:
|
|
1871
|
+
Instead of relaying on `filter_attributes` you may create
|
|
1872
|
+
your own callback method containing invocations of your
|
|
1873
|
+
filtering methods in the desired order (independent from
|
|
1874
|
+
the "natural" order, based on adding the sets to model class):
|
|
1766
1875
|
|
|
1767
1876
|
```ruby
|
|
1768
1877
|
class User < ActiveRecord::Base
|
|
1769
|
-
include ActiveModel::AttributeFilters::Common
|
|
1878
|
+
include ActiveModel::AttributeFilters::Common
|
|
1770
1879
|
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
end
|
|
1774
|
-
```
|
|
1880
|
+
has_attributes_that :should_be_squeezed => [ :email, :name ]
|
|
1881
|
+
has_attribute_that :should_be_capitalized => :name
|
|
1775
1882
|
|
|
1776
|
-
|
|
1883
|
+
before_validation :prepare_attributes
|
|
1777
1884
|
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
attributes_that :should_be_squeezed => [ :name ]
|
|
1783
|
-
before_validation :squeeze_attributes
|
|
1885
|
+
def prepare_attributes
|
|
1886
|
+
capitalize_attributes # common filter that uses the set called :should_be_capitalized
|
|
1887
|
+
squeeze_attributes # common filter that uses the set called :should_be_squeezed
|
|
1888
|
+
end
|
|
1784
1889
|
end
|
|
1785
1890
|
```
|
|
1786
1891
|
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
> `"Some Name"`
|
|
1892
|
+
Or you can just register multiple callbacks to achieve the same
|
|
1893
|
+
result.
|
|
1790
1894
|
|
|
1791
|
-
|
|
1895
|
+
### Custom filtering methods ###
|
|
1792
1896
|
|
|
1793
|
-
|
|
1897
|
+
You can create your own filtering methods and they will be called
|
|
1898
|
+
among others by `filter_attributes`. You just have to use special
|
|
1899
|
+
DSL class method called `filtering_method` to mark your method
|
|
1900
|
+
and assign its name to some global attribute set (not used by
|
|
1901
|
+
any other filtering method).
|
|
1794
1902
|
|
|
1795
|
-
|
|
1903
|
+
Synopsis:
|
|
1796
1904
|
|
|
1797
|
-
|
|
1905
|
+
* `filtering_method(method_name, set_name)`
|
|
1798
1906
|
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
* Operates on: strings, arrays of strings, hashes of strings (as values)
|
|
1803
|
-
* Uses annotations: no
|
|
1907
|
+
The global set of the given name will be looked up when callback
|
|
1908
|
+
method `filter_attributes` will be called and if non-empty then
|
|
1909
|
+
the registered method will be called (among others).
|
|
1804
1910
|
|
|
1805
1911
|
Example:
|
|
1806
1912
|
|
|
1807
1913
|
```ruby
|
|
1808
1914
|
class User < ActiveRecord::Base
|
|
1809
|
-
include ActiveModel::AttributeFilters::Common
|
|
1810
|
-
|
|
1811
|
-
squish_attributes :name
|
|
1812
|
-
before_validation :squish_attributes
|
|
1813
|
-
end
|
|
1814
|
-
```
|
|
1815
|
-
|
|
1816
|
-
or
|
|
1817
|
-
|
|
1818
|
-
```ruby
|
|
1819
|
-
class User < ActiveRecord::Base
|
|
1820
|
-
include ActiveModel::AttributeFilters::Common::Squeeze
|
|
1821
|
-
|
|
1822
|
-
attributes_that :should_be_squished => [ :name ]
|
|
1823
|
-
before_validation :squish_attributes
|
|
1824
|
-
end
|
|
1825
|
-
```
|
|
1826
|
-
|
|
1827
|
-
Then:
|
|
1828
|
-
|
|
1829
|
-
> `" Some Name"`
|
|
1830
|
-
|
|
1831
|
-
will become:
|
|
1832
|
-
|
|
1833
|
-
> `"Some Name"`
|
|
1834
|
-
|
|
1835
|
-
#### Split ####
|
|
1836
|
-
|
|
1837
|
-
* Submodule: [`Split`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters/Common/Split.html)
|
|
1838
|
-
|
|
1839
|
-
##### `split_attributes` #####
|
|
1840
|
-
|
|
1841
|
-
Splits attributes into arrays and puts the results into other attributes or into the same attributes.
|
|
1842
|
-
|
|
1843
|
-
* Callback methods: `split_attributes`
|
|
1844
|
-
* Class-level helpers:
|
|
1845
|
-
* `split_attributes(attribute_name, parameters_hash)`
|
|
1846
|
-
* `split_attributes(attribute_name)`
|
|
1847
|
-
* Uses set: `:should_be_splitted`
|
|
1848
|
-
* Operates on: strings, arrays of strings, hashes of strings (as values)
|
|
1849
|
-
* Uses annotations: yes
|
|
1850
|
-
* `split_pattern` - a pattern passed to [`split`](http://www.ruby-doc.org/core/String.html#method-i-split) method (optional)
|
|
1851
|
-
* `split_limit` - a limit passed to `split` method (optional)
|
|
1852
|
-
* `split_into` - attribute names used as destinations for parts
|
|
1853
|
-
* `split_flatten` - flag that causes resulting array to be flattened
|
|
1854
|
-
|
|
1855
|
-
If some source attribute is an array or a hash then the filter will recursively traverse it and
|
|
1856
|
-
operate on each element. The filter works the same way as the `split` method from the `String` class
|
|
1857
|
-
of Ruby's standard library. If the filter encounters an object which is not a string nor an array or a hash,
|
|
1858
|
-
it simply leaves it as is.
|
|
1859
|
-
|
|
1860
|
-
You can set `:pattern` (`:split_pattern`) and `:limit` (`:split_limit`) arguments passed to
|
|
1861
|
-
`split` method but note that **a limit is applied to each processed string separately**,
|
|
1862
|
-
not to the resulting array **(if the processed attribute is an array)**. For instance,
|
|
1863
|
-
if there is a string containing 3 words (`'A B C'`) and the limit is set to 2 then the last two words
|
|
1864
|
-
will be left intact and placed in a second element of the resulting array (`['A', 'B C']`).
|
|
1865
|
-
If the source is an array (`['A', 'B B B B', 'C']`) the result of this operation will be array of arrays
|
|
1866
|
-
(`[ ['A'], ['B B'], ['C'] ]`); as you can see the limit will be applied to its second element.
|
|
1867
|
-
|
|
1868
|
-
If there are no destination attributes defined (`:into` or `:split_into` option) then
|
|
1869
|
-
the resulting array will be written to a current attribute. If there are destination attributes
|
|
1870
|
-
given then the resulting array will be written into them (each subsequent element into each next attribute).
|
|
1871
|
-
The elements that don't fit in the collection are simply ignored.
|
|
1872
|
-
|
|
1873
|
-
There is also `flatten` (or `:split_flatten`) parameter that causes the resulting array to be
|
|
1874
|
-
flattened. Note that it doesn't change how the limits work; they still will be applied but to a single
|
|
1875
|
-
split results, not to the whole resulting array (in case of array of arrays).
|
|
1876
|
-
|
|
1877
|
-
Examples:
|
|
1878
|
-
|
|
1879
|
-
```ruby
|
|
1880
|
-
class User < ActiveRecord::Base
|
|
1881
|
-
# Including common filter for splitting
|
|
1882
|
-
include ActiveModel::AttributeFilters::Common::Split
|
|
1883
|
-
|
|
1884
|
-
# Registering virtual attribute
|
|
1885
|
-
attr_virtual :real_name
|
|
1886
|
-
attr_accessible :real_name
|
|
1887
|
-
|
|
1888
|
-
# Adding attribute name to :should_be_splitted set
|
|
1889
|
-
split_attributes :real_name
|
|
1890
|
-
|
|
1891
|
-
# Registering callback method
|
|
1892
|
-
# Warning: it will be executed each time model object is validated
|
|
1893
|
-
# (the nice thing is that it allows to validate the results, not the unsplitted data)
|
|
1894
|
-
before_validation :split_attributes
|
|
1895
|
-
end
|
|
1896
|
-
```
|
|
1897
|
-
|
|
1898
|
-
or without a `split_attributes` helper:
|
|
1899
|
-
|
|
1900
|
-
```ruby
|
|
1901
|
-
class User < ActiveRecord::Base
|
|
1902
|
-
# Including common filter for splitting
|
|
1903
|
-
include ActiveModel::AttributeFilters::Common::Split
|
|
1904
|
-
|
|
1905
|
-
# Registering virtual attribute
|
|
1906
|
-
attr_virtual :real_name
|
|
1907
|
-
attr_accessible :real_name
|
|
1908
|
-
|
|
1909
|
-
# Adding attribute name to :should_be_splitted set (by hand)
|
|
1910
|
-
attributes_that :should_be_splitted => :real_name
|
|
1911
|
-
|
|
1912
|
-
# Registering callback method
|
|
1913
|
-
before_validation :split_attributes
|
|
1914
|
-
end
|
|
1915
|
-
```
|
|
1916
|
-
|
|
1917
|
-
The result of executing the filter above will be replacement of a string by an array containing
|
|
1918
|
-
words (each one in a separate element). The `real_name` attribute is a virtual attribute in this example
|
|
1919
|
-
but it could be real attribute. The result will be written as an array into the same attribute since there
|
|
1920
|
-
are no destination attributes given. So `'Paul Wolf'` will become `['Paul', 'Wolf']`.
|
|
1921
|
-
|
|
1922
|
-
Using limit:
|
|
1923
|
-
|
|
1924
|
-
```ruby
|
|
1925
|
-
class User < ActiveRecord::Base
|
|
1926
|
-
include ActiveModel::AttributeFilters::Common::Split
|
|
1927
|
-
|
|
1928
|
-
attr_virtual :real_name
|
|
1929
|
-
attr_accessible :real_name
|
|
1930
|
-
split_attributes :real_name, :limit => 2
|
|
1931
|
-
before_validation :split_attributes
|
|
1932
|
-
end
|
|
1933
|
-
```
|
|
1934
|
-
|
|
1935
|
-
or without a `split_attributes` keyword:
|
|
1936
|
-
|
|
1937
|
-
```ruby
|
|
1938
|
-
class User < ActiveRecord::Base
|
|
1939
|
-
include ActiveModel::AttributeFilters::Common::Split
|
|
1940
|
-
|
|
1941
|
-
attr_virtual :real_name
|
|
1942
|
-
attr_accessible :real_name
|
|
1943
|
-
|
|
1944
|
-
attributes_that :should_be_splitted => { :real_name => { :split_limit => 2 } }
|
|
1945
|
-
before_validation :split_attributes
|
|
1946
|
-
end
|
|
1947
|
-
```
|
|
1948
|
-
|
|
1949
|
-
The result of the above example will be the same as the previous one with the difference that any
|
|
1950
|
-
reduntant elements will be left intact and placed as the last element of an array. So for data:
|
|
1951
|
-
|
|
1952
|
-
> `'Paul Thomas Wolf'`
|
|
1953
|
-
|
|
1954
|
-
the array will be:
|
|
1955
|
-
|
|
1956
|
-
> `[ 'Paul', 'Thomas Wolf' ]`
|
|
1957
|
-
|
|
1958
|
-
Another example, let's write results to some attributes:
|
|
1915
|
+
include ActiveModel::AttributeFilters::Common
|
|
1959
1916
|
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
include ActiveModel::AttributeFilters::Common::Split
|
|
1917
|
+
has_attributes_that should_be_happy: [ :username, :real_name ]
|
|
1918
|
+
before_validation :filter_attributes
|
|
1963
1919
|
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1920
|
+
def happify
|
|
1921
|
+
filter_attributes_that(:should_be_happy) do |v, o|
|
|
1922
|
+
v + "-happy"
|
|
1923
|
+
end
|
|
1924
|
+
end
|
|
1925
|
+
filtering_method :happify, :should_be_happy
|
|
1968
1926
|
end
|
|
1969
1927
|
```
|
|
1970
1928
|
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
This will split a value of the `real_name` attribute and place the results in the attributes
|
|
1974
|
-
called `first_name` and `last_name`, so for:
|
|
1975
|
-
|
|
1976
|
-
> `'Paul Thomas Wolf'`
|
|
1977
|
-
|
|
1978
|
-
the result will be:
|
|
1979
|
-
|
|
1980
|
-
```
|
|
1981
|
-
first_name: 'Paul'
|
|
1982
|
-
last_name: 'Thomas Wolf'
|
|
1983
|
-
```
|
|
1984
|
-
|
|
1985
|
-
If you remove the limit, then it will be quite different:
|
|
1986
|
-
|
|
1987
|
-
```
|
|
1988
|
-
first_name: 'Paul'
|
|
1989
|
-
last_name: 'Thomas'
|
|
1990
|
-
```
|
|
1991
|
-
|
|
1992
|
-
That's because there are more results than attributes they fit into. You just have to keep in mind
|
|
1993
|
-
that this filter behaves like the String's split method with the difference when the results are written
|
|
1994
|
-
into other attributes. In that case the limit causes redundant data to be placed in the last element (if a limit
|
|
1995
|
-
is lower or is the same as the count of destination attributes) and its lack causes some of the resulting data to
|
|
1996
|
-
be ignored (if there are more slices than receiving attributes).
|
|
1997
|
-
|
|
1998
|
-
The pattern parameter (`:pattern` when using `split_attributes` or `:split_pattern` when directly
|
|
1999
|
-
annotating attribute in a set) should be a string.
|
|
2000
|
-
|
|
2001
|
-
#### Join ####
|
|
2002
|
-
|
|
2003
|
-
* Submodule: [`Join`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters/Common/Join.html)
|
|
2004
|
-
|
|
2005
|
-
##### `join_attributes` #####
|
|
2006
|
-
|
|
2007
|
-
Joins attributes and places the results into other attributes or into the same attributes as strings.
|
|
1929
|
+
Of course, you can set your own method as a callback explicitly
|
|
1930
|
+
instead of using the `filter_attributes`.
|
|
2008
1931
|
|
|
2009
|
-
|
|
2010
|
-
* Class-level helpers:
|
|
2011
|
-
* `join_attributes(attribute_name, parameters_hash)` (a.k.a `joint_attribute`)
|
|
2012
|
-
* `join_attributes(attribute_name)` (a.k.a `joint_attribute`)
|
|
2013
|
-
* Uses set: `:should_be_joined`
|
|
2014
|
-
* Operates on: strings, arrays of strings
|
|
2015
|
-
* Uses annotations: yes
|
|
2016
|
-
* `join_separator` - a pattern passed to [`join`](http://www.ruby-doc.org/core/Array.html#method-i-join) method (optional)
|
|
2017
|
-
* `join_compact` - compact flag; if true then an array is compacted before it's joined (optional)
|
|
2018
|
-
* `join_from` - attribute names used as sources for joins
|
|
2019
|
-
|
|
2020
|
-
The join filter uses `join` instance method of the `Array` class to produce single string from multiple strings.
|
|
2021
|
-
These strings may be values of other attributes (source attributes), values of an array stored in an attribute
|
|
2022
|
-
or mix of it. If the `:compact` (`:join_compact` in case of manually annotating a set) parameter is given
|
|
2023
|
-
and it's not `false` nor `nil` then results are compacted during processing. That means any slices equals to `nil` are
|
|
2024
|
-
removed.
|
|
2025
|
-
|
|
2026
|
-
If the parameter `:from` (or annotation key `:join_from`) was not given then a currently processed attribute
|
|
2027
|
-
is treated as a source (it should be an array).
|
|
2028
|
-
|
|
2029
|
-
Examples:
|
|
1932
|
+
### Data types ###
|
|
2030
1933
|
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
1934
|
+
The common filters are aware of different kinds of data and can operate
|
|
1935
|
+
on attributes that are arrays or hashes. If an array or a hash is detected then
|
|
1936
|
+
the filtering is made **recursively** for each element (or for each value in case
|
|
1937
|
+
of a hash) and the produced value is returned. If the attribute has an
|
|
1938
|
+
unknown type then its value is not altered at all and left intact.
|
|
2034
1939
|
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
join_attributes_into :real_name, :from => [ :first_name, :last_name ]
|
|
2038
|
-
before_validation :join_attributes
|
|
2039
|
-
end
|
|
2040
|
-
```
|
|
1940
|
+
Some of the common filters may treat arrays and hashes in a slight different
|
|
1941
|
+
way (e.g. joining and splitting filters do that).
|
|
2041
1942
|
|
|
2042
|
-
|
|
1943
|
+
The common filters are aware of multibyte strings so string
|
|
1944
|
+
operations should handle diacritics properly.
|
|
2043
1945
|
|
|
2044
|
-
|
|
2045
|
-
join_attributes [ :first_name, :last_name ] => :real_name
|
|
2046
|
-
```
|
|
1946
|
+
### List of filters ###
|
|
2047
1947
|
|
|
2048
|
-
|
|
1948
|
+
See the [COMMON-FILTERS](http://rubydoc.info/gems/attribute-filters/file/docs/COMMON-FILTERS.md) for detailed descriptions and usage examples.
|
|
2049
1949
|
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
1950
|
+
See the
|
|
1951
|
+
[`ActiveModel::AttributeFilters::Common`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters/Common)
|
|
1952
|
+
for descriptions of common filtering modules.
|
|
2053
1953
|
|
|
2054
1954
|
Custom applications
|
|
2055
1955
|
-------------------
|
|
@@ -2064,16 +1964,16 @@ Example:
|
|
|
2064
1964
|
```ruby
|
|
2065
1965
|
class User < ActiveRecord::Base
|
|
2066
1966
|
|
|
2067
|
-
|
|
1967
|
+
has_attributes_that_are required_to_trade: [ :username, :email, :real_name, :address, :account ]
|
|
2068
1968
|
|
|
2069
1969
|
def is_able_to_trade?
|
|
2070
|
-
are_attributes_that_are
|
|
2071
|
-
are_attributes_that_are
|
|
1970
|
+
are_attributes_that_are.required_to_trade.all.present? and
|
|
1971
|
+
are_attributes_that_are.required_to_trade.all.valid?
|
|
2072
1972
|
end
|
|
2073
1973
|
|
|
2074
1974
|
def attributes_missing_to_trade
|
|
2075
|
-
attributes_that_are
|
|
2076
|
-
attributes_that_are
|
|
1975
|
+
attributes_that_are.required_to_trade.list.blank? +
|
|
1976
|
+
attributes_that_are.required_to_trade.list.invalid?
|
|
2077
1977
|
end
|
|
2078
1978
|
end
|
|
2079
1979
|
```
|