sqids-rails 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: 2806a56ec74df13fa5efa5f6ed2800d792223c7240b65cfad3cb50eff7a02a4b
4
+ data.tar.gz: 9f11f7fc06b94e888187ce01c5983431ae597761157652f9677f5c06e1be35d5
5
+ SHA512:
6
+ metadata.gz: 8b18b3d1ef47868206df30a4f89078464d65254e1494798d7724aade26d3d8a71bf7f15d9353bda313659f4401d246cde365895224713b34b09e092a133e5804
7
+ data.tar.gz: 9f184450853b55deff34b120e16fbacad516806f1c03bc7a8f88655ffb7dde094f0c68afdfaf02a18ef0c9bb20d6d2d1b483ec4e1bc9de2dc3b5654f2e8cc978
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Tony Burns
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,113 @@
1
+ # sqids-rails
2
+
3
+ [Sqids](https://sqids.org) (formerly [Hashids](https://github.com/hashids)) integration for [Ruby on Rails](https://rubyonrails.org).
4
+
5
+ From [sqids-ruby](https://github.com/sqids/sqids-ruby):
6
+
7
+ > [Sqids](https://sqids.org/ruby) _(pronounced "squids")_ is a small library that lets you generate unique IDs from numbers. It's good for link shortening, fast & URL-safe ID generation and decoding back into numbers for quicker database lookups.
8
+ >
9
+ > Features:
10
+ >
11
+ > - Encode multiple numbers - generate short IDs from one or several non-negative numbers
12
+ > - Quick decoding - easily decode IDs back into numbers
13
+ > - Unique IDs - generate unique IDs by shuffling the alphabet once
14
+ > - ID padding - provide minimum length to make IDs more uniform
15
+ > - URL safe - auto-generated IDs do not contain common profanity
16
+ > - Randomized output - Sequential input provides nonconsecutive IDs
17
+ > - Many implementations - Support for 40+ programming languages
18
+
19
+ ## Getting started
20
+
21
+ Run `bundle add sqids-rails` or add this line to your application's `Gemfile`:
22
+
23
+ ```ruby
24
+ gem 'sqids-rails'
25
+ ```
26
+
27
+ And then execute:
28
+
29
+ ```shell
30
+ bundle
31
+ ```
32
+
33
+ ## Usage
34
+
35
+ Add auto-generated sqids columns to your ActiveRecord models with `has_sqid`:
36
+
37
+ ```ruby
38
+ # Schema: users(sqid:string, long_sqid:string)
39
+ class User < ApplicationRecord
40
+ include Sqids::Rails::Model
41
+
42
+ has_sqid
43
+ has_sqid :long_sqid, min_length: 24
44
+ end
45
+
46
+ user = User.new
47
+ user.save
48
+ user.sqid # => "lzNKgEb6ZuaU"
49
+ user.sqid_long # => "4y3SVm9M2aV8Olu6p4zZoGij"
50
+ user.regenerate_sqid
51
+ user.regenerate_long_sqid
52
+ ```
53
+
54
+ `has_sqid` follows the same behavior as ActiveRecord's built-in [has_secure_token](https://api.rubyonrails.org/classes/ActiveRecord/SecureToken/ClassMethods.html#method-i-has_secure_token)
55
+
56
+ Use a custom attribute name (the default is `sqid`):
57
+
58
+ ```ruby
59
+ has_sqid :uid
60
+ ```
61
+
62
+ Enforce a _minimum length_ for generated IDs:
63
+
64
+ ```ruby
65
+ has_sqid min_length: 24
66
+ ```
67
+
68
+ Provide a custom alphabet for generated IDs:
69
+
70
+ ```ruby
71
+ has_sqid alphabet: "FxnXM1kBN6cuhsAvjW3Co7l2RePyY8DwaU04Tzt9fHQrqSVKdpimLGIJOgb5ZE"
72
+ ```
73
+
74
+ Prevent specific words from appearing anywhere in generated IDs:
75
+
76
+ ```ruby
77
+ has_sqid blocklist: Set.new(%w[86Rf07])
78
+ ```
79
+
80
+ ## Roadmap
81
+
82
+ - [x] `has_sqid` for auto-generating Sqid columns
83
+ - [ ] Extensions to [ActiveRecord::FinderMethods](https://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html) and [ActiveRecord::Associations::CollectionProxy](https://api.rubyonrails.org/classes/ActiveRecord/Associations/CollectionProxy.html#method-i-find) to find records with a Sqid-encoded primary key
84
+
85
+ ## Contributing
86
+
87
+ Bug reports and pull requests are welcome on [GitHub](https://github.com/tbhb/sqids-rails). 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/tbhb/sqids-rails/blob/main/CODE_OF_CONDUCT.md).
88
+
89
+ ## Acknowledgements
90
+
91
+ Thanks to Ivan Akimov ([@4kimov](https://github.com/4kimov)) for creating and maintaining Sqids and [sqids-ruby](https://github.com/sqids/sqids-ruby), and Roberto Miranda ([@robertomiranda](https://github.com/robertomiranda)) for `has_secure_token`.
92
+
93
+ ## MIT License
94
+
95
+ Copyright (c) 2024 Anthony Burns
96
+
97
+ Permission is hereby granted, free of charge, to any person obtaining a copy
98
+ of this software and associated documentation files (the "Software"), to deal
99
+ in the Software without restriction, including without limitation the rights
100
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
101
+ copies of the Software, and to permit persons to whom the Software is
102
+ furnished to do so, subject to the following conditions:
103
+
104
+ The above copyright notice and this permission notice shall be included in
105
+ all copies or substantial portions of the Software.
106
+
107
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
108
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
109
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
110
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
111
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
112
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
113
+ THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
File without changes
@@ -0,0 +1,6 @@
1
+ class User < ApplicationRecord
2
+ include Sqids::Rails::Model
3
+
4
+ has_sqid
5
+ has_sqid :long_sqid, min_length: 24
6
+ end
@@ -0,0 +1,9 @@
1
+ class CreateUsers < ActiveRecord::Migration[7.1]
2
+ def change
3
+ create_table :users do |t|
4
+ t.string :sqid
5
+ t.string :long_sqid
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ class Sqids
2
+ module Rails
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,107 @@
1
+ class Sqids
2
+ module Rails
3
+ module Model
4
+ class AlphabetError < StandardError; end
5
+
6
+ class MinimumLengthError < StandardError; end
7
+
8
+ extend ActiveSupport::Concern
9
+
10
+ module ClassMethods
11
+ # Example using #has_sqid:
12
+ #
13
+ # # Schema: User(sqid:string, long_sqid:string)
14
+ # class User < ApplicationRecord
15
+ # include Sqids::Rails::Model
16
+ #
17
+ # has_sqid
18
+ # has_sqid :long_sqid, min_length: 24
19
+ # end
20
+ #
21
+ # user = User.new
22
+ # user.save
23
+ # user.sqid # => "lzNKgEb6ZuaU"
24
+ # user.sqid_long # => "4y3SVm9M2aV8Olu6p4zZoGij"
25
+ # user.regenerate_sqid
26
+ # user.regenerate_long_sqid
27
+ #
28
+ # +SecureRandom.random_number(Sqids.max_value)+ is used to generate the random number to encode.
29
+ #
30
+ # Note that it's still possible to generate a race condition in the database in the same way that
31
+ # {validates_uniqueness_of}[https://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#method-i-validates_uniqueness_of]
32
+ # can. You're encouraged to add a unique index in the database to deal with this even more unlikely scenario.
33
+ #
34
+ # See the {Sqids Ruby}[https://github.com/sqids/sqids-ruby] documentation for more information on the options.
35
+ #
36
+ # === Options
37
+ #
38
+ # [:alphabet]
39
+ # The alphabet to use for encoding. Default is +Sqids::Rails.alphabet+.
40
+ # The minimum alphabet length is 3 characters.
41
+ # The alphabet cannot contain any multibyte characters.
42
+ #
43
+ # [:blocklist]
44
+ # The blocklist to use for encoding. Default is +Sqids::Rails.blocklist+.
45
+ #
46
+ # [:min_length]
47
+ # The minimum length of the generated sqid, from 0-255. Default is +Sqids::Rails.min_length+. Sqids cannot
48
+ # generate IDs up to a certain length, only at least a certain length.
49
+ #
50
+ # [:on]
51
+ # The callback when the value is generated. When called with <tt>on: :initialize</tt>, the value is generated
52
+ # in an <tt>after_initialize</tt> callback, otherwise the value will be used in a <tt>before_</tt> callback.
53
+ # When not specified, +:on+ will use the value of <tt>Sqids::Rails.generate_sqid_on</tt>, which defaults to
54
+ # +:initialize+.
55
+ def has_sqid(
56
+ attribute = :sqid,
57
+ alphabet: Sqids::Rails.alphabet,
58
+ blocklist: Sqids::Rails.blocklist,
59
+ min_length: Sqids::Rails.min_length,
60
+ on: Sqids::Rails.generate_sqid_on
61
+ )
62
+ if alphabet.length < 3
63
+ raise AlphabetError, "Sqid requires an alphabet of at least 3 characters"
64
+ end
65
+
66
+ if alphabet.each_char.any? { |char| char.bytesize > 1 }
67
+ raise AlphabetError, "Sqid alphabet cannot contain multibyte characters"
68
+ end
69
+
70
+ if alphabet.chars.uniq.length != alphabet.length
71
+ raise AlphabetError, "Sqid alphabet must contain unique characters"
72
+ end
73
+
74
+ if min_length < 0 || min_length > 255
75
+ raise MinimumLengthError, "Sqid requires a minimum length between 0 and 255 characters"
76
+ end
77
+
78
+ define_method(:"regenerate_#{attribute}") do
79
+ update!(
80
+ attribute => self.class.generate_unique_sqid(
81
+ alphabet: alphabet, blocklist: blocklist, min_length: min_length
82
+ )
83
+ )
84
+ end
85
+ set_callback(on, (on == :initialize) ? :after : :before) do
86
+ if new_record? && !query_attribute(attribute)
87
+ send(
88
+ :"#{attribute}=",
89
+ self.class.generate_unique_sqid(alphabet: alphabet, blocklist: blocklist, min_length: min_length)
90
+ )
91
+ end
92
+ end
93
+ end
94
+
95
+ def generate_unique_sqid(
96
+ alphabet: Sqids::Rails.alphabet, blocklist: Sqids::Rails.blocklist, min_length: Sqids::Rails.min_length
97
+ )
98
+ @sqids ||= {}
99
+ @sqids[[alphabet, blocklist, min_length]] ||= Sqids.new(
100
+ alphabet: alphabet, blocklist: blocklist, min_length: min_length
101
+ )
102
+ @sqids[[alphabet, blocklist, min_length]].encode([SecureRandom.random_number(Sqids.max_value)])
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,5 @@
1
+ class Sqids
2
+ module Rails
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,23 @@
1
+ require "active_support/core_ext/module/attribute_accessors"
2
+
3
+ require "sqids"
4
+ require "sqids/rails/version"
5
+ require "sqids/rails/engine"
6
+ require "sqids/rails/model"
7
+
8
+ class Sqids
9
+ module Rails
10
+ mattr_accessor :alphabet, default: Sqids::DEFAULT_ALPHABET
11
+ mattr_accessor :blocklist, default: Sqids::DEFAULT_BLOCKLIST
12
+ mattr_accessor :min_length, default: Sqids::DEFAULT_MIN_LENGTH
13
+ mattr_accessor :generate_sqid_on, default: :initialize
14
+
15
+ def self.configure
16
+ yield self
17
+ end
18
+
19
+ def self.sqids
20
+ @sqids ||= Sqids.new(alphabet: alphabet, blocklist: blocklist, min_length: min_length)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1 @@
1
+ require "sqids/rails"
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :sqids_rails do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sqids-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tony Burns
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-07-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 6.1.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.1.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: sqids
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: appraisal
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Short, unique, and human-readable IDs for ActiveRecord models with Sqids.
56
+ email:
57
+ - tony@tonyburns.net
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - LICENSE.txt
63
+ - README.md
64
+ - Rakefile
65
+ - app/assets/config/sqids_rails_manifest.js
66
+ - app/models/user.rb
67
+ - db/migrate/20240705145551_create_users.rb
68
+ - lib/sqids-rails.rb
69
+ - lib/sqids/rails.rb
70
+ - lib/sqids/rails/engine.rb
71
+ - lib/sqids/rails/model.rb
72
+ - lib/sqids/rails/version.rb
73
+ - lib/tasks/sqids/rails_tasks.rake
74
+ homepage: https://github.com/tbhb/sqids-rails
75
+ licenses:
76
+ - MIT
77
+ metadata:
78
+ homepage_uri: https://github.com/tbhb/sqids-rails
79
+ source_code_uri: https://github.com/tbhb/sqids-rails
80
+ changelog_uri: https://github.com/tbhb/sqids-rails/blob/main/sqids-rails/CHANGELOG.md
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '3.1'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements: []
96
+ rubygems_version: 3.5.14
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: Short, unique, and human-readable IDs for ActiveRecord models with Sqids.
100
+ test_files: []