Skip to content

Commit 6b69ab1

Browse files
committed
Add configuration options to control to_key and to_param overrides
This allows users to disable Identifiable's overriding of Rails' to_key and to_param methods, which can break compatibility with other gems like Devise. Both options default to true to maintain backward compatibility.
1 parent e222639 commit 6b69ab1

File tree

7 files changed

+375
-9
lines changed

7 files changed

+375
-9
lines changed

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,36 @@ end
112112

113113
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.
114114

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+
115145
## Alternatives
116146

117147
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:

lib/identifiable.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,20 @@
33
module Identifiable
44
module Stylists
55
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
616
end
717

818
require "active_record"
19+
require "identifiable/configuration"
920
require "identifiable/stylist"
1021
require "identifiable/stylists/alphanumeric"
1122
require "identifiable/stylists/numeric"

lib/identifiable/configuration.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

lib/identifiable/model.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,17 @@ def set_public_id!
125125
# such as `dom_id` will use the public ID instead of the regular ID when
126126
# identifying the record.
127127
def to_key
128+
return super unless Identifiable.configuration.overwrite_to_key
129+
128130
[self[self.class.identifiable_column]]
129131
end
130132

131133
# By overriding ActiveRecord's `#to_param`, this means that Rails' helpers,
132134
# such as the `link_to` helpers will default to using the public ID
133135
# instead of the regular ID when identifying the record.
134136
def to_param
137+
return super unless Identifiable.configuration.overwrite_to_param
138+
135139
self[self.class.identifiable_column]
136140
end
137141
end

spec/configuration_spec.rb

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe Identifiable::Configuration do
4+
let(:config) { described_class.new }
5+
6+
describe "#initialize" do
7+
it "sets default values" do
8+
expect(config.overwrite_to_key).to be_truthy
9+
expect(config.overwrite_to_param).to be_truthy
10+
end
11+
end
12+
13+
describe "#overwrite_to_key" do
14+
it "can be read" do
15+
expect(config.overwrite_to_key).to be_truthy
16+
end
17+
18+
it "can be set to false" do
19+
config.overwrite_to_key = false
20+
expect(config.overwrite_to_key).to be_falsey
21+
end
22+
23+
it "can be set to true" do
24+
config.overwrite_to_key = false
25+
config.overwrite_to_key = true
26+
expect(config.overwrite_to_key).to be_truthy
27+
end
28+
end
29+
30+
describe "#overwrite_to_param" do
31+
it "can be read" do
32+
expect(config.overwrite_to_param).to be_truthy
33+
end
34+
35+
it "can be set to false" do
36+
config.overwrite_to_param = false
37+
expect(config.overwrite_to_param).to be_falsey
38+
end
39+
40+
it "can be set to true" do
41+
config.overwrite_to_param = false
42+
config.overwrite_to_param = true
43+
expect(config.overwrite_to_param).to be_truthy
44+
end
45+
end
46+
end

spec/identifiable_spec.rb

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,84 @@
44
it "has a version number" do
55
expect(Identifiable::VERSION).not_to be nil
66
end
7+
8+
describe ".configure" do
9+
after do
10+
# Reset configuration after each test
11+
Identifiable.configure do |config|
12+
config.overwrite_to_key = true
13+
config.overwrite_to_param = true
14+
end
15+
end
16+
17+
it "yields a configuration object" do
18+
expect { |b| Identifiable.configure(&b) }.to yield_with_args(Identifiable.configuration)
19+
end
20+
21+
it "allows configuring overwrite_to_key" do
22+
Identifiable.configure do |config|
23+
config.overwrite_to_key = false
24+
end
25+
26+
expect(Identifiable.configuration.overwrite_to_key).to be_falsey
27+
end
28+
29+
it "allows configuring overwrite_to_param" do
30+
Identifiable.configure do |config|
31+
config.overwrite_to_param = false
32+
end
33+
34+
expect(Identifiable.configuration.overwrite_to_param).to be_falsey
35+
end
36+
37+
it "allows configuring multiple options at once" do
38+
Identifiable.configure do |config|
39+
config.overwrite_to_key = false
40+
config.overwrite_to_param = false
41+
end
42+
43+
expect(Identifiable.configuration.overwrite_to_key).to be_falsey
44+
expect(Identifiable.configuration.overwrite_to_param).to be_falsey
45+
end
46+
end
47+
48+
describe ".configuration" do
49+
after do
50+
# Reset configuration after each test
51+
Identifiable.configure do |config|
52+
config.overwrite_to_key = true
53+
config.overwrite_to_param = true
54+
end
55+
end
56+
57+
it "returns the same configuration object on multiple calls" do
58+
config1 = Identifiable.configuration
59+
config2 = Identifiable.configuration
60+
expect(config1).to be(config2)
61+
end
62+
63+
it "returns a configuration object that responds to configuration methods" do
64+
config = Identifiable.configuration
65+
expect(config).to respond_to(:overwrite_to_key)
66+
expect(config).to respond_to(:overwrite_to_param)
67+
expect(config).to respond_to(:overwrite_to_key=)
68+
expect(config).to respond_to(:overwrite_to_param=)
69+
end
70+
71+
it "maintains configuration changes across calls" do
72+
Identifiable.configure do |config|
73+
config.overwrite_to_key = false
74+
config.overwrite_to_param = false
75+
end
76+
77+
config = Identifiable.configuration
78+
expect(config.overwrite_to_key).to be_falsey
79+
expect(config.overwrite_to_param).to be_falsey
80+
81+
# Should persist
82+
config_again = Identifiable.configuration
83+
expect(config_again.overwrite_to_key).to be_falsey
84+
expect(config_again.overwrite_to_param).to be_falsey
85+
end
86+
end
787
end

0 commit comments

Comments
 (0)