active_record-acts_as 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/README.md +10 -1
- data/lib/active_record/acts_as/instance_methods.rb +37 -9
- data/lib/active_record/acts_as/relation.rb +2 -0
- data/lib/active_record/acts_as/version.rb +1 -1
- data/spec/actable_spec.rb +8 -3
- data/spec/acts_as_spec.rb +39 -14
- data/spec/models.rb +7 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 35b482727f031a96a8549a8a8801a8cd8ee4f2af
|
4
|
+
data.tar.gz: fbd614d7466868481fae7ea7fe20930c19310124
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 60436ebc291619e730fcd600429378d82e4647ae5ed17ddffe3df9c596798b9a7ba0d98000ccd4a59b7ecdd18079d620e14b904c9f1b9c55e7cb3aa3915e9d0f
|
7
|
+
data.tar.gz: d0c69a18ef2329e3fcdfbc751c73d68ef28ea76f798f2c717e9c5693547443bf401a3a07bd5bc6cc1597b934b05a676c002dfec1fc7b167211c947ef472aed78
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -57,7 +57,9 @@ class Pen < ActiveRecord::Base
|
|
57
57
|
end
|
58
58
|
|
59
59
|
class Book < ActiveRecord::Base
|
60
|
-
|
60
|
+
# In case you don't wish to validate
|
61
|
+
# this model against Product
|
62
|
+
acts_as :product, validates_actable: false
|
61
63
|
end
|
62
64
|
|
63
65
|
class Store < ActiveRecord::Base
|
@@ -113,6 +115,13 @@ Product.first.specific
|
|
113
115
|
# => #<Pen ...>
|
114
116
|
```
|
115
117
|
|
118
|
+
If you have to come back to the parent object from the specific, the `acting_as` returns the parent element:
|
119
|
+
|
120
|
+
```Ruby
|
121
|
+
Pen.first.acting_as
|
122
|
+
# => #<Product ...>
|
123
|
+
```
|
124
|
+
|
116
125
|
In `has_many` case you can use subclasses:
|
117
126
|
|
118
127
|
```Ruby
|
@@ -10,10 +10,18 @@ module ActiveRecord
|
|
10
10
|
super || acting_as?(klass)
|
11
11
|
end
|
12
12
|
|
13
|
+
# Is the superclass persisted to the database?
|
14
|
+
def acting_as_persisted?
|
15
|
+
return false if acting_as.nil?
|
16
|
+
!acting_as.id.nil? && !acting_as.actable_id.nil?
|
17
|
+
end
|
18
|
+
|
13
19
|
def actable_must_be_valid
|
14
|
-
|
15
|
-
acting_as.
|
16
|
-
errors.
|
20
|
+
if validates_actable
|
21
|
+
unless acting_as.valid?
|
22
|
+
acting_as.errors.each do |att, message|
|
23
|
+
errors.add(att, message)
|
24
|
+
end
|
17
25
|
end
|
18
26
|
end
|
19
27
|
end
|
@@ -37,16 +45,20 @@ module ActiveRecord
|
|
37
45
|
private :write_attribute
|
38
46
|
|
39
47
|
def attributes
|
40
|
-
acting_as.attributes.except(acting_as_reflection.type, acting_as_reflection.foreign_key).merge(super)
|
48
|
+
acting_as_persisted? ? acting_as.attributes.except(acting_as_reflection.type, acting_as_reflection.foreign_key).merge(super) : super
|
41
49
|
end
|
42
50
|
|
43
51
|
def attribute_names
|
44
|
-
super | (acting_as.attribute_names - [acting_as_reflection.type, acting_as_reflection.foreign_key])
|
52
|
+
acting_as_persisted? ? super | (acting_as.attribute_names - [acting_as_reflection.type, acting_as_reflection.foreign_key]) : super
|
45
53
|
end
|
46
54
|
|
47
55
|
|
48
|
-
def respond_to?(name, include_private = false)
|
49
|
-
super || acting_as.respond_to?(name)
|
56
|
+
def respond_to?(name, include_private = false, as_original_class = false)
|
57
|
+
as_original_class ? super(name, include_private) : super(name, include_private) || acting_as.respond_to?(name)
|
58
|
+
end
|
59
|
+
|
60
|
+
def self_respond_to?(name, include_private = false)
|
61
|
+
respond_to? name, include_private, true
|
50
62
|
end
|
51
63
|
|
52
64
|
def dup
|
@@ -56,10 +68,26 @@ module ActiveRecord
|
|
56
68
|
end
|
57
69
|
|
58
70
|
def method_missing(method, *args, &block)
|
71
|
+
uses_superclass_for?(method) ? acting_as.send(method, *args, &block) : super
|
72
|
+
end
|
73
|
+
|
74
|
+
def uses_superclass_for?(method)
|
75
|
+
responds_locally = self_respond_to?(method)
|
59
76
|
if acting_as.respond_to?(method)
|
60
|
-
|
77
|
+
if responds_locally
|
78
|
+
false
|
79
|
+
else
|
80
|
+
# Only use getters if the superclass has
|
81
|
+
# an instance that is linked to this class instance.
|
82
|
+
if acting_as_persisted?
|
83
|
+
true
|
84
|
+
else
|
85
|
+
responds_locally ? false : true
|
86
|
+
end
|
87
|
+
end
|
61
88
|
else
|
62
|
-
|
89
|
+
# If the superclass doesn't have it, use this class's methods
|
90
|
+
false
|
63
91
|
end
|
64
92
|
end
|
65
93
|
end
|
@@ -9,6 +9,8 @@ module ActiveRecord
|
|
9
9
|
options, scope = scope, nil if Hash === scope
|
10
10
|
options = {as: :actable, dependent: :destroy, validate: false, autosave: true}.merge options
|
11
11
|
|
12
|
+
cattr_reader(:validates_actable) { options.delete(:validates_actable) == false ? false : true }
|
13
|
+
|
12
14
|
reflections = has_one name, scope, options
|
13
15
|
default_scope -> { eager_load(name) }
|
14
16
|
validate :actable_must_be_valid
|
data/spec/actable_spec.rb
CHANGED
@@ -31,9 +31,14 @@ RSpec.describe "ActiveRecord::Base subclass with #actable" do
|
|
31
31
|
end
|
32
32
|
|
33
33
|
describe ".specific" do
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
context "returns specific submodel" do
|
35
|
+
it "unless the submodel instance association doesn't exist" do
|
36
|
+
expect(subject.new.specific).to be_nil
|
37
|
+
end
|
38
|
+
it "if the submodel instance association exists" do
|
39
|
+
pen.save
|
40
|
+
expect(Product.find(pen.acting_as.id).specific).to eq(pen)
|
41
|
+
end
|
37
42
|
end
|
38
43
|
end
|
39
44
|
|
data/spec/acts_as_spec.rb
CHANGED
@@ -5,7 +5,9 @@ RSpec.describe "ActiveRecord::Base model with #acts_as called" do
|
|
5
5
|
|
6
6
|
let(:pen_attributes) { {name: 'pen', price: 0.8, color: 'red'} }
|
7
7
|
let(:pen) { Pen.new pen_attributes }
|
8
|
+
let(:isolated_pen) { IsolatedPen.new color: 'red' }
|
8
9
|
let(:store) { Store.new name: 'biggerman' }
|
10
|
+
let(:product) { Product.new store: store }
|
9
11
|
|
10
12
|
it "has a has_one relation" do
|
11
13
|
association = subject.reflect_on_all_associations.find { |r| r.name == :product }
|
@@ -129,16 +131,25 @@ RSpec.describe "ActiveRecord::Base model with #acts_as called" do
|
|
129
131
|
expect { Product.find(product_id) }.to raise_error(ActiveRecord::RecordNotFound)
|
130
132
|
end
|
131
133
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
134
|
+
context "validates supermodel attributes" do
|
135
|
+
it "upon validate" do
|
136
|
+
p = Pen.new
|
137
|
+
expect(p).to be_invalid
|
138
|
+
expect(p.errors.keys).to include(:name, :price, :color)
|
139
|
+
p.name = 'testing'
|
140
|
+
expect(p).to be_invalid
|
141
|
+
p.color = 'red'
|
142
|
+
expect(p).to be_invalid
|
143
|
+
p.price = 0.8
|
144
|
+
expect(p).to be_valid
|
145
|
+
end
|
146
|
+
it "unless validates_actable is set to false" do
|
147
|
+
p = IsolatedPen.new
|
148
|
+
expect(p).to be_invalid
|
149
|
+
expect(p.errors.keys).to include(:color)
|
150
|
+
p.color = 'red'
|
151
|
+
expect(p).to be_valid
|
152
|
+
end
|
142
153
|
end
|
143
154
|
|
144
155
|
it "can set assosications defined in supermodel" do
|
@@ -156,12 +167,26 @@ RSpec.describe "ActiveRecord::Base model with #acts_as called" do
|
|
156
167
|
expect(pen.store).to eq(store)
|
157
168
|
end
|
158
169
|
|
159
|
-
|
160
|
-
|
170
|
+
context "includes supermodel attributes in .to_json response" do
|
171
|
+
it "unless the submodel instance association doesn't exist" do
|
172
|
+
expect(JSON.parse(isolated_pen.to_json)).to eq(JSON.parse('{"id":null,"color":"red"}'))
|
173
|
+
end
|
174
|
+
it "if the submodel instance association exists" do
|
175
|
+
p = Product.new(name: 'Test Pen', price: 0.8, actable: pen)
|
176
|
+
p.save
|
177
|
+
expect(JSON.parse(pen.to_json)).to eq(JSON.parse('{"id":' + pen.id.to_s + ',"name":"pen","price":0.8,"store_id":null,"color":"red"}'))
|
178
|
+
end
|
161
179
|
end
|
162
180
|
|
163
|
-
|
164
|
-
|
181
|
+
context "includes supermodel attribute names in .attribute_names response" do
|
182
|
+
it "unless the submodel instance association doesn't exist" do
|
183
|
+
expect(pen.attribute_names).to include("id", "color")
|
184
|
+
end
|
185
|
+
it "if the submodel instance association exists" do
|
186
|
+
p = Product.new(name: 'Test Pen', price: 0.8, actable: pen)
|
187
|
+
p.save
|
188
|
+
expect(pen.attribute_names).to include("id", "color", "name", "price", "store_id")
|
189
|
+
end
|
165
190
|
end
|
166
191
|
end
|
167
192
|
|
data/spec/models.rb
CHANGED
@@ -21,6 +21,13 @@ class Pen < ActiveRecord::Base
|
|
21
21
|
validates_presence_of :color
|
22
22
|
end
|
23
23
|
|
24
|
+
class IsolatedPen < ActiveRecord::Base
|
25
|
+
self.table_name = :pens
|
26
|
+
acts_as :product, validates_actable: false
|
27
|
+
|
28
|
+
validates_presence_of :color
|
29
|
+
end
|
30
|
+
|
24
31
|
class Store < ActiveRecord::Base
|
25
32
|
has_many :products
|
26
33
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_record-acts_as
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hassan Zamani
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-01-
|
11
|
+
date: 2015-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sqlite3
|