├── .github
├── logo-dark.svg
├── logo-light.svg
└── workflows
│ └── main.yml
├── .gitignore
├── .standard.yml
├── Gemfile
├── Gemfile.lock
├── LICENSE.txt
├── README.md
├── Rakefile
├── bin
├── console
├── release
└── setup
├── db
└── migrate
│ └── 20241128150951_create_rails_vaults.rb
├── lib
├── generators
│ └── rails_vault
│ │ ├── add_generator.rb
│ │ ├── install_generator.rb
│ │ └── templates
│ │ └── vault.rb.tt
├── rails_vault.rb
└── rails_vault
│ ├── base.rb
│ ├── engine.rb
│ ├── vaults.rb
│ └── version.rb
└── rails_vault.gemspec
/.github/logo-dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.github/logo-light.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Ruby
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | pull_request:
9 |
10 | jobs:
11 | build:
12 | runs-on: ubuntu-latest
13 | name: Ruby ${{ matrix.ruby }}
14 | strategy:
15 | matrix:
16 | ruby:
17 | - '3.1.0'
18 |
19 | steps:
20 | - uses: actions/checkout@v4
21 | - name: Set up Ruby
22 | uses: ruby/setup-ruby@v1
23 | with:
24 | ruby-version: ${{ matrix.ruby }}
25 | bundler-cache: true
26 | - name: Run Standard
27 | run: bundle exec standardrb
28 | - name: Run the default task
29 | run: bundle exec rake
30 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.bundle/
2 | /.yardoc
3 | /_yardoc/
4 | /coverage/
5 | /doc/
6 | /pkg/
7 | /spec/reports/
8 | /tmp/
9 |
--------------------------------------------------------------------------------
/.standard.yml:
--------------------------------------------------------------------------------
1 | ruby_version: 3.1.0
2 | ignore:
3 | - "tmp/**/*"
4 | - "test/**/*"
5 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source "https://rubygems.org"
4 |
5 | gemspec
6 |
7 | group :development do
8 | gem "standard"
9 | end
10 |
11 | group :development, :test do
12 | gem "minitest"
13 | gem "debug", "~> 1.9", ">= 1.9.2"
14 | end
15 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | PATH
2 | remote: .
3 | specs:
4 | rails_vault (0.1.0)
5 | rails (>= 7.2.2)
6 | store_attribute (>= 1.3)
7 |
8 | GEM
9 | remote: https://rubygems.org/
10 | specs:
11 | actioncable (7.2.2.1)
12 | actionpack (= 7.2.2.1)
13 | activesupport (= 7.2.2.1)
14 | nio4r (~> 2.0)
15 | websocket-driver (>= 0.6.1)
16 | zeitwerk (~> 2.6)
17 | actionmailbox (7.2.2.1)
18 | actionpack (= 7.2.2.1)
19 | activejob (= 7.2.2.1)
20 | activerecord (= 7.2.2.1)
21 | activestorage (= 7.2.2.1)
22 | activesupport (= 7.2.2.1)
23 | mail (>= 2.8.0)
24 | actionmailer (7.2.2.1)
25 | actionpack (= 7.2.2.1)
26 | actionview (= 7.2.2.1)
27 | activejob (= 7.2.2.1)
28 | activesupport (= 7.2.2.1)
29 | mail (>= 2.8.0)
30 | rails-dom-testing (~> 2.2)
31 | actionpack (7.2.2.1)
32 | actionview (= 7.2.2.1)
33 | activesupport (= 7.2.2.1)
34 | nokogiri (>= 1.8.5)
35 | racc
36 | rack (>= 2.2.4, < 3.2)
37 | rack-session (>= 1.0.1)
38 | rack-test (>= 0.6.3)
39 | rails-dom-testing (~> 2.2)
40 | rails-html-sanitizer (~> 1.6)
41 | useragent (~> 0.16)
42 | actiontext (7.2.2.1)
43 | actionpack (= 7.2.2.1)
44 | activerecord (= 7.2.2.1)
45 | activestorage (= 7.2.2.1)
46 | activesupport (= 7.2.2.1)
47 | globalid (>= 0.6.0)
48 | nokogiri (>= 1.8.5)
49 | actionview (7.2.2.1)
50 | activesupport (= 7.2.2.1)
51 | builder (~> 3.1)
52 | erubi (~> 1.11)
53 | rails-dom-testing (~> 2.2)
54 | rails-html-sanitizer (~> 1.6)
55 | activejob (7.2.2.1)
56 | activesupport (= 7.2.2.1)
57 | globalid (>= 0.3.6)
58 | activemodel (7.2.2.1)
59 | activesupport (= 7.2.2.1)
60 | activerecord (7.2.2.1)
61 | activemodel (= 7.2.2.1)
62 | activesupport (= 7.2.2.1)
63 | timeout (>= 0.4.0)
64 | activestorage (7.2.2.1)
65 | actionpack (= 7.2.2.1)
66 | activejob (= 7.2.2.1)
67 | activerecord (= 7.2.2.1)
68 | activesupport (= 7.2.2.1)
69 | marcel (~> 1.0)
70 | activesupport (7.2.2.1)
71 | base64
72 | benchmark (>= 0.3)
73 | bigdecimal
74 | concurrent-ruby (~> 1.0, >= 1.3.1)
75 | connection_pool (>= 2.2.5)
76 | drb
77 | i18n (>= 1.6, < 2)
78 | logger (>= 1.4.2)
79 | minitest (>= 5.1)
80 | securerandom (>= 0.3)
81 | tzinfo (~> 2.0, >= 2.0.5)
82 | ast (2.4.2)
83 | base64 (0.2.0)
84 | benchmark (0.4.0)
85 | bigdecimal (3.1.9)
86 | builder (3.3.0)
87 | concurrent-ruby (1.3.5)
88 | connection_pool (2.5.0)
89 | crass (1.0.6)
90 | date (3.4.1)
91 | debug (1.10.0)
92 | irb (~> 1.10)
93 | reline (>= 0.3.8)
94 | drb (2.2.1)
95 | erubi (1.13.1)
96 | globalid (1.2.1)
97 | activesupport (>= 6.1)
98 | i18n (1.14.7)
99 | concurrent-ruby (~> 1.0)
100 | io-console (0.8.0)
101 | irb (1.15.1)
102 | pp (>= 0.6.0)
103 | rdoc (>= 4.0.0)
104 | reline (>= 0.4.2)
105 | json (2.10.1)
106 | language_server-protocol (3.17.0.4)
107 | lint_roller (1.1.0)
108 | logger (1.6.6)
109 | loofah (2.24.0)
110 | crass (~> 1.0.2)
111 | nokogiri (>= 1.12.0)
112 | mail (2.8.1)
113 | mini_mime (>= 0.1.1)
114 | net-imap
115 | net-pop
116 | net-smtp
117 | marcel (1.0.4)
118 | mini_mime (1.1.5)
119 | mini_portile2 (2.8.8)
120 | minitest (5.25.4)
121 | net-imap (0.5.6)
122 | date
123 | net-protocol
124 | net-pop (0.1.2)
125 | net-protocol
126 | net-protocol (0.2.2)
127 | timeout
128 | net-smtp (0.5.1)
129 | net-protocol
130 | nio4r (2.7.4)
131 | nokogiri (1.18.2)
132 | mini_portile2 (~> 2.8.2)
133 | racc (~> 1.4)
134 | parallel (1.26.3)
135 | parser (3.3.7.1)
136 | ast (~> 2.4.1)
137 | racc
138 | pp (0.6.2)
139 | prettyprint
140 | prettyprint (0.2.0)
141 | psych (5.2.3)
142 | date
143 | stringio
144 | racc (1.8.1)
145 | rack (3.1.10)
146 | rack-session (2.1.0)
147 | base64 (>= 0.1.0)
148 | rack (>= 3.0.0)
149 | rack-test (2.2.0)
150 | rack (>= 1.3)
151 | rackup (2.2.1)
152 | rack (>= 3)
153 | rails (7.2.2.1)
154 | actioncable (= 7.2.2.1)
155 | actionmailbox (= 7.2.2.1)
156 | actionmailer (= 7.2.2.1)
157 | actionpack (= 7.2.2.1)
158 | actiontext (= 7.2.2.1)
159 | actionview (= 7.2.2.1)
160 | activejob (= 7.2.2.1)
161 | activemodel (= 7.2.2.1)
162 | activerecord (= 7.2.2.1)
163 | activestorage (= 7.2.2.1)
164 | activesupport (= 7.2.2.1)
165 | bundler (>= 1.15.0)
166 | railties (= 7.2.2.1)
167 | rails-dom-testing (2.2.0)
168 | activesupport (>= 5.0.0)
169 | minitest
170 | nokogiri (>= 1.6)
171 | rails-html-sanitizer (1.6.2)
172 | loofah (~> 2.21)
173 | nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
174 | railties (7.2.2.1)
175 | actionpack (= 7.2.2.1)
176 | activesupport (= 7.2.2.1)
177 | irb (~> 1.13)
178 | rackup (>= 1.0.0)
179 | rake (>= 12.2)
180 | thor (~> 1.0, >= 1.2.2)
181 | zeitwerk (~> 2.6)
182 | rainbow (3.1.1)
183 | rake (13.2.1)
184 | rdoc (6.12.0)
185 | psych (>= 4.0.0)
186 | regexp_parser (2.10.0)
187 | reline (0.6.0)
188 | io-console (~> 0.5)
189 | rubocop (1.71.2)
190 | json (~> 2.3)
191 | language_server-protocol (>= 3.17.0)
192 | parallel (~> 1.10)
193 | parser (>= 3.3.0.2)
194 | rainbow (>= 2.2.2, < 4.0)
195 | regexp_parser (>= 2.9.3, < 3.0)
196 | rubocop-ast (>= 1.38.0, < 2.0)
197 | ruby-progressbar (~> 1.7)
198 | unicode-display_width (>= 2.4.0, < 4.0)
199 | rubocop-ast (1.38.0)
200 | parser (>= 3.3.1.0)
201 | rubocop-performance (1.23.1)
202 | rubocop (>= 1.48.1, < 2.0)
203 | rubocop-ast (>= 1.31.1, < 2.0)
204 | ruby-progressbar (1.13.0)
205 | securerandom (0.4.1)
206 | standard (1.45.0)
207 | language_server-protocol (~> 3.17.0.2)
208 | lint_roller (~> 1.0)
209 | rubocop (~> 1.71.0)
210 | standard-custom (~> 1.0.0)
211 | standard-performance (~> 1.6)
212 | standard-custom (1.0.2)
213 | lint_roller (~> 1.0)
214 | rubocop (~> 1.50)
215 | standard-performance (1.6.0)
216 | lint_roller (~> 1.1)
217 | rubocop-performance (~> 1.23.0)
218 | store_attribute (2.0.0)
219 | activerecord (>= 6.1)
220 | stringio (3.1.3)
221 | thor (1.3.2)
222 | timeout (0.4.3)
223 | tzinfo (2.0.6)
224 | concurrent-ruby (~> 1.0)
225 | unicode-display_width (3.1.4)
226 | unicode-emoji (~> 4.0, >= 4.0.4)
227 | unicode-emoji (4.0.4)
228 | useragent (0.16.11)
229 | websocket-driver (0.7.7)
230 | base64
231 | websocket-extensions (>= 0.1.0)
232 | websocket-extensions (0.1.5)
233 | zeitwerk (2.6.18)
234 |
235 | PLATFORMS
236 | arm64-darwin-23
237 | x86_64-linux
238 |
239 | DEPENDENCIES
240 | debug (~> 1.9, >= 1.9.2)
241 | minitest
242 | rails_vault!
243 | standard
244 |
245 | BUNDLED WITH
246 | 2.3.3
247 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2025 Rails Designer
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.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # rails_vault
2 |
3 | Simple and easy to add settings, preferences and so on to any model. See [an example](#usage).
4 |
5 |
6 | **Sponsored By [Rails Designer](https://railsdesigner.com/)**
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Want to make JavaScript your second-favorite language? 👉 [JavaScript for Rails Developers](https://javascriptforrails.com/)
17 |
18 |
19 | ## Installation
20 |
21 | ```bash
22 | bundle add rails_vault
23 | rails generate rails_vault:install
24 | rails db:migrate
25 | ```
26 |
27 |
28 | ## Usage
29 |
30 | Generate a vault:
31 | ```bash
32 | rails generate rails_vault:add MODEL::VAULT [field:type field:type]
33 | ```
34 |
35 | Example:
36 |
37 | ```bash
38 | rails generate rails_vault:add User::Preferences \
39 | time_zone:string \
40 | datetime_format:string \
41 | hotkeys_disabled:boolean
42 | ```
43 |
44 | This will:
45 | 1. Create a vault class at **app/models/users/preferences.rb**
46 | 2. Add `vault :preferences` to your User model
47 |
48 | ### Define vault attributes
49 |
50 | ```ruby
51 | class User::Preferences < RailsVault::Base
52 | vault_attribute :time_zone, :string, default: "UTC"
53 | vault_attribute :datetime_format, :string, default: "dd-mm-yyyy"
54 | vault_attribute :hotkeys_disabled, :boolean, default: false
55 | end
56 | ```
57 |
58 | ### Read and write values
59 |
60 | ```ruby
61 | user = User.first
62 | user.create_preferences # => User::Preferences Create (6.3ms) INSERT INTO "rails_vaults" …
63 | user.preferences.time_zone # => "UTC"
64 | user.preferences.hotkeys_disabled? # => false
65 |
66 | user.preferences.update time_zone: "Amsterdam", hotkeys_disabled: true
67 |
68 | user.preferences.time_zone # => "Amsterdam"
69 | user.preferences.hotkeys_disabled? # => true
70 | ```
71 |
72 | > **Note**: currently **rails_vault** is only tested against PostgreSQL, but PRs for improvements to other databases are appreciated.
73 |
74 |
75 | ## Contributing
76 |
77 | This project uses [Standard](https://github.com/testdouble/standard) for formatting Ruby code. Please make sure to run `be standardrb` before submitting pull requests. Run tests via `rails test`.
78 |
79 |
80 | ## License
81 |
82 | rails_vault is released under the [MIT License](https://opensource.org/licenses/MIT).
83 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "bundler/gem_tasks"
4 | require "minitest/test_task"
5 |
6 | Minitest::TestTask.create
7 |
8 | require "standard/rake"
9 |
10 | task default: %i[test standard]
11 |
--------------------------------------------------------------------------------
/bin/console:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | require "bundler/setup"
5 | require "rails_vault"
6 |
7 | # You can add fixtures and/or initialization code here to make experimenting
8 | # with your gem easier. You can also use a different console, if you like.
9 |
10 | require "irb"
11 | IRB.start(__FILE__)
12 |
--------------------------------------------------------------------------------
/bin/release:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | VERSION=$1
4 |
5 | if [ -z "$VERSION" ]; then
6 | echo "Error: The version number is required."
7 | echo "Usage: $0 "
8 | exit 1
9 | fi
10 |
11 | printf "module RailsVault\n VERSION = \"$VERSION\"\nend\n" > ./lib/rails_vault/version.rb
12 | bundle
13 | git add Gemfile.lock lib/rails_vault/version.rb
14 | git commit -m "Bump version for $VERSION"
15 | git push
16 | git tag v$VERSION
17 | git push --tags
18 | gem build rails_vault.gemspec
19 | gem push "rails_vault-$VERSION.gem"
20 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -euo pipefail
3 | IFS=$'\n\t'
4 | set -vx
5 |
6 | bundle install
7 |
--------------------------------------------------------------------------------
/db/migrate/20241128150951_create_rails_vaults.rb:
--------------------------------------------------------------------------------
1 | class CreateRailsVaults < ActiveRecord::Migration[7.0]
2 | def change
3 | create_table :rails_vaults do |t|
4 | t.belongs_to :resource, polymorphic: true, null: false
5 | t.string :scope, null: false
6 |
7 | if t.respond_to?(:jsonb)
8 | t.jsonb :payload, null: false, default: {}
9 | else
10 | t.json :payload, null: false, default: {}
11 | end
12 |
13 | t.timestamps
14 | end
15 |
16 | add_index :rails_vaults, :scope
17 | if connection.adapter_name.downcase == "postgresql"
18 | add_index :rails_vaults, :payload, using: :gin
19 | else
20 | add_index :rails_vaults, :payload
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/lib/generators/rails_vault/add_generator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "rails/generators/named_base"
4 |
5 | module RailsVault
6 | module Generators
7 | class AddGenerator < Rails::Generators::NamedBase
8 | source_root File.expand_path("../templates", __FILE__)
9 |
10 | argument :attributes, type: :array, default: [], banner: "field:type field:type"
11 |
12 | def create_vault_file
13 | template "vault.rb", File.join("app/models", class_path, "#{file_name}.rb")
14 | end
15 |
16 | def inject_vault_into_model
17 | parent_class = class_name.split("::").first
18 |
19 | inject_into_class "app/models/#{class_path.join("/")}.rb", parent_class do
20 | " vault :#{plural_name}\n"
21 | end
22 | end
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/lib/generators/rails_vault/install_generator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "rails/generators/base"
4 |
5 | module RailsVault
6 | module Generators
7 | class InstallGenerator < Rails::Generators::Base
8 | source_root File.expand_path("../templates", __FILE__)
9 |
10 | def create_migrations
11 | rails_command "railties:install:migrations FROM=rails_vault", inline: true
12 | end
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/lib/generators/rails_vault/templates/vault.rb.tt:
--------------------------------------------------------------------------------
1 | class <%= class_name %> < RailsVault::Base
2 | <%- attributes.each do |attribute| -%>
3 | vault_attribute :<%= attribute.name %>, :<%= attribute.type %>
4 | <%- end -%>
5 | end
6 |
--------------------------------------------------------------------------------
/lib/rails_vault.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "store_attribute"
4 | require "rails_vault/version"
5 | require "rails_vault/engine"
6 | require "rails_vault/base"
7 | require "rails_vault/vaults"
8 |
9 | module RailsVault
10 | class Error < StandardError; end
11 | end
12 |
--------------------------------------------------------------------------------
/lib/rails_vault/base.rb:
--------------------------------------------------------------------------------
1 | module RailsVault
2 | class Base < ActiveRecord::Base
3 | self.table_name = "rails_vaults"
4 |
5 | belongs_to :resource, polymorphic: true
6 |
7 | class << self
8 | def inherited(subclass)
9 | super
10 |
11 | scope_name = subclass.name.demodulize.underscore
12 |
13 | subclass.vault_scope(scope_name)
14 | end
15 |
16 | def vault_scope(scope_name)
17 | default_scope { where(scope: scope_name) }
18 | end
19 |
20 | def vault_attribute(key, *attributes)
21 | options = attributes.extract_options!
22 |
23 | store_attribute :payload, key, *attributes, **options
24 | end
25 | end
26 |
27 | def vault_attributes = payload.keys
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/lib/rails_vault/engine.rb:
--------------------------------------------------------------------------------
1 | module RailsVault
2 | class Engine < ::Rails::Engine
3 | isolate_namespace RailsVault
4 |
5 | initializer "rails_vault.active_record" do
6 | ActiveSupport.on_load(:active_record) do
7 | include RailsVault::Vaults
8 | end
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/lib/rails_vault/vaults.rb:
--------------------------------------------------------------------------------
1 | module RailsVault
2 | module Vaults
3 | extend ActiveSupport::Concern
4 |
5 | class_methods do
6 | def vault(association_name, class_name: nil)
7 | has_one(
8 | association_name,
9 | as: :resource,
10 | class_name: class_name.presence || "#{self}::#{association_name.to_s.camelize}",
11 | dependent: :destroy
12 | )
13 | end
14 |
15 | def vaults(*association_names)
16 | association_names.each do |association_name|
17 | has_one(association_name, as: :resource, dependent: :destroy)
18 | end
19 | end
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/lib/rails_vault/version.rb:
--------------------------------------------------------------------------------
1 | module RailsVault
2 | VERSION = "0.1.0"
3 | end
4 |
--------------------------------------------------------------------------------
/rails_vault.gemspec:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require_relative "lib/rails_vault/version"
4 |
5 | Gem::Specification.new do |spec|
6 | spec.name = "rails_vault"
7 | spec.version = RailsVault::VERSION
8 | spec.authors = ["Rails Designer Developers"]
9 | spec.email = ["devs@railsdesigner.com"]
10 | spec.summary = "Simple and easy to add settings, preferences and so on to any model."
11 | spec.description = "Rails Vault is a simple to use gem to add settings and preferences to ActiveRecord models. The settings are stored as JSON in a separate table."
12 | spec.homepage = "https://railsdesigner.com/rails-vault/"
13 | spec.license = "MIT"
14 |
15 | spec.metadata["homepage_uri"] = spec.homepage
16 | spec.metadata["source_code_uri"] = "https://github.com/Rails-Designer/rails_vault/"
17 |
18 | spec.files = Dir["{bin,db,lib}/**/*", "Rakefile", "README.md", "rails_vault.gemspec", "Gemfile", "Gemfile.lock"]
19 |
20 | spec.required_ruby_version = ">= 3.1.0"
21 | spec.add_dependency "rails", ">= 7.2.2"
22 | spec.add_dependency "store_attribute", ">= 1.3"
23 | end
24 |
--------------------------------------------------------------------------------