identifiable 0.1.0 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 490257eea4bca942162766045db54e9cac0b3cdbedcea08a418e3b659cc209ec
4
- data.tar.gz: e3cfa1004c351eac0170b1740e291b9f3a878c72a450b9cc7c787ae999b33d83
3
+ metadata.gz: e229c2c8c0e8206c88cdbd14e66472bb7e16a65ab0d0db94e4e312622224fca1
4
+ data.tar.gz: 6898197f22c73a31ea84585076b2638427dbc184b5a60ae8e3ba7cc5d9309782
5
5
  SHA512:
6
- metadata.gz: e54d72207095067e3b7fea091a5bb41665525d43c5ececa51c228f5ee824d1fc7f55c5c2ca5aac177504456508b60bef7a7d61a27757cc3a801be269cc2b4f0c
7
- data.tar.gz: e685fb908d6122fc2e4ce52cb0957bfb50c813705a9acecfe64ddb5ec7fea09dbbddacb346ec70d83de2c4b73107189edc53b5ae0554d58cafc68eed24189da3
6
+ metadata.gz: 462f3c632763996b78500c622433e2e058914ee0136b9c6a4478085f09270ae9f604dea0e6c1f31f9a11fda4366f018ba1d755617c9a12431f5ff9757f6fab47
7
+ data.tar.gz: 715519049734d87cce4399ab2e5c510e88b4bbe4626b53986a4e21ed9d68e6cbfa3e110c6829c71b369765e5e3efd3b648c747f49207818b04cfaa19db5a92ad
@@ -5,14 +5,14 @@ jobs:
5
5
  name: 'Test Suite'
6
6
  strategy:
7
7
  matrix:
8
- ruby: [2.5, 2.6, 2.7]
8
+ ruby: [3.2.8, 3.3.8, 3.4.4]
9
9
  runs-on: ubuntu-latest
10
10
  steps:
11
11
  - uses: actions/checkout@v2
12
12
  - uses: ruby/setup-ruby@v1
13
13
  with:
14
14
  ruby-version: ${{ matrix.ruby }}
15
- - uses: actions/cache@v1
15
+ - uses: actions/cache@v4
16
16
  with:
17
17
  path: vendor/bundle
18
18
  key: bundle-${{ matrix.ruby }}-${{ hashFiles('**/*.gemspec') }}
@@ -26,11 +26,11 @@ jobs:
26
26
  - uses: actions/checkout@v2
27
27
  - uses: ruby/setup-ruby@v1
28
28
  with:
29
- ruby-version: 2.7.2
30
- - uses: actions/cache@v1
29
+ ruby-version: 3.2.8
30
+ - uses: actions/cache@v4
31
31
  with:
32
32
  path: vendor/bundle
33
- key: bundle-2.7.2-${{ hashFiles('**/*.gemspec') }}
34
- restore-keys: bundle-2.7.2
33
+ key: bundle-3.2.8-${{ hashFiles('**/*.gemspec') }}
34
+ restore-keys: bundle-3.2.8
35
35
  - run: bundle install --jobs 4 --retry 3 --path vendor/bundle
36
36
  - run: bundle exec rubocop
data/.rubocop.yml CHANGED
@@ -1,9 +1,20 @@
1
1
  AllCops:
2
2
  NewCops: enable
3
+ SuggestExtensions: false
4
+
5
+ Gemspec/RequiredRubyVersion:
6
+ Enabled: false
7
+
8
+ Gemspec/DevelopmentDependencies:
9
+ Enabled: false
3
10
 
4
11
  Style/Documentation:
5
12
  Enabled: false
6
13
 
14
+ Style/StringLiterals:
15
+ Enabled: true
16
+ EnforcedStyle: double_quotes
17
+
7
18
  Layout/LineLength:
8
19
  Enabled: false
9
20
 
data/.tool-versions CHANGED
@@ -1 +1 @@
1
- ruby 2.7.1
1
+ ruby 3.2.0
data/CHANGELOG.md ADDED
@@ -0,0 +1,39 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## Unreleased
6
+
7
+ *Nothing yet*
8
+
9
+ ## 1.0.0 - Released June 22, 2025
10
+
11
+ ### Added
12
+ - **Configuration system**: Use `Identifiable.configure` to set the `overwrite_to_key` and `overwrite_to_param` options that control whether Identifiable overrides Rails' `to_key` and `to_param` model methods. Both options default to `true` to maintain backward compatibility.
13
+ - Support for Ruby version 3.2, 3.3, and 3.4.
14
+
15
+ ### Changed
16
+ - This is now considered a stable 1.0 release.
17
+
18
+ ### Removed
19
+ - Support for Ruby 2.7, 3.0, and 3.1. The new minimum supported Ruby version is 3.2.
20
+ - Support for Rails versions below 7.0. The new minimum supported Rails version is 7.0.
21
+
22
+ ### Fixed
23
+ - Configuration options resolve compatibility issues with other gems like Devise (#7).
24
+
25
+ ## 0.2.0 - Released October 16, 2022
26
+
27
+ ### Added
28
+ - Support for Ruby versions 3.0 and 3.1.
29
+ - Models that include identifiable will now use Identifiable's public ID for the `#to_key` and `#to_param` methods, meaning that you can now use Rails helpers like `dom_id(@order)` and `order_path(@order)`, and they'll use public IDs instead of the database primary key.
30
+
31
+ ### Removed
32
+ - Support for Ruby 2.5 and 2.6. The new minimum supported Ruby version is 2.7.
33
+
34
+ ### Fixed
35
+ - A migration will no longer fail if the model has identifiable but the table doesn't exist yet.
36
+
37
+ ## 0.1.0 - Released November 15, 2020
38
+
39
+ This is the early, initial release of Identifiable.
data/Gemfile CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source 'https://rubygems.org'
3
+ source "https://rubygems.org"
4
4
 
5
5
  gemspec
data/Gemfile.lock CHANGED
@@ -1,70 +1,99 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- identifiable (0.1.0)
5
- activerecord (> 4.2)
4
+ identifiable (1.0.0)
5
+ activerecord (> 7)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- activemodel (6.0.3.4)
11
- activesupport (= 6.0.3.4)
12
- activerecord (6.0.3.4)
13
- activemodel (= 6.0.3.4)
14
- activesupport (= 6.0.3.4)
15
- activesupport (6.0.3.4)
16
- concurrent-ruby (~> 1.0, >= 1.0.2)
17
- i18n (>= 0.7, < 2)
18
- minitest (~> 5.1)
19
- tzinfo (~> 1.1)
20
- zeitwerk (~> 2.2, >= 2.2.2)
21
- ast (2.4.1)
22
- concurrent-ruby (1.1.7)
23
- diff-lcs (1.4.4)
24
- i18n (1.8.5)
10
+ activemodel (8.0.2)
11
+ activesupport (= 8.0.2)
12
+ activerecord (8.0.2)
13
+ activemodel (= 8.0.2)
14
+ activesupport (= 8.0.2)
15
+ timeout (>= 0.4.0)
16
+ activesupport (8.0.2)
17
+ base64
18
+ benchmark (>= 0.3)
19
+ bigdecimal
20
+ concurrent-ruby (~> 1.0, >= 1.3.1)
21
+ connection_pool (>= 2.2.5)
22
+ drb
23
+ i18n (>= 1.6, < 2)
24
+ logger (>= 1.4.2)
25
+ minitest (>= 5.1)
26
+ securerandom (>= 0.3)
27
+ tzinfo (~> 2.0, >= 2.0.5)
28
+ uri (>= 0.13.1)
29
+ ast (2.4.3)
30
+ base64 (0.3.0)
31
+ benchmark (0.4.1)
32
+ bigdecimal (3.2.2)
33
+ concurrent-ruby (1.3.5)
34
+ connection_pool (2.5.3)
35
+ diff-lcs (1.6.2)
36
+ drb (2.2.3)
37
+ i18n (1.14.7)
25
38
  concurrent-ruby (~> 1.0)
26
- minitest (5.14.2)
27
- parallel (1.20.0)
28
- parser (2.7.2.0)
39
+ json (2.12.2)
40
+ language_server-protocol (3.17.0.5)
41
+ lint_roller (1.1.0)
42
+ logger (1.7.0)
43
+ mini_portile2 (2.8.9)
44
+ minitest (5.25.5)
45
+ parallel (1.27.0)
46
+ parser (3.3.8.0)
29
47
  ast (~> 2.4.1)
30
- rainbow (3.0.0)
48
+ racc
49
+ prism (1.4.0)
50
+ racc (1.8.1)
51
+ rainbow (3.1.1)
31
52
  rake (12.3.3)
32
- regexp_parser (1.8.2)
33
- rexml (3.2.4)
34
- rspec (3.10.0)
35
- rspec-core (~> 3.10.0)
36
- rspec-expectations (~> 3.10.0)
37
- rspec-mocks (~> 3.10.0)
38
- rspec-core (3.10.0)
39
- rspec-support (~> 3.10.0)
40
- rspec-expectations (3.10.0)
53
+ regexp_parser (2.10.0)
54
+ rspec (3.13.1)
55
+ rspec-core (~> 3.13.0)
56
+ rspec-expectations (~> 3.13.0)
57
+ rspec-mocks (~> 3.13.0)
58
+ rspec-core (3.13.4)
59
+ rspec-support (~> 3.13.0)
60
+ rspec-expectations (3.13.5)
41
61
  diff-lcs (>= 1.2.0, < 2.0)
42
- rspec-support (~> 3.10.0)
43
- rspec-mocks (3.10.0)
62
+ rspec-support (~> 3.13.0)
63
+ rspec-mocks (3.13.5)
44
64
  diff-lcs (>= 1.2.0, < 2.0)
45
- rspec-support (~> 3.10.0)
46
- rspec-support (3.10.0)
47
- rubocop (1.3.0)
65
+ rspec-support (~> 3.13.0)
66
+ rspec-support (3.13.4)
67
+ rubocop (1.77.0)
68
+ json (~> 2.3)
69
+ language_server-protocol (~> 3.17.0.2)
70
+ lint_roller (~> 1.1.0)
48
71
  parallel (~> 1.10)
49
- parser (>= 2.7.1.5)
72
+ parser (>= 3.3.0.2)
50
73
  rainbow (>= 2.2.2, < 4.0)
51
- regexp_parser (>= 1.8)
52
- rexml
53
- rubocop-ast (>= 1.1.1)
74
+ regexp_parser (>= 2.9.3, < 3.0)
75
+ rubocop-ast (>= 1.45.1, < 2.0)
54
76
  ruby-progressbar (~> 1.7)
55
- unicode-display_width (>= 1.4.0, < 2.0)
56
- rubocop-ast (1.1.1)
57
- parser (>= 2.7.1.5)
58
- ruby-progressbar (1.10.1)
59
- sqlite3 (1.4.2)
60
- thread_safe (0.3.6)
61
- tzinfo (1.2.7)
62
- thread_safe (~> 0.1)
63
- unicode-display_width (1.7.0)
64
- zeitwerk (2.4.0)
77
+ unicode-display_width (>= 2.4.0, < 4.0)
78
+ rubocop-ast (1.45.1)
79
+ parser (>= 3.3.7.2)
80
+ prism (~> 1.4)
81
+ ruby-progressbar (1.13.0)
82
+ securerandom (0.4.1)
83
+ sqlite3 (2.7.0)
84
+ mini_portile2 (~> 2.8.0)
85
+ sqlite3 (2.7.0-arm64-darwin)
86
+ timeout (0.4.3)
87
+ tzinfo (2.0.6)
88
+ concurrent-ruby (~> 1.0)
89
+ unicode-display_width (3.1.4)
90
+ unicode-emoji (~> 4.0, >= 4.0.4)
91
+ unicode-emoji (4.0.4)
92
+ uri (1.0.3)
65
93
 
66
94
  PLATFORMS
67
- ruby
95
+ arm64-darwin-25
96
+ x84_64-linux
68
97
 
69
98
  DEPENDENCIES
70
99
  identifiable!
@@ -74,4 +103,4 @@ DEPENDENCIES
74
103
  sqlite3
75
104
 
76
105
  BUNDLED WITH
77
- 2.1.4
106
+ 2.4.1
data/README.md CHANGED
@@ -13,10 +13,10 @@ Identifiable makes it really simple to generate and use random public-facing IDs
13
13
 
14
14
  ```ruby
15
15
  # Before:
16
- orders_url(id: @order.id) # → https://example.app/orders/14
16
+ orders_url(@order) # → https://example.app/orders/14
17
17
 
18
18
  # After:
19
- orders_url(id: @order.public_id) # → https://example.app/orders/87133275
19
+ orders_url(@order) # → https://example.app/orders/87133275
20
20
  ```
21
21
 
22
22
  ## Installation
@@ -72,7 +72,7 @@ While Identifiable strives to have useful defaults, you may want to customize yo
72
72
 
73
73
  ### Different public ID styles
74
74
 
75
- By default, Identifiable will generate numeric public IDs, with each character between 0 and 9, but it can also generate alphanumeric public IDs and UUID public ids. To chose your public ID style, simply pass it in as a parameter to `identifiable` on your model.
75
+ By default, Identifiable will generate numeric public IDs, with each character between 0 and 9, but it can also generate alphanumeric public IDs and UUID public IDs. To choose your public ID style, simply pass it in as a parameter to `identifiable` on your model.
76
76
 
77
77
  ```ruby
78
78
  class Order < ApplicationRecord
@@ -112,14 +112,47 @@ end
112
112
 
113
113
  The `length` parameter is ignored if you're using `style: :uuid`, because UUIDs already have a fixed length. The `length` parameter also needs be an Integer, and can't be less than `4` or greater than `128`. If any of these constraints are broken, Identifiable will raise an error letting you know.
114
114
 
115
+ ## Configuration
116
+
117
+ By default, Identifiable overrides Rails' `to_key` and `to_param` methods so that your URLs and DOM IDs will use your public IDs instead of your database IDs.
118
+
119
+ This can break other gems that rely on the default behavior of Rails' `to_key` and `to_param` methods, like devise! You can configure Identifiable to not override these methods if you'd like:
120
+
121
+ ```ruby
122
+ # In config/initializers/identifiable.rb
123
+ Identifiable.configure do |config|
124
+ config.overwrite_to_key = false
125
+ config.overwrite_to_param = false
126
+ end
127
+ ```
128
+
129
+ The `overwrite_to_key` option controls whether Rails helpers like `dom_id` use your public ID or your database ID. The default value is `true`.
130
+
131
+ The `overwrite_to_param` option controls whether URL helpers use your public ID or your database ID in routes. The default value is `true`.
132
+
133
+ If you disable both options, your application will behave like this:
134
+
135
+ ```ruby
136
+ @order = Order.last
137
+ @order.id # => 14
138
+ @order.public_id # => "87133275"
139
+ orders_url(@order) # => https://example.app/orders/14
140
+
141
+ # But you can still create URLs using the public ID
142
+ orders_url(@order.public_id) # => https://example.app/orders/87133275
143
+ ```
144
+
145
+ ## Alternatives
146
+
147
+ I built Identifiable because I never could quite get the other gems that do similar things quite the way that I liked them. You might have the same experience with Identifiable, so if you try Identifiable and find that it's not quite to your tastes, try out some of these alternatives:
148
+
149
+ * [**Hashid Rails**](https://github.com/jcypret/hashid-rails) uses [hashids](http://hashids.org/ruby) to seamlessly create hex strings for your primary keys. It's nice because it doesn't require an extra column in your database, but it's limited in what it can do.
150
+ * [**Public UID**](https://github.com/equivalent/public_uid) is a real power-users public ID gem, and until I made this it was the main way I would build public ID features into the apps I was working on, but I found it too heavy for what I wanted 90% of the time, which is why Identifiable is customizable, but not _too_ customizable. If you find Identifiable isn't customizable or powerful enough for your needs, give Public UID a go!
151
+
115
152
  ## Contributing
116
153
 
117
- Bug reports and pull requests are welcome on [GitHub](https://github.com/tpritc/identifiable). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/tpritc/identifiable/blob/main/CODE_OF_CONDUCT.md).
154
+ Bug reports and pull requests are welcome on [GitHub](https://github.com/tpritc/identifiable). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/tpritc/identifiable/blob/main/CODE_OF_CONDUCT.md) while interacting in the project's codebases, issue trackers, chat rooms, and mailing lists.
118
155
 
119
156
  ## License
120
157
 
121
158
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). If you or your organization need a custom, commercial license for any reason, [send me an email](mailto:hi@tpritc.com) and I'll be happy to set something up for you.
122
-
123
- ## Code of Conduct
124
-
125
- Everyone interacting in the Identifiable project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/tpritc/identifiable/blob/main/CODE_OF_CONDUCT.md).
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'bundler/gem_tasks'
4
- require 'rspec/core/rake_task'
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
5
 
6
6
  RSpec::Core::RakeTask.new(:spec)
7
7
 
data/bin/console CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'bundler/setup'
5
- require 'identifiable'
4
+ require "bundler/setup"
5
+ require "identifiable"
6
6
 
7
7
  # You can add fixtures and/or initialization code here to make experimenting
8
8
  # with your gem easier. You can also use a different console, if you like.
@@ -11,5 +11,5 @@ require 'identifiable'
11
11
  # require "pry"
12
12
  # Pry.start
13
13
 
14
- require 'irb'
14
+ require "irb"
15
15
  IRB.start(__FILE__)
data/bin/rspec ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rspec' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("bundle", __dir__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rspec-core", "rspec")
data/bin/rubocop ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rubocop' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
+
13
+ bundle_binstub = File.expand_path("bundle", __dir__)
14
+
15
+ if File.file?(bundle_binstub)
16
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
+ load(bundle_binstub)
18
+ else
19
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
+ end
22
+ end
23
+
24
+ require "rubygems"
25
+ require "bundler/setup"
26
+
27
+ load Gem.bin_path("rubocop", "rubocop")
data/identifiable.gemspec CHANGED
@@ -1,30 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'lib/identifiable/version'
3
+ require_relative "lib/identifiable/version"
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.version = Identifiable::VERSION
7
- spec.name = 'identifiable'
8
- spec.authors = ['Tom Pritchard']
9
- spec.email = ['hi@tpritc.com']
7
+ spec.name = "identifiable"
8
+ spec.authors = ["Tom Pritchard"]
9
+ spec.email = ["tom@tpritc.com"]
10
10
 
11
- spec.summary = 'A quick and easy way to add random, customizable, public-facing IDs to your models.'
12
- spec.homepage = 'https://github.com/tpritc/identifiable'
13
- spec.license = 'MIT'
14
- spec.required_ruby_version = '>= 2.5.0'
11
+ spec.summary = "A quick and easy way to add random, customizable, public-facing IDs to your models."
12
+ spec.homepage = "https://github.com/tpritc/identifiable"
13
+ spec.license = "MIT"
14
+ spec.required_ruby_version = ">= 3.2.0"
15
15
 
16
16
  # Specify which files should be added to the gem when it is released.
17
17
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
18
18
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
19
19
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
20
  end
21
- spec.bindir = 'exe'
21
+ spec.bindir = "exe"
22
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
- spec.require_paths = ['lib']
23
+ spec.require_paths = ["lib"]
24
24
 
25
- spec.add_dependency 'activerecord', '> 4.2'
26
- spec.add_development_dependency 'rake', '~> 12.0'
27
- spec.add_development_dependency 'rspec', '~> 3.0'
28
- spec.add_development_dependency 'rubocop', '~> 1.3'
29
- spec.add_development_dependency 'sqlite3'
25
+ spec.add_dependency "activerecord", "> 7"
26
+ spec.add_development_dependency "rake", "~> 12.0"
27
+ spec.add_development_dependency "rspec", "~> 3.0"
28
+ spec.add_development_dependency "rubocop", "~> 1.3"
29
+ spec.add_development_dependency "sqlite3"
30
+ spec.metadata["rubygems_mfa_required"] = "true"
30
31
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Identifiable
4
+ class Configuration
5
+ attr_accessor :overwrite_to_key, :overwrite_to_param
6
+
7
+ def initialize
8
+ @overwrite_to_key = true
9
+ @overwrite_to_param = true
10
+ end
11
+ end
12
+ end
@@ -4,7 +4,7 @@ module Identifiable
4
4
  module Errors
5
5
  class ColumnMustBeASymbolError < StandardError
6
6
  def initialize(column_value)
7
- column_value_string = column_value.to_s || 'nil'
7
+ column_value_string = column_value.to_s
8
8
  column_value_class = column_value.class.to_s
9
9
  super("The identifiable's column must be a symbol. You passed in #{column_value_string}, which was a #{column_value_class}.")
10
10
  end
@@ -12,51 +12,51 @@ module Identifiable
12
12
 
13
13
  class ColumnCannotBeIdError < StandardError
14
14
  def initialize
15
- super('The identifiable\'s column cannot be :id, since that\'s your primary key. You should create another index column in your table with a name like :public_id.')
15
+ super("The identifiable's column cannot be :id, since that's your primary key. You should create another index column in your table with a name like :public_id.")
16
16
  end
17
17
  end
18
18
 
19
19
  class ColumnMustExistInTheTableError < StandardError
20
20
  def initialize(column_value, valid_columns:)
21
- column_value_string = column_value.to_s || 'nil'
21
+ column_value_string = column_value.to_s
22
22
  super("The identifiable's column must exist on the table for this model. You passed in #{column_value_string}, but the valid columns are: #{valid_columns}")
23
23
  end
24
24
  end
25
25
 
26
26
  class StyleMustBeAValidStyleError < StandardError
27
27
  def initialize(style_value)
28
- style_value_string = style_value.to_s || 'nil'
29
- super("The identifiable\'s style must be a valid stylist. You passed in #{style_value_string}, but the valid options are: #{Identifiable::Stylist::VALID_STYLES}")
28
+ style_value_string = style_value.to_s
29
+ super("The identifiable's style must be a valid stylist. You passed in #{style_value_string}, but the valid options are: #{Identifiable::Stylist::VALID_STYLES}")
30
30
  end
31
31
  end
32
32
 
33
33
  class LengthMustBeAnIntegerError < StandardError
34
34
  def initialize
35
- super('The identifiable\'s length must be an Integer.')
35
+ super("The identifiable's length must be an Integer.")
36
36
  end
37
37
  end
38
38
 
39
39
  class LengthIsTooShortError < StandardError
40
40
  def initialize
41
- super('The identifiable\'s length must be at least 4.')
41
+ super("The identifiable's length must be at least 4.")
42
42
  end
43
43
  end
44
44
 
45
45
  class LengthIsTooLongError < StandardError
46
46
  def initialize
47
- super('The identifiable\'s length cannot be more than 128.')
47
+ super("The identifiable's length cannot be more than 128.")
48
48
  end
49
49
  end
50
50
 
51
51
  class LengthMustBeNilIfStyleIsUuidError < StandardError
52
52
  def initialize
53
- super('The identifiable\'s length cannot be set if you\'re using the :uuid style, because UUIDs have a fixed length. You should remove the length parameter.')
53
+ super("The identifiable's length cannot be set if you're using the :uuid style, because UUIDs have a fixed length. You should remove the length parameter.")
54
54
  end
55
55
  end
56
56
 
57
57
  class RanOutOfAttemptsToSetPublicIdError < StandardError
58
58
  def initialize
59
- super('We tried 100 times to find an unused public ID, but we could not find one. You should increase the length parameter of the public ID.')
59
+ super("We tried 100 times to find an unused public ID, but we could not find one. You should increase the length parameter of the public ID.")
60
60
  end
61
61
  end
62
62
  end
@@ -25,7 +25,7 @@ module Identifiable
25
25
  end
26
26
 
27
27
  def find_by_public_id(public_id)
28
- where(Hash[identifiable_column, public_id]).first
28
+ where({ identifiable_column => public_id }).first
29
29
  end
30
30
 
31
31
  def find_by_public_id!(public_id)
@@ -54,11 +54,17 @@ module Identifiable
54
54
  # The column parameter must be in the model's table, so check that the
55
55
  # column corresponds to a column in the model's table, and raise an error
56
56
  # if it is not.
57
+ #
58
+ # We suppress ActiveRecord::StatmentInvalid errors just in case the table
59
+ # does not exist yet.
60
+ # rubocop:disable Lint/SuppressedException
57
61
  def _identifiable_validate_column_must_be_in_the_table
58
62
  return if column_names.include? @identifiable_column.to_s
59
63
 
60
64
  raise Identifiable::Errors::ColumnMustExistInTheTableError.new(@identifiable_column, valid_columns: column_names)
65
+ rescue ActiveRecord::StatementInvalid
61
66
  end
67
+ # rubocop:enable Lint/SuppressedException
62
68
 
63
69
  # We can only use valid styles, so check that the style parameter is a
64
70
  # valid style, and raise an error if it is not.
@@ -114,5 +120,23 @@ module Identifiable
114
120
  # If we got this far, we've got a new valid public ID, time to set it!
115
121
  self[self.class.identifiable_column] = new_public_id
116
122
  end
123
+
124
+ # By overriding ActiveRecord's `#to_key`, this means that Rails' helpers,
125
+ # such as `dom_id` will use the public ID instead of the regular ID when
126
+ # identifying the record.
127
+ def to_key
128
+ return super unless Identifiable.configuration.overwrite_to_key
129
+
130
+ [self[self.class.identifiable_column]]
131
+ end
132
+
133
+ # By overriding ActiveRecord's `#to_param`, this means that Rails' helpers,
134
+ # such as the `link_to` helpers will default to using the public ID
135
+ # instead of the regular ID when identifying the record.
136
+ def to_param
137
+ return super unless Identifiable.configuration.overwrite_to_param
138
+
139
+ self[self.class.identifiable_column]
140
+ end
117
141
  end
118
142
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Identifiable
4
- VERSION = '0.1.0'
4
+ VERSION = "1.0.0"
5
5
  end
data/lib/identifiable.rb CHANGED
@@ -3,15 +3,26 @@
3
3
  module Identifiable
4
4
  module Stylists
5
5
  end
6
+
7
+ class << self
8
+ def configuration
9
+ @configuration ||= Configuration.new
10
+ end
11
+
12
+ def configure
13
+ yield(configuration)
14
+ end
15
+ end
6
16
  end
7
17
 
8
- require 'active_record'
9
- require 'identifiable/stylist'
10
- require 'identifiable/stylists/alphanumeric'
11
- require 'identifiable/stylists/numeric'
12
- require 'identifiable/stylists/uuid'
13
- require 'identifiable/errors'
14
- require 'identifiable/model'
15
- require 'identifiable/version'
18
+ require "active_record"
19
+ require "identifiable/configuration"
20
+ require "identifiable/stylist"
21
+ require "identifiable/stylists/alphanumeric"
22
+ require "identifiable/stylists/numeric"
23
+ require "identifiable/stylists/uuid"
24
+ require "identifiable/errors"
25
+ require "identifiable/model"
26
+ require "identifiable/version"
16
27
 
17
28
  ActiveRecord::Base.include Identifiable::Model
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: identifiable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Pritchard
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-11-15 00:00:00.000000000 Z
11
+ date: 2025-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">"
18
18
  - !ruby/object:Gem::Version
19
- version: '4.2'
19
+ version: '7'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">"
25
25
  - !ruby/object:Gem::Version
26
- version: '4.2'
26
+ version: '7'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -82,7 +82,7 @@ dependencies:
82
82
  version: '0'
83
83
  description:
84
84
  email:
85
- - hi@tpritc.com
85
+ - tom@tpritc.com
86
86
  executables: []
87
87
  extensions: []
88
88
  extra_rdoc_files: []
@@ -92,6 +92,7 @@ files:
92
92
  - ".rspec"
93
93
  - ".rubocop.yml"
94
94
  - ".tool-versions"
95
+ - CHANGELOG.md
95
96
  - CODE_OF_CONDUCT.md
96
97
  - Gemfile
97
98
  - Gemfile.lock
@@ -99,9 +100,12 @@ files:
99
100
  - README.md
100
101
  - Rakefile
101
102
  - bin/console
103
+ - bin/rspec
104
+ - bin/rubocop
102
105
  - bin/setup
103
106
  - identifiable.gemspec
104
107
  - lib/identifiable.rb
108
+ - lib/identifiable/configuration.rb
105
109
  - lib/identifiable/errors.rb
106
110
  - lib/identifiable/model.rb
107
111
  - lib/identifiable/stylist.rb
@@ -112,7 +116,8 @@ files:
112
116
  homepage: https://github.com/tpritc/identifiable
113
117
  licenses:
114
118
  - MIT
115
- metadata: {}
119
+ metadata:
120
+ rubygems_mfa_required: 'true'
116
121
  post_install_message:
117
122
  rdoc_options: []
118
123
  require_paths:
@@ -121,14 +126,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
121
126
  requirements:
122
127
  - - ">="
123
128
  - !ruby/object:Gem::Version
124
- version: 2.5.0
129
+ version: 3.2.0
125
130
  required_rubygems_version: !ruby/object:Gem::Requirement
126
131
  requirements:
127
132
  - - ">="
128
133
  - !ruby/object:Gem::Version
129
134
  version: '0'
130
135
  requirements: []
131
- rubygems_version: 3.1.2
136
+ rubygems_version: 3.4.1
132
137
  signing_key:
133
138
  specification_version: 4
134
139
  summary: A quick and easy way to add random, customizable, public-facing IDs to your