active_model_persistence 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +0 -76
- data/lib/active_model_persistence/index.rb +4 -17
- data/lib/active_model_persistence/indexable.rb +8 -12
- data/lib/active_model_persistence/persistence.rb +33 -14
- data/lib/active_model_persistence/primary_key.rb +24 -22
- data/lib/active_model_persistence/primary_key_index.rb +1 -1
- data/lib/active_model_persistence/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e3b8a31cdacf32baeaabb6d3c72631002098c9a35630d1c0aff5e836737e42dc
|
4
|
+
data.tar.gz: '00843ca11ad71c596c192d066efc3f43d7e531c068d12bea9866f58bea404b3e'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 25984dd367fedae9ead6973601c042a164643e5aaa09e5198ebcc6a8f5dfe333eba73d37f34ca257f61a58f6aca7b6b9326727f337b2d159d5d0bd71db62e0bd
|
7
|
+
data.tar.gz: ca0ddf06112d7e70bb7898f8f3ba0a95f63f5db4f9cf3aee1f6a7d054b3fd5dfb705609844d42ff55d9eab05a7652fb6f2fa086ca8d1a7a97b79e61ee6811cfe
|
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,13 @@
|
|
7
7
|
|
8
8
|
The full change log is stored on [this project's GitHub releases page](https://github.com/jcouball/active_model_persistence/releases).
|
9
9
|
|
10
|
+
## v0.5.0
|
11
|
+
|
12
|
+
* 87b32e5 Fix the version file after the previous revert (#20)
|
13
|
+
* f4f6c39 Revert "Add inheritance support (#14)" (#19)
|
14
|
+
|
15
|
+
See https://github.com/ruby-git/ruby-git/releases/tag/v0.5.0
|
16
|
+
|
10
17
|
## v0.4.0
|
11
18
|
|
12
19
|
* e491e22 Set the version file back to the correct version (#17)
|
data/README.md
CHANGED
@@ -65,82 +65,6 @@ Employee.find_by_manager_id('boss') #=> [e1, e2]
|
|
65
65
|
# etc.
|
66
66
|
```
|
67
67
|
|
68
|
-
## Inheritance
|
69
|
-
|
70
|
-
ActiveModelPersistence supports inheritance in models. Include
|
71
|
-
`ActiveModelPersistence::Persistence` only in the base class.
|
72
|
-
|
73
|
-
Here is an example with a `User` base class and two derived clases `Employee` and `Member`.
|
74
|
-
Each derived class adds different attributes and indexes.
|
75
|
-
|
76
|
-
```ruby
|
77
|
-
require 'active_model_persistence'
|
78
|
-
|
79
|
-
class User
|
80
|
-
include ActiveModelPersistence::Persistence
|
81
|
-
|
82
|
-
attribute :id, :integer
|
83
|
-
attribute :name, :string
|
84
|
-
end
|
85
|
-
|
86
|
-
class Employee < User
|
87
|
-
attribute :manager_id, :integer
|
88
|
-
|
89
|
-
index :manager_id, unique: false
|
90
|
-
end
|
91
|
-
|
92
|
-
class Member < User
|
93
|
-
attribute :joined_on, :date, default: Date.today
|
94
|
-
|
95
|
-
index :joined_on, unique: false
|
96
|
-
end
|
97
|
-
```
|
98
|
-
|
99
|
-
As an example, say we have one instance of each class:
|
100
|
-
|
101
|
-
```ruby
|
102
|
-
user = User.create!(id: 1, name: 'User James')
|
103
|
-
employee = Employee.create!(id: 2, name: 'Employee Bob', manager_id: nil)
|
104
|
-
member = Member.create!(id: 3, name: 'Member Mary', joined_on: Date.parse('2022-01-01'))
|
105
|
-
```
|
106
|
-
|
107
|
-
The primary key is shared by all objects of these classes so it must be unique for
|
108
|
-
all objects created from these classes. For instance:
|
109
|
-
|
110
|
-
```ruby
|
111
|
-
require 'rspec-expectations'
|
112
|
-
include RSpec::Matchers
|
113
|
-
|
114
|
-
# Creating a Member with the same primary key as a User will fail
|
115
|
-
expect { Member.create!(id: 1, name: 'Member Jason') }.to(
|
116
|
-
raise_error(ActiveModelPersistence::UniqueConstraintError)
|
117
|
-
)
|
118
|
-
```
|
119
|
-
|
120
|
-
Calling a find method such as `find` or `find_by_*` on a class will only return
|
121
|
-
objects that are a kind of that class.
|
122
|
-
|
123
|
-
That means calling a find method on `User` will return users, employees, or members:
|
124
|
-
|
125
|
-
```ruby
|
126
|
-
expect(User.find(1)).to eq(user)
|
127
|
-
expect(User.find(2)).to eq(employee)
|
128
|
-
expect(User.find(3)).to eq(member)
|
129
|
-
```
|
130
|
-
|
131
|
-
While calling a find method on `Employee` will only return employees:
|
132
|
-
|
133
|
-
```ruby
|
134
|
-
expect(Employee.find(1)).to be_nil
|
135
|
-
expect(Employee.find(2)).to eq(employee)
|
136
|
-
expect(Employee.find(3)).to be_nil
|
137
|
-
```
|
138
|
-
|
139
|
-
`all`, `count`, `delete_all`, `destroy_all` and other methods similarly limit what
|
140
|
-
objects are acted upon based on what class they are called on.
|
141
|
-
|
142
|
-
## API Documentation
|
143
|
-
|
144
68
|
See [the full API documentation](https://jcouball.github.io/active_record_persistence/) for more details.
|
145
69
|
|
146
70
|
## Installation
|
@@ -15,18 +15,6 @@ module ActiveModelPersistence
|
|
15
15
|
#
|
16
16
|
attr_reader :name
|
17
17
|
|
18
|
-
# Identifies the base class this index applies to
|
19
|
-
#
|
20
|
-
# Objects that are not of this class or one of its subclasses will not be added to the index.
|
21
|
-
#
|
22
|
-
# @example
|
23
|
-
# i = Index.new(name: 'id', base_class: self, key_source: :id, unique: true)
|
24
|
-
# i.base_class == self #=> true
|
25
|
-
#
|
26
|
-
# @return [Class] the class this index applies to
|
27
|
-
#
|
28
|
-
attr_reader :base_class
|
29
|
-
|
30
18
|
# Defines how the object's key value is calculated
|
31
19
|
#
|
32
20
|
# If a proc is provided, it will be called with the object as an argument to get the key value.
|
@@ -34,7 +22,7 @@ module ActiveModelPersistence
|
|
34
22
|
# If a symbol is provided, it will identify the method to call on the object to get the key value.
|
35
23
|
#
|
36
24
|
# @example
|
37
|
-
# i = Index.new(name: 'id',
|
25
|
+
# i = Index.new(name: 'id', key_value_source: :id, unique: true)
|
38
26
|
# i.key_value_source # => :id
|
39
27
|
#
|
40
28
|
# @return [Symbol, Proc] the method name or proc used to calculate the index key
|
@@ -49,7 +37,7 @@ module ActiveModelPersistence
|
|
49
37
|
# when trying to add the second object.
|
50
38
|
#
|
51
39
|
# @example
|
52
|
-
# i = Index.new(name: 'id',
|
40
|
+
# i = Index.new(name: 'id', key_value_source: :id, unique: true)
|
53
41
|
# i.unique? # => true
|
54
42
|
#
|
55
43
|
# @return [Boolean] true if the index is unique
|
@@ -86,9 +74,8 @@ module ActiveModelPersistence
|
|
86
74
|
# @param key_value_source [Symbol, Proc] the attribute name or proc used to calculate the index key
|
87
75
|
# @param unique [Boolean] when true the index will only allow one object per key
|
88
76
|
#
|
89
|
-
def initialize(name:,
|
77
|
+
def initialize(name:, key_value_source: nil, unique: false)
|
90
78
|
@name = name.to_s
|
91
|
-
@base_class = base_class
|
92
79
|
@key_value_source = determine_key_value_source(name, key_value_source)
|
93
80
|
@unique = unique
|
94
81
|
@key_to_objects_map = {}
|
@@ -241,7 +228,7 @@ module ActiveModelPersistence
|
|
241
228
|
# @api private
|
242
229
|
#
|
243
230
|
def remove_object_from_index(object, key)
|
244
|
-
key_to_objects_map[key].delete_if { |o| o.
|
231
|
+
key_to_objects_map[key].delete_if { |o| o.primary_key == object.primary_key }
|
245
232
|
key_to_objects_map.delete(key) if key_to_objects_map[key].empty?
|
246
233
|
object.clear_index_key(name)
|
247
234
|
end
|
@@ -60,7 +60,6 @@ module ActiveModelPersistence
|
|
60
60
|
# make these class methods on that class.
|
61
61
|
#
|
62
62
|
module ClassMethods
|
63
|
-
# @!attribute [r] indexes
|
64
63
|
# Returns a hash of indexes for the model keyed by name
|
65
64
|
#
|
66
65
|
# @example
|
@@ -68,7 +67,9 @@ module ActiveModelPersistence
|
|
68
67
|
#
|
69
68
|
# @return [Hash<String, ActiveModelPersistence::Index>] the indexes defined by the model
|
70
69
|
#
|
71
|
-
|
70
|
+
def indexes
|
71
|
+
@indexes ||= {}
|
72
|
+
end
|
72
73
|
|
73
74
|
# Adds an index to the model
|
74
75
|
#
|
@@ -97,7 +98,9 @@ module ActiveModelPersistence
|
|
97
98
|
indexes[index_name.to_sym] = index
|
98
99
|
|
99
100
|
singleton_class.define_method("find_by_#{index_name}") do |key|
|
100
|
-
index.objects(key).
|
101
|
+
index.objects(key).tap do |objects|
|
102
|
+
objects.each { |o| o.instance_variable_set(:@previously_new_record, false) }
|
103
|
+
end
|
101
104
|
end
|
102
105
|
end
|
103
106
|
|
@@ -122,9 +125,7 @@ module ActiveModelPersistence
|
|
122
125
|
# @return [void]
|
123
126
|
#
|
124
127
|
def update_indexes(object)
|
125
|
-
indexes.each_value
|
126
|
-
index.add_or_update(object) if object.is_a?(index.base_class)
|
127
|
-
end
|
128
|
+
indexes.each_value { |index| index.add_or_update(object) }
|
128
129
|
end
|
129
130
|
|
130
131
|
# Removes the given object from all defined indexes
|
@@ -143,9 +144,7 @@ module ActiveModelPersistence
|
|
143
144
|
# @return [void]
|
144
145
|
#
|
145
146
|
def remove_from_indexes(object)
|
146
|
-
indexes.each_value
|
147
|
-
index.remove(object) if object.is_a?(index.base_class)
|
148
|
-
end
|
147
|
+
indexes.each_value { |index| index.remove(object) }
|
149
148
|
end
|
150
149
|
|
151
150
|
private
|
@@ -159,15 +158,12 @@ module ActiveModelPersistence
|
|
159
158
|
def default_index_options(index_name)
|
160
159
|
{
|
161
160
|
name: index_name.to_sym,
|
162
|
-
base_class: self,
|
163
161
|
unique: false
|
164
162
|
}
|
165
163
|
end
|
166
164
|
end
|
167
165
|
|
168
166
|
included do
|
169
|
-
cattr_reader :indexes, instance_accessor: false, default: {}
|
170
|
-
|
171
167
|
# Adds the object to the indexes defined by the model
|
172
168
|
#
|
173
169
|
# @example
|
@@ -158,7 +158,7 @@ module ActiveModelPersistence
|
|
158
158
|
# @return [Array<Object>] the model objects in the object store
|
159
159
|
#
|
160
160
|
def all
|
161
|
-
object_array.
|
161
|
+
object_array.each
|
162
162
|
end
|
163
163
|
|
164
164
|
# The number of model objects saved in the object store
|
@@ -174,7 +174,7 @@ module ActiveModelPersistence
|
|
174
174
|
# @return [Integer] the number of model objects in the object store
|
175
175
|
#
|
176
176
|
def count
|
177
|
-
object_array.
|
177
|
+
object_array.size
|
178
178
|
end
|
179
179
|
|
180
180
|
alias size count
|
@@ -196,11 +196,30 @@ module ActiveModelPersistence
|
|
196
196
|
# @return [void]
|
197
197
|
#
|
198
198
|
def destroy_all
|
199
|
-
|
200
|
-
objects_to_destroy.each(&:destroy)
|
199
|
+
object_array.first.destroy while object_array.size.positive?
|
201
200
|
end
|
202
201
|
|
203
|
-
|
202
|
+
# Removes all model objects from the object store
|
203
|
+
#
|
204
|
+
# Each saved model object's `#destroy` method is NOT called.
|
205
|
+
#
|
206
|
+
# @example
|
207
|
+
# array_of_attributes = [
|
208
|
+
# { id: 1, name: 'James' },
|
209
|
+
# { id: 2, name: 'Frank' }
|
210
|
+
# ]
|
211
|
+
# ModelExample.create(array_of_attributes)
|
212
|
+
# ModelExample.all.count #=> 2
|
213
|
+
# ModelExample.destroy_all
|
214
|
+
# ModelExample.all.count #=> 0
|
215
|
+
#
|
216
|
+
# @return [void]
|
217
|
+
#
|
218
|
+
def delete_all
|
219
|
+
@object_array = []
|
220
|
+
indexes.values.each(&:remove_all)
|
221
|
+
nil
|
222
|
+
end
|
204
223
|
|
205
224
|
# private
|
206
225
|
|
@@ -210,12 +229,13 @@ module ActiveModelPersistence
|
|
210
229
|
#
|
211
230
|
# @api private
|
212
231
|
#
|
232
|
+
def object_array
|
233
|
+
@object_array ||= []
|
234
|
+
end
|
213
235
|
end
|
214
236
|
|
215
237
|
# rubocop:disable Metrics/BlockLength
|
216
238
|
included do
|
217
|
-
cattr_reader :object_array, instance_accessor: false, default: []
|
218
|
-
|
219
239
|
# Returns true if this object hasn't been saved or destroyed yet
|
220
240
|
#
|
221
241
|
# @example
|
@@ -351,7 +371,7 @@ module ActiveModelPersistence
|
|
351
371
|
def destroy
|
352
372
|
if persisted?
|
353
373
|
remove_from_indexes
|
354
|
-
self.class.object_array.delete_if { |o| o.
|
374
|
+
self.class.object_array.delete_if { |o| o.primary_key == primary_key }
|
355
375
|
end
|
356
376
|
@new_record = false
|
357
377
|
@destroyed = true
|
@@ -409,14 +429,13 @@ module ActiveModelPersistence
|
|
409
429
|
# Creates a record with values matching those of the instance attributes
|
410
430
|
# and returns its id.
|
411
431
|
#
|
412
|
-
# @return [Object] the
|
432
|
+
# @return [Object] the primary_key of the created object
|
413
433
|
#
|
414
434
|
# @api private
|
415
435
|
#
|
416
436
|
def _create
|
417
|
-
return false unless
|
418
|
-
|
419
|
-
raise UniqueConstraintError if primary_key_index.include?(primary_key_value)
|
437
|
+
return false unless primary_key?
|
438
|
+
raise UniqueConstraintError if primary_key_index.include?(primary_key)
|
420
439
|
|
421
440
|
self.class.object_array << self
|
422
441
|
|
@@ -424,7 +443,7 @@ module ActiveModelPersistence
|
|
424
443
|
|
425
444
|
yield(self) if block_given?
|
426
445
|
|
427
|
-
|
446
|
+
primary_key
|
428
447
|
end
|
429
448
|
|
430
449
|
# Updates an object that is already in the object store
|
@@ -434,7 +453,7 @@ module ActiveModelPersistence
|
|
434
453
|
# @api private
|
435
454
|
#
|
436
455
|
def _update
|
437
|
-
raise RecordNotFound unless primary_key_index.include?(
|
456
|
+
raise RecordNotFound unless primary_key_index.include?(primary_key)
|
438
457
|
|
439
458
|
yield(self) if block_given?
|
440
459
|
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'active_support/core_ext/module'
|
4
|
-
|
5
3
|
module ActiveModelPersistence
|
6
4
|
# Exposes the `primary_key` accessor to read or write the primary key attribute value
|
7
5
|
#
|
@@ -44,8 +42,7 @@ module ActiveModelPersistence
|
|
44
42
|
# make these class methods on that class.
|
45
43
|
#
|
46
44
|
module ClassMethods
|
47
|
-
#
|
48
|
-
# Identifies the attribute that the `primary_key_value` accessor maps to
|
45
|
+
# Identifies the attribute that the `primary_key` accessor maps to
|
49
46
|
#
|
50
47
|
# The primary key is 'id' by default.
|
51
48
|
#
|
@@ -57,28 +54,33 @@ module ActiveModelPersistence
|
|
57
54
|
# end
|
58
55
|
# Employee.primary_key #=> :username
|
59
56
|
#
|
60
|
-
# @return [
|
57
|
+
# @return [Symbol] the attribute that the `primary_key` accessor is an alias for
|
61
58
|
#
|
62
|
-
|
63
|
-
|
59
|
+
def primary_key
|
60
|
+
@primary_key ||= 'id'
|
61
|
+
end
|
64
62
|
|
65
|
-
|
66
|
-
# @!attribute [r] primary_key
|
67
|
-
# Identifies the attribute that the `primary_key_value` accessor maps to
|
68
|
-
#
|
69
|
-
# The primary key is 'id' by default.
|
63
|
+
# Sets the attribute to use for the primary key
|
70
64
|
#
|
71
65
|
# @example
|
72
66
|
# class Employee
|
73
67
|
# include ActiveModelPersistence::PrimaryKey
|
74
68
|
# attribute :username, :string
|
75
|
-
#
|
69
|
+
# primary_key = :username
|
76
70
|
# end
|
77
|
-
# Employee.
|
71
|
+
# e = Employee.new(username: 'couballj')
|
72
|
+
# e.primary_key #=> 'couballj'
|
73
|
+
#
|
74
|
+
# @param attribute [Symbol] the attribute to use for the primary key
|
75
|
+
#
|
76
|
+
# @return [void]
|
78
77
|
#
|
79
|
-
|
80
|
-
|
78
|
+
def primary_key=(attribute)
|
79
|
+
@primary_key = attribute.to_s
|
80
|
+
end
|
81
|
+
end
|
81
82
|
|
83
|
+
included do
|
82
84
|
# Returns the primary key attribute's value
|
83
85
|
#
|
84
86
|
# @example
|
@@ -92,8 +94,8 @@ module ActiveModelPersistence
|
|
92
94
|
#
|
93
95
|
# @return [Object] the primary key attribute's value
|
94
96
|
#
|
95
|
-
def
|
96
|
-
__send__(primary_key)
|
97
|
+
def primary_key
|
98
|
+
__send__(self.class.primary_key)
|
97
99
|
end
|
98
100
|
|
99
101
|
# Sets the primary key atribute's value
|
@@ -112,8 +114,8 @@ module ActiveModelPersistence
|
|
112
114
|
#
|
113
115
|
# @return [void]
|
114
116
|
#
|
115
|
-
def
|
116
|
-
__send__("#{primary_key}=", value)
|
117
|
+
def primary_key=(value)
|
118
|
+
__send__("#{self.class.primary_key}=", value)
|
117
119
|
end
|
118
120
|
|
119
121
|
# Returns true if the primary key attribute's value is not null or empty
|
@@ -131,8 +133,8 @@ module ActiveModelPersistence
|
|
131
133
|
#
|
132
134
|
# @return [Boolean] true if the primary key attribute's value is not null or empty
|
133
135
|
#
|
134
|
-
def
|
135
|
-
|
136
|
+
def primary_key?
|
137
|
+
primary_key.present?
|
136
138
|
end
|
137
139
|
end
|
138
140
|
end
|