acts_as_togglable 0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 265a16f2f5d3dab3e3805e78ca640bc781176929977d5b9de352c64b4d6f88a3
4
+ data.tar.gz: 6e83b89e865a683548723f00a2bd0ac437c4e9f0640e79ca8b7f4de33fd3c68f
5
+ SHA512:
6
+ metadata.gz: 89f1568ad0cb1d4403c02f627a069ce2b0fb58690154d790970b5b387790028166b10d7947f9b6b0c940ee607aae9fea35ebe316126e8cd4c6f5738dd7cab186
7
+ data.tar.gz: 26234f7964b4dbc59bff3a640b468ef5fff8f11275db63a7c350396b0353ba85d4a70ca456d01f3b7e2ed8bc3c4b3b92c7e6630b94460846f1a300867cb7c71b
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Jose Ferrer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # acts_as_togglable
2
+
3
+ Named bang toggle methods for ActiveRecord boolean attributes.
4
+
5
+ Instead of `user.toggle!(:admin)` (which bypasses validations), get clean named methods like `user.admin!` that run validations and callbacks.
6
+
7
+ ## Installation
8
+
9
+ Add to your Gemfile:
10
+
11
+ ```ruby
12
+ gem "acts_as_togglable"
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ### Explicit mode
18
+
19
+ Specify which boolean attributes get bang methods:
20
+
21
+ ```ruby
22
+ class User < ApplicationRecord
23
+ acts_as_togglable :admin, :active
24
+ end
25
+
26
+ user = User.create(admin: false, active: true)
27
+ user.admin! # => true (toggled and saved)
28
+ user.active! # => false (toggled and saved)
29
+ user.admin! # => false (toggled back)
30
+ ```
31
+
32
+ ### Auto mode
33
+
34
+ Generate bang methods for all boolean columns:
35
+
36
+ ```ruby
37
+ class Post < ApplicationRecord
38
+ acts_as_togglable
39
+ end
40
+
41
+ post = Post.create(published: false, featured: true)
42
+ post.published! # => true
43
+ post.featured! # => false
44
+ ```
45
+
46
+ ## How it works
47
+
48
+ Each bang method:
49
+
50
+ - Toggles the boolean value
51
+ - Saves with `update!` (runs validations and callbacks)
52
+ - Returns the new boolean value
53
+ - Raises `ActiveRecord::RecordInvalid` if validations fail
54
+
55
+ ## Why not just use `toggle!`?
56
+
57
+ Rails' built-in `toggle!` bypasses validations and callbacks. This matters when your app depends on them.
58
+
59
+ For example, a blog post that updates the sitemap when published:
60
+
61
+ ```ruby
62
+ class Post < ApplicationRecord
63
+ acts_as_togglable :published
64
+
65
+ after_save :update_sitemap, if: :published?
66
+
67
+ private
68
+
69
+ def update_sitemap
70
+ SitemapGenerator.rebuild
71
+ end
72
+ end
73
+ ```
74
+
75
+ ```ruby
76
+ # With toggle! — callback is SKIPPED, sitemap not updated
77
+ post.toggle!(:published)
78
+
79
+ # With acts_as_togglable — callback fires, sitemap updated
80
+ post.published!
81
+ ```
82
+
83
+ Other cases where callbacks and validations matter:
84
+
85
+ - Sending a welcome email when a user is activated
86
+ - Logging an audit trail when permissions change
87
+ - Validating that only one post can be featured at a time
88
+
89
+ ## Comparison with Rails toggle!
90
+
91
+ | | `acts_as_togglable` | Rails `toggle!` |
92
+ |---|---|---|
93
+ | Syntax | `user.admin!` | `user.toggle!(:admin)` |
94
+ | Validations | Runs | Bypassed |
95
+ | Callbacks | Runs | Bypassed |
96
+ | Return value | New boolean | `true` |
97
+
98
+ ## License
99
+
100
+ MIT
@@ -0,0 +1,55 @@
1
+ require "active_support/concern"
2
+
3
+ module ActsAsTogglable
4
+ module Model
5
+ extend ActiveSupport::Concern
6
+
7
+ class_methods do
8
+ def acts_as_togglable(*attributes)
9
+ if attributes.any?
10
+ attributes.each do |attr|
11
+ define_method(:"#{attr}!") do
12
+ new_value = !public_send(attr)
13
+ update!(attr => new_value)
14
+ new_value
15
+ end
16
+ end
17
+ else
18
+ @_acts_as_togglable_auto = true
19
+ end
20
+ end
21
+
22
+ def _acts_as_togglable_auto?
23
+ @_acts_as_togglable_auto == true
24
+ end
25
+ end
26
+
27
+ def method_missing(method_name, *args, &block)
28
+ if self.class._acts_as_togglable_auto? && method_name.to_s.end_with?("!")
29
+ attr = method_name.to_s.chomp("!")
30
+ column = self.class.columns_hash[attr]
31
+
32
+ if column&.type == :boolean
33
+ self.class.define_method(method_name) do
34
+ new_value = !public_send(attr)
35
+ update!(attr => new_value)
36
+ new_value
37
+ end
38
+ return public_send(method_name)
39
+ end
40
+ end
41
+
42
+ super
43
+ end
44
+
45
+ def respond_to_missing?(method_name, include_private = false)
46
+ if self.class._acts_as_togglable_auto? && method_name.to_s.end_with?("!")
47
+ attr = method_name.to_s.chomp("!")
48
+ column = self.class.columns_hash[attr]
49
+ return true if column&.type == :boolean
50
+ end
51
+
52
+ super
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,3 @@
1
+ module ActsAsTogglable
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,10 @@
1
+ require_relative "acts_as_togglable/version"
2
+ require_relative "acts_as_togglable/model"
3
+
4
+ if defined?(ActiveSupport.on_load)
5
+ ActiveSupport.on_load(:active_record) do
6
+ include ActsAsTogglable::Model
7
+ end
8
+ elsif defined?(ActiveRecord::Base)
9
+ ActiveRecord::Base.include(ActsAsTogglable::Model)
10
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: acts_as_togglable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jose Ferrer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-02-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '6.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '6.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '6.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '6.0'
41
+ description: Adds methods like user.admin! that toggle boolean attributes with validations
42
+ and callbacks, unlike Rails toggle! which bypasses them.
43
+ email:
44
+ - estoy@moviendo.me
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - LICENSE.txt
50
+ - README.md
51
+ - lib/acts_as_togglable.rb
52
+ - lib/acts_as_togglable/model.rb
53
+ - lib/acts_as_togglable/version.rb
54
+ homepage: https://github.com/moviendome/acts_as_togglable
55
+ licenses:
56
+ - MIT
57
+ metadata:
58
+ source_code_uri: https://github.com/moviendome/acts_as_togglable
59
+ changelog_uri: https://github.com/moviendome/acts_as_togglable/blob/main/CHANGELOG.md
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubygems_version: 3.5.22
76
+ signing_key:
77
+ specification_version: 4
78
+ summary: Named bang toggle methods for ActiveRecord booleans
79
+ test_files: []