passive_model 1.0.2 → 1.1.0
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/CHANGELOG.md +15 -0
- data/README.md +104 -37
- data/lib/passive_model/base.rb +25 -5
- data/lib/passive_model/version.rb +1 -1
- data/lib/passive_model.rb +4 -1
- metadata +8 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3c2b1ac63fdec874fc2f59c9d9bedd53f40dfec303cf9c045ce7f922cb312679
|
|
4
|
+
data.tar.gz: e6344a1d4168704cdc9160ebb5fcfbd6bc9d98e661c0c1c6e9feeffa7cb28648
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c1c90541613b89b7704700d32a48fef9bb0adb9eeee6862f65129b71f1547a77a3c98d4ec337184381a6bbc3a5a24cdc4764d4f22424145a40b32f0cf157ccc1
|
|
7
|
+
data.tar.gz: ddacc10308fee161f2e1d059fb8e96736700d3529466a825df52deffc5a5b67a09bcc80a6a3848ab8d1e3c70db49c5306ba5b92ab903fff8c47bd1f499912c3f
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.1.0 - 2026-06-14
|
|
4
|
+
|
|
5
|
+
- Require `active_model` directly when loading `passive_model`, so the gem boots
|
|
6
|
+
without relying on the host Rails application to preload ActiveModel.
|
|
7
|
+
- Replace the broad `rails` runtime dependency with `activemodel`.
|
|
8
|
+
- Align the gem's Ruby requirement with ActiveModel 7.
|
|
9
|
+
- Change `save!` to raise `PassiveModel::ValidationError`, an
|
|
10
|
+
`ActiveModel::ValidationError` subclass, instead of
|
|
11
|
+
`ActiveRecord::RecordInvalid`.
|
|
12
|
+
- Store `before_save` callbacks per subclass so callbacks do not leak between
|
|
13
|
+
unrelated `PassiveModel::Base` subclasses.
|
|
14
|
+
- Add focused tests for independent boot, validations, `save`, `save!`, and
|
|
15
|
+
callback isolation.
|
data/README.md
CHANGED
|
@@ -1,95 +1,162 @@
|
|
|
1
1
|
# PassiveModel
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
PassiveModel provides lightweight model objects for Rails applications when you
|
|
4
|
+
want ActiveModel-style behavior without a database table.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
It is useful for form objects, service inputs, or other plain Ruby objects that
|
|
7
|
+
need validations, naming, translation, conversion, and callback hooks similar to
|
|
8
|
+
Active Record models.
|
|
6
9
|
|
|
7
10
|
## Installation
|
|
8
11
|
|
|
9
12
|
Add this line to your application's Gemfile:
|
|
10
13
|
|
|
11
14
|
```ruby
|
|
12
|
-
gem
|
|
15
|
+
gem "passive_model"
|
|
13
16
|
```
|
|
14
17
|
|
|
15
18
|
And then execute:
|
|
16
19
|
|
|
17
|
-
|
|
20
|
+
```sh
|
|
21
|
+
bundle install
|
|
22
|
+
```
|
|
18
23
|
|
|
19
|
-
Or install it yourself
|
|
24
|
+
Or install it yourself:
|
|
20
25
|
|
|
21
|
-
|
|
26
|
+
```sh
|
|
27
|
+
gem install passive_model
|
|
28
|
+
```
|
|
22
29
|
|
|
23
|
-
|
|
30
|
+
PassiveModel depends on ActiveModel 7.0 or newer. It does not depend on Rails or
|
|
31
|
+
ActiveRecord.
|
|
24
32
|
|
|
25
|
-
|
|
33
|
+
## Usage
|
|
26
34
|
|
|
27
|
-
|
|
35
|
+
Create a class that inherits from `PassiveModel::Base` and define the attributes
|
|
36
|
+
your object exposes.
|
|
28
37
|
|
|
29
|
-
```
|
|
38
|
+
```ruby
|
|
30
39
|
class ContactForm < PassiveModel::Base
|
|
31
40
|
attr_accessor :first_name, :last_name
|
|
32
41
|
|
|
33
42
|
validates :first_name, presence: true
|
|
34
43
|
validates :last_name, presence: true
|
|
35
44
|
validate :first_name_is_not_spam
|
|
36
|
-
|
|
45
|
+
|
|
37
46
|
private
|
|
38
|
-
|
|
47
|
+
|
|
39
48
|
def first_name_is_not_spam
|
|
40
|
-
return
|
|
49
|
+
return unless first_name.to_s.downcase == "test"
|
|
41
50
|
|
|
42
|
-
errors.add(:first_name,
|
|
51
|
+
errors.add(:first_name, "is not valid")
|
|
43
52
|
end
|
|
44
53
|
end
|
|
45
54
|
```
|
|
46
55
|
|
|
47
|
-
|
|
56
|
+
### Creating Objects
|
|
48
57
|
|
|
49
|
-
|
|
58
|
+
Pass initial attributes to `.new`:
|
|
50
59
|
|
|
51
|
-
|
|
60
|
+
```ruby
|
|
61
|
+
form = ContactForm.new(first_name: "John", last_name: "Doe")
|
|
62
|
+
```
|
|
52
63
|
|
|
53
|
-
|
|
64
|
+
### Assigning Attributes
|
|
54
65
|
|
|
55
|
-
|
|
66
|
+
Assign multiple attributes with `attributes=`:
|
|
56
67
|
|
|
57
|
-
|
|
68
|
+
```ruby
|
|
69
|
+
form.attributes = { first_name: "Lewis" }
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The current implementation copies each key directly to an instance variable. For
|
|
73
|
+
example, `first_name: "Lewis"` sets `@first_name`. Define `attr_accessor`,
|
|
74
|
+
`attr_reader`, or explicit methods for values you need to read later.
|
|
58
75
|
|
|
59
|
-
|
|
76
|
+
This assignment style does not call custom setters and does not reject unknown
|
|
77
|
+
attribute names.
|
|
60
78
|
|
|
61
|
-
|
|
79
|
+
### Validations
|
|
62
80
|
|
|
63
|
-
|
|
81
|
+
`PassiveModel::Base` includes ActiveModel validations, so standard Rails
|
|
82
|
+
validators work:
|
|
64
83
|
|
|
65
|
-
|
|
84
|
+
```ruby
|
|
85
|
+
form = ContactForm.new(last_name: "Doe")
|
|
86
|
+
|
|
87
|
+
form.valid? # => false
|
|
88
|
+
form.errors[:first_name] # => ["can't be blank"]
|
|
89
|
+
```
|
|
66
90
|
|
|
67
|
-
|
|
91
|
+
ActiveModel validation callbacks such as `before_validation` and
|
|
92
|
+
`after_validation` are also available.
|
|
68
93
|
|
|
69
|
-
|
|
94
|
+
### Save
|
|
70
95
|
|
|
71
|
-
`
|
|
96
|
+
`save` validates the object. If the object is invalid, it returns `false`. If the
|
|
97
|
+
object is valid, it runs registered `before_save` callbacks and returns `true`.
|
|
98
|
+
|
|
99
|
+
```ruby
|
|
100
|
+
invalid_form = ContactForm.new(last_name: "Doe")
|
|
101
|
+
valid_form = ContactForm.new(first_name: "John", last_name: "Doe")
|
|
102
|
+
|
|
103
|
+
invalid_form.save # => false
|
|
104
|
+
valid_form.save # => true
|
|
105
|
+
```
|
|
72
106
|
|
|
73
|
-
|
|
107
|
+
### Save Bang
|
|
74
108
|
|
|
75
|
-
|
|
109
|
+
`save!` calls `save` and raises `PassiveModel::ValidationError` when the object
|
|
110
|
+
cannot be saved. `PassiveModel::ValidationError` inherits from
|
|
111
|
+
`ActiveModel::ValidationError`; it does not require ActiveRecord.
|
|
76
112
|
|
|
77
|
-
```
|
|
113
|
+
```ruby
|
|
114
|
+
form = ContactForm.new
|
|
115
|
+
|
|
116
|
+
form.save! # raises PassiveModel::ValidationError
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### before_save Callback
|
|
120
|
+
|
|
121
|
+
Register a `before_save` callback with the class method:
|
|
122
|
+
|
|
123
|
+
```ruby
|
|
78
124
|
class ContactForm < PassiveModel::Base
|
|
125
|
+
attr_accessor :first_name
|
|
126
|
+
|
|
127
|
+
validates :first_name, presence: true
|
|
128
|
+
|
|
79
129
|
before_save :send_info_to_mailchimp
|
|
80
|
-
|
|
81
|
-
validate :first_name, presence: true
|
|
82
|
-
|
|
130
|
+
|
|
83
131
|
private
|
|
84
|
-
|
|
132
|
+
|
|
85
133
|
def send_info_to_mailchimp
|
|
86
|
-
# API call
|
|
134
|
+
# API call
|
|
87
135
|
end
|
|
88
136
|
end
|
|
89
137
|
```
|
|
90
138
|
|
|
91
|
-
The callback
|
|
139
|
+
The callback is executed only after validations pass.
|
|
140
|
+
|
|
141
|
+
`before_save` callbacks are stored per class, so callbacks registered on one
|
|
142
|
+
`PassiveModel::Base` subclass do not run for unrelated subclasses.
|
|
143
|
+
|
|
144
|
+
### persisted?
|
|
145
|
+
|
|
146
|
+
`persisted?` is intended to report whether `save` has been called successfully.
|
|
147
|
+
In the current implementation it returns `false` unless an instance sets
|
|
148
|
+
`@persisted` itself.
|
|
149
|
+
|
|
150
|
+
## Behavior Notes
|
|
151
|
+
|
|
152
|
+
These notes describe the current gem behavior and should be reviewed before
|
|
153
|
+
changing runtime code:
|
|
154
|
+
|
|
155
|
+
- `persisted?` does not currently switch to `true` after a successful `save`.
|
|
156
|
+
- Attribute assignment writes instance variables directly instead of using
|
|
157
|
+
ActiveModel attributes or custom setters.
|
|
92
158
|
|
|
93
159
|
## Contributing
|
|
94
160
|
|
|
95
|
-
|
|
161
|
+
For bug reports or feature requests, open an issue at
|
|
162
|
+
https://github.com/RocketApex/passive_model.
|
data/lib/passive_model/base.rb
CHANGED
|
@@ -12,6 +12,27 @@ module PassiveModel
|
|
|
12
12
|
include ActiveModel::Validations::Callbacks
|
|
13
13
|
include ActiveModel::Conversion
|
|
14
14
|
extend ActiveModel::Naming
|
|
15
|
+
extend ActiveModel::Translation
|
|
16
|
+
|
|
17
|
+
class << self
|
|
18
|
+
def before_save(name)
|
|
19
|
+
callback = name.to_sym
|
|
20
|
+
|
|
21
|
+
before_save_callbacks << callback unless before_save_callbacks.include?(callback)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def inherited(subclass)
|
|
25
|
+
super
|
|
26
|
+
|
|
27
|
+
subclass.instance_variable_set(:@before_save_callbacks, before_save_callbacks.dup)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def before_save_callbacks
|
|
33
|
+
@before_save_callbacks ||= []
|
|
34
|
+
end
|
|
35
|
+
end
|
|
15
36
|
|
|
16
37
|
def initialize(hash = {})
|
|
17
38
|
set_attributes(hash)
|
|
@@ -24,12 +45,12 @@ module PassiveModel
|
|
|
24
45
|
def save
|
|
25
46
|
return false unless self.valid?
|
|
26
47
|
|
|
27
|
-
execute_callbacks(
|
|
48
|
+
execute_callbacks(before_save_callbacks)
|
|
28
49
|
true
|
|
29
50
|
end
|
|
30
51
|
|
|
31
52
|
def save!
|
|
32
|
-
raise(
|
|
53
|
+
raise(PassiveModel::ValidationError.new(self)) unless self.save
|
|
33
54
|
end
|
|
34
55
|
|
|
35
56
|
def persisted?
|
|
@@ -44,9 +65,8 @@ module PassiveModel
|
|
|
44
65
|
end
|
|
45
66
|
end
|
|
46
67
|
|
|
47
|
-
def
|
|
48
|
-
|
|
49
|
-
@@before_save_callbacks << name unless @@before_save_callbacks.include?(name)
|
|
68
|
+
def before_save_callbacks
|
|
69
|
+
self.class.send(:before_save_callbacks)
|
|
50
70
|
end
|
|
51
71
|
|
|
52
72
|
def set_attributes(hash)
|
data/lib/passive_model.rb
CHANGED
metadata
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: passive_model
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0
|
|
4
|
+
version: 1.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jey Geethan
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
13
|
+
name: activemodel
|
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
|
16
15
|
requirements:
|
|
17
16
|
- - ">="
|
|
@@ -32,6 +31,7 @@ executables: []
|
|
|
32
31
|
extensions: []
|
|
33
32
|
extra_rdoc_files: []
|
|
34
33
|
files:
|
|
34
|
+
- CHANGELOG.md
|
|
35
35
|
- MIT-LICENSE
|
|
36
36
|
- README.md
|
|
37
37
|
- Rakefile
|
|
@@ -44,9 +44,8 @@ licenses:
|
|
|
44
44
|
metadata:
|
|
45
45
|
allowed_push_host: https://rubygems.org
|
|
46
46
|
homepage_uri: https://github.com/RocketApex/passive_model
|
|
47
|
-
source_code_uri: https://github.com/RocketApex/passive_model
|
|
48
|
-
changelog_uri: https://github.com/RocketApex/passive_model
|
|
49
|
-
post_install_message:
|
|
47
|
+
source_code_uri: https://github.com/RocketApex/passive_model/tree/main
|
|
48
|
+
changelog_uri: https://github.com/RocketApex/passive_model/blob/main/CHANGELOG.md
|
|
50
49
|
rdoc_options: []
|
|
51
50
|
require_paths:
|
|
52
51
|
- lib
|
|
@@ -54,15 +53,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
54
53
|
requirements:
|
|
55
54
|
- - ">="
|
|
56
55
|
- !ruby/object:Gem::Version
|
|
57
|
-
version: 2.
|
|
56
|
+
version: 2.7.0
|
|
58
57
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
59
58
|
requirements:
|
|
60
59
|
- - ">="
|
|
61
60
|
- !ruby/object:Gem::Version
|
|
62
61
|
version: '0'
|
|
63
62
|
requirements: []
|
|
64
|
-
rubygems_version:
|
|
65
|
-
signing_key:
|
|
63
|
+
rubygems_version: 4.0.11
|
|
66
64
|
specification_version: 4
|
|
67
65
|
summary: For using models without saving to the database
|
|
68
66
|
test_files: []
|