active_record-acts_as 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
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