active_type 0.3.5 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +33 -0
- data/gemfiles/Gemfile.3.2.lock +1 -1
- data/gemfiles/Gemfile.4.0.lock +1 -1
- data/gemfiles/Gemfile.4.1.lock +1 -1
- data/gemfiles/Gemfile.4.2.1.lock +1 -1
- data/gemfiles/Gemfile.4.2.1.pg.lock +1 -1
- data/lib/active_type/util.rb +49 -0
- data/lib/active_type/version.rb +1 -1
- data/lib/active_type.rb +2 -1
- data/spec/active_type/util_spec.rb +128 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af57ff59af07cfdb0a8576c733da8aa2d0e254ce
|
4
|
+
data.tar.gz: e1e04618118baf2b5260e20ed3685d695930e756
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 91477402f2df135aa9a2bef4a3b63f51c113be820940f83c350230af27b76dcc3c16d587c11874bd64320e1115f68b8fb25c7904e9d6579e3313853fddb8ad08
|
7
|
+
data.tar.gz: 7f9fa15fc5ed489c5bee1350f07b97852e32732017c4bb0535d53f4e3fb36c928f20bb9b44dcb5ab6f1ebce5cb892a60e3c382e5e92044e38ef51c823409fb7b
|
data/README.md
CHANGED
@@ -271,6 +271,39 @@ Supported options for `nests_many` / `nests_one` are:
|
|
271
271
|
```
|
272
272
|
|
273
273
|
|
274
|
+
Casting
|
275
|
+
-------
|
276
|
+
|
277
|
+
When working with ActiveType you will often find it useful to cast an ActiveRecord instance to its extended `ActiveType::Record` variant.
|
278
|
+
|
279
|
+
Use `ActiveType.cast` for this:
|
280
|
+
|
281
|
+
```
|
282
|
+
class User < ActiveRecord::Base
|
283
|
+
...
|
284
|
+
end
|
285
|
+
|
286
|
+
class SignUp < ActiveType::Record[User]
|
287
|
+
...
|
288
|
+
end
|
289
|
+
|
290
|
+
user = User.find(1)
|
291
|
+
sign_up = ActiveType.cast(SignUp)
|
292
|
+
sign_up.is_a?(SignUp) # => true
|
293
|
+
```
|
294
|
+
|
295
|
+
This is basically like [`ActiveRecord#becomes`](http://apidock.com/rails/v4.2.1/ActiveRecord/Persistence/becomes), but with less bugs and more consistent behavior.
|
296
|
+
|
297
|
+
You can also cast an entire relation (scope) to a relation of an `ActiveType::Record`:
|
298
|
+
|
299
|
+
```
|
300
|
+
adult_users = User.where('age >= 18')
|
301
|
+
adult_sign_ups = ActiveType.cast(adult_users, SignUp)
|
302
|
+
sign_up = adult_sign_ups.find(1)
|
303
|
+
sign_up.is_a?(SignUp) # => true
|
304
|
+
```
|
305
|
+
|
306
|
+
|
274
307
|
Supported Rails versions
|
275
308
|
------------------------
|
276
309
|
|
data/gemfiles/Gemfile.3.2.lock
CHANGED
data/gemfiles/Gemfile.4.0.lock
CHANGED
data/gemfiles/Gemfile.4.1.lock
CHANGED
data/gemfiles/Gemfile.4.2.1.lock
CHANGED
@@ -0,0 +1,49 @@
|
|
1
|
+
module ActiveType
|
2
|
+
module Util
|
3
|
+
|
4
|
+
def cast(object, klass)
|
5
|
+
if object.is_a?(ActiveRecord::Relation)
|
6
|
+
cast_relation(object, klass)
|
7
|
+
elsif object.is_a?(ActiveRecord::Base)
|
8
|
+
cast_record(object, klass)
|
9
|
+
else
|
10
|
+
raise ArgumentError, "Don't know how to cast #{object.inspect}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def scoped(klass_or_relation)
|
15
|
+
klass_or_relation.where(nil)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def cast_record(record, klass)
|
21
|
+
# record.becomes(klass).dup
|
22
|
+
klass.new do |casted|
|
23
|
+
# Rails 3.2, 4.2
|
24
|
+
casted.instance_variable_set(:@attributes, record.instance_variable_get(:@attributes))
|
25
|
+
# Rails 3.2
|
26
|
+
record.instance_variable_set(:@attributes_cache, record.instance_variable_get(:@attributes_cache))
|
27
|
+
# Rails 4.2
|
28
|
+
casted.instance_variable_set(:@changed_attributes, record.instance_variable_get(:@changed_attributes))
|
29
|
+
# Rails 3.2, 4.2
|
30
|
+
casted.instance_variable_set(:@new_record, record.new_record?)
|
31
|
+
# Rails 3.2, 4.2
|
32
|
+
casted.instance_variable_set(:@destroyed, record.destroyed?)
|
33
|
+
# Rails 3.2, 4.2
|
34
|
+
casted.instance_variable_set(:@errors, record.errors)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def cast_relation(relation, klass)
|
39
|
+
scoped(klass).merge(scoped(relation))
|
40
|
+
end
|
41
|
+
|
42
|
+
extend self
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
# Make Util methods available under the `ActiveType` namespace
|
47
|
+
# like `ActiveType.cast(...)`
|
48
|
+
extend Util
|
49
|
+
end
|
data/lib/active_type/version.rb
CHANGED
data/lib/active_type.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'active_type/version'
|
4
4
|
require 'active_record'
|
5
|
+
require 'active_type/util'
|
5
6
|
require 'active_type/record'
|
6
7
|
require 'active_type/object'
|
7
8
|
|
@@ -10,4 +11,4 @@ if ActiveRecord::VERSION::STRING == '4.2.0'
|
|
10
11
|
ActiveType is not compatible with ActiveRecord 4.2.0. Please upgrade to 4.2.1
|
11
12
|
For details see https://github.com/makandra/active_type/issues/31
|
12
13
|
MESSAGE
|
13
|
-
end
|
14
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module UtilSpec
|
4
|
+
|
5
|
+
class BaseRecord < ActiveRecord::Base
|
6
|
+
self.table_name = 'records'
|
7
|
+
end
|
8
|
+
|
9
|
+
class ExtendedRecord < ActiveType::Record[BaseRecord]
|
10
|
+
|
11
|
+
attribute :virtual_string
|
12
|
+
after_initialize :set_virtual_string
|
13
|
+
|
14
|
+
def set_virtual_string
|
15
|
+
self.virtual_string = "persisted_string is #{persisted_string}"
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
class Parent < ActiveRecord::Base
|
21
|
+
self.table_name = 'sti_records'
|
22
|
+
end
|
23
|
+
|
24
|
+
class Child < Parent
|
25
|
+
end
|
26
|
+
|
27
|
+
class ChildSibling < Parent
|
28
|
+
end
|
29
|
+
|
30
|
+
class ExtendedChild < ActiveType::Record[Child]
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
describe ActiveType::Util do
|
36
|
+
|
37
|
+
describe '.cast' do
|
38
|
+
|
39
|
+
describe 'for a relation' do
|
40
|
+
|
41
|
+
it 'casts a scope to a scope of another class' do
|
42
|
+
record = UtilSpec::BaseRecord.create!(persisted_string: 'foo')
|
43
|
+
base_scope = UtilSpec::BaseRecord.where(persisted_string: 'foo')
|
44
|
+
casted_scope = ActiveType::Util.cast(base_scope, UtilSpec::ExtendedRecord)
|
45
|
+
casted_scope.build.should be_a(UtilSpec::ExtendedRecord)
|
46
|
+
found_record = casted_scope.find(record.id)
|
47
|
+
found_record.persisted_string.should == 'foo'
|
48
|
+
found_record.should be_a(UtilSpec::ExtendedRecord)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'preserves existing scope conditions' do
|
52
|
+
match = UtilSpec::BaseRecord.create!(persisted_string: 'foo')
|
53
|
+
no_match = UtilSpec::BaseRecord.create!(persisted_string: 'bar')
|
54
|
+
base_scope = UtilSpec::BaseRecord.where(persisted_string: 'foo')
|
55
|
+
casted_scope = ActiveType::Util.cast(base_scope, UtilSpec::ExtendedRecord)
|
56
|
+
casted_match = UtilSpec::ExtendedRecord.find(match.id)
|
57
|
+
casted_scope.to_a.should == [casted_match]
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
describe 'for a record type' do
|
63
|
+
|
64
|
+
it 'casts a base record to an extended record' do
|
65
|
+
base_record = UtilSpec::BaseRecord.create!(persisted_string: 'foo')
|
66
|
+
extended_record = ActiveType::Util.cast(base_record, UtilSpec::ExtendedRecord)
|
67
|
+
extended_record.should be_a(UtilSpec::ExtendedRecord)
|
68
|
+
extended_record.should be_persisted
|
69
|
+
extended_record.id.should be_present
|
70
|
+
extended_record.id.should == base_record.id
|
71
|
+
extended_record.persisted_string.should == 'foo'
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'casts an extended record to a base record' do
|
75
|
+
extended_record = UtilSpec::ExtendedRecord.create!(persisted_string: 'foo')
|
76
|
+
base_record = ActiveType::Util.cast(extended_record, UtilSpec::BaseRecord)
|
77
|
+
base_record.should be_a(UtilSpec::BaseRecord)
|
78
|
+
base_record.should be_persisted
|
79
|
+
base_record.id.should be_present
|
80
|
+
base_record.id.should == extended_record.id
|
81
|
+
base_record.persisted_string.should == 'foo'
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'calls after_initialize callbacks of the cast target' do
|
85
|
+
base_record = UtilSpec::BaseRecord.create!(persisted_string: 'foo')
|
86
|
+
extended_record = ActiveType::Util.cast(base_record, UtilSpec::ExtendedRecord)
|
87
|
+
extended_record.virtual_string.should be_present
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'lets after_initialize callbacks access attributes (bug in ActiveRecord#becomes)' do
|
91
|
+
base_record = UtilSpec::BaseRecord.create!(persisted_string: 'foo')
|
92
|
+
extended_record = ActiveType::Util.cast(base_record, UtilSpec::ExtendedRecord)
|
93
|
+
extended_record.virtual_string.should == 'persisted_string is foo'
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'preserves the #type of an STI record that is casted to an ExtendedRecord' do
|
97
|
+
child_record = UtilSpec::Child.create!(persisted_string: 'foo')
|
98
|
+
extended_child_record = ActiveType::Util.cast(child_record, UtilSpec::ExtendedChild)
|
99
|
+
extended_child_record.should be_a(UtilSpec::ExtendedChild)
|
100
|
+
extended_child_record.type.should == 'UtilSpec::Child'
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'changes the #type of an STI record when casted to another type in the hierarchy' do
|
104
|
+
child_record = UtilSpec::Child.create!(persisted_string: 'foo')
|
105
|
+
child_sibling_record = ActiveType::Util.cast(child_record, UtilSpec::ChildSibling)
|
106
|
+
child_sibling_record.should be_a(UtilSpec::ChildSibling)
|
107
|
+
child_sibling_record.type.should == 'UtilSpec::Child'
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'preserves dirty tracking flags' do
|
111
|
+
base_record = UtilSpec::BaseRecord.create!(persisted_string: 'foo')
|
112
|
+
base_record.changes.should == {}
|
113
|
+
base_record.persisted_string = 'bar'
|
114
|
+
base_record.changes.should == { 'persisted_string' => ['foo', 'bar'] }
|
115
|
+
extended_record = ActiveType::Util.cast(base_record, UtilSpec::ExtendedRecord)
|
116
|
+
extended_record.should be_a(UtilSpec::ExtendedRecord)
|
117
|
+
extended_record.changes.should == { 'persisted_string' => ['foo', 'bar'] }
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
it "exposes all methods through ActiveType's root namespace" do
|
125
|
+
ActiveType.should respond_to(:cast)
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_type
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tobias Kraze
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-06-
|
12
|
+
date: 2015-06-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -88,6 +88,7 @@ files:
|
|
88
88
|
- lib/active_type/object.rb
|
89
89
|
- lib/active_type/record.rb
|
90
90
|
- lib/active_type/type_caster.rb
|
91
|
+
- lib/active_type/util.rb
|
91
92
|
- lib/active_type/version.rb
|
92
93
|
- lib/active_type/virtual_attributes.rb
|
93
94
|
- spec/active_type/extended_record/single_table_inheritance_spec.rb
|
@@ -95,6 +96,7 @@ files:
|
|
95
96
|
- spec/active_type/nested_attributes_spec.rb
|
96
97
|
- spec/active_type/object_spec.rb
|
97
98
|
- spec/active_type/record_spec.rb
|
99
|
+
- spec/active_type/util_spec.rb
|
98
100
|
- spec/integration/holidays_spec.rb
|
99
101
|
- spec/integration/shape_spec.rb
|
100
102
|
- spec/integration/sign_in_spec.rb
|
@@ -142,6 +144,7 @@ test_files:
|
|
142
144
|
- spec/active_type/nested_attributes_spec.rb
|
143
145
|
- spec/active_type/object_spec.rb
|
144
146
|
- spec/active_type/record_spec.rb
|
147
|
+
- spec/active_type/util_spec.rb
|
145
148
|
- spec/integration/holidays_spec.rb
|
146
149
|
- spec/integration/shape_spec.rb
|
147
150
|
- spec/integration/sign_in_spec.rb
|