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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 34fc19a0853dc464c318bb8da5d55542940a7428
4
- data.tar.gz: 9343cbe6c7b873b2a55af6e937042dc2fca10554
3
+ metadata.gz: 35b482727f031a96a8549a8a8801a8cd8ee4f2af
4
+ data.tar.gz: fbd614d7466868481fae7ea7fe20930c19310124
5
5
  SHA512:
6
- metadata.gz: fdedabb5d9cff8c513c70f799b2a35527e896d37c452ea4c99ef01cff726988542179c85465588d70c701275c51b598b54f0cb164f5de63f814a67f470a98205
7
- data.tar.gz: 8df4505d0d20012f9675dba4acd8512ebfc2d8c6cb64a9088853ccff6125af156132ec7cedae895810f5ac019d6f0c15543169da77e3b4c2fbed8779a60580ae
6
+ metadata.gz: 60436ebc291619e730fcd600429378d82e4647ae5ed17ddffe3df9c596798b9a7ba0d98000ccd4a59b7ecdd18079d620e14b904c9f1b9c55e7cb3aa3915e9d0f
7
+ data.tar.gz: d0c69a18ef2329e3fcdfbc751c73d68ef28ea76f798f2c717e9c5693547443bf401a3a07bd5bc6cc1597b934b05a676c002dfec1fc7b167211c947ef472aed78
data/.gitignore CHANGED
@@ -20,3 +20,5 @@ tmp
20
20
  *.o
21
21
  *.a
22
22
  mkmf.log
23
+ .ruby-gemset
24
+ .ruby-version
data/README.md CHANGED
@@ -57,7 +57,9 @@ class Pen < ActiveRecord::Base
57
57
  end
58
58
 
59
59
  class Book < ActiveRecord::Base
60
- acts_as :product
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
- unless acting_as.valid?
15
- acting_as.errors.each do |att, message|
16
- errors.add(att, message)
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
- acting_as.send(method, *args, &block)
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
- super
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
@@ -1,6 +1,6 @@
1
1
 
2
2
  module ActiveRecord
3
3
  module ActsAs
4
- VERSION = "1.0.3"
4
+ VERSION = "1.0.4"
5
5
  end
6
6
  end
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
- it "return specific submodel" do
35
- pen.save
36
- expect(Product.find(pen.acting_as.id).specific).to eq(pen)
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
- it "validates supermodel attribures upon validation" do
133
- p = Pen.new
134
- expect(p).to be_invalid
135
- expect(p.errors.keys).to include(:name, :price, :color)
136
- p.name = 'testing'
137
- expect(p).to be_invalid
138
- p.color = 'red'
139
- expect(p).to be_invalid
140
- p.price = 0.8
141
- expect(p).to be_valid
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
- it "includes supermodel attributes in .to_json responce" do
160
- expect(pen.to_json).to eq('{"id":null,"name":"pen","price":0.8,"store_id":null,"color":"red"}')
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
- it "includes supermodel attribute names in .attribute_names responce" do
164
- expect(pen.attribute_names).to include("id", "color", "name", "price", "store_id")
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.3
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-06 00:00:00.000000000 Z
11
+ date: 2015-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sqlite3