hashid-rails 0.7.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
  SHA1:
3
- metadata.gz: ff291b0a3ecd103ccc6af6971f85636cd06e0c3f
4
- data.tar.gz: 99cddc687a989d82845d7d928a26d5e8f19b872b
3
+ metadata.gz: 452d76b6a75d881163fd3f8a5216b458ac1d96fd
4
+ data.tar.gz: 54201c5c82b115e15c207c7d0c57a8176cb490e7
5
5
  SHA512:
6
- metadata.gz: 2ba2b51cab4a714ba1d5020095e742bac5569a2d2316282af29e5733d97a0cd723b47009368e08b426fe10378e09824a8448446487dfad0e95bd08be48392dd4
7
- data.tar.gz: 851fd6b4a1f66a5baf332ec942852c2811e635888f79aefd7b438e36c0c6622b7f24cb49a547a2000f3acb77e1f7e20846a052f1ec8d7893512f78db88f9a0dc
6
+ metadata.gz: b604b9ed6b7550f16445847d1f2f93de1af252cc70c1a72c76a2709cb803eda02598e8b0d2102705a109911dcc18f4abc916f025c293102da700303c24756233
7
+ data.tar.gz: 679db7739b37d2d705e9b1745e78abd881682982c8d5fc591d6de159cc8641e3e2b10ace09e2084c0e7d3332eb2581747e810f72bb5208e697fc9cfb59ddf5f5
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ /.ruby-version
data/.rubocop.yml CHANGED
@@ -4,7 +4,7 @@ Style/IndentArray:
4
4
  EnforcedStyle: consistent
5
5
  Style/Documentation:
6
6
  Enabled: false
7
- Style/BlockLength:
7
+ Metrics/BlockLength:
8
8
  Exclude:
9
9
  - "*.gemspec"
10
10
  - "spec/**/*.rb"
data/.travis.yml CHANGED
@@ -1,8 +1,9 @@
1
1
  language: ruby
2
2
  cache: bundler
3
3
  rvm:
4
- - 2.2.5
5
- - 2.3.1
4
+ - 2.3.0
6
5
  addons:
7
6
  code_climate:
8
- repo_token: 561da3bbc224e5217ceba7b8f99d24190d7d65b221570db6cf0949381e4c0c27
7
+ repo_token: 37aee70bb2e818f3bf4d2af88ea4a4355393901ba98b3876c244d42ed20fdbe1
8
+ after_success:
9
+ - bundle exec codeclimate-test-reporter
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.0 (2017-04-29)
4
+ - Sign hashids to prevent accidentally decoded regular ids
5
+ - Require explicitly including Hashid::Rails in models
6
+ - Improve support for model associations
7
+ - Rename config variables to better match hashids project
8
+ - Improve overall test coverage
9
+
3
10
  ## 0.7.0 (2017-02-15)
4
11
  - Add configuration option to disable overriding default `find` (#22).
5
12
 
data/README.md CHANGED
@@ -32,56 +32,86 @@ $ gem install hashid-rails
32
32
 
33
33
  ## Basic Usage
34
34
 
35
- Just use `Model#find` passing in the hashid instead of the model id.
35
+ 1. Include Hashid Rails in the ActiveRecord model you'd like to enable hashids.
36
+
37
+ ```ruby
38
+ class Model < ActiveRecord::Base
39
+ include Hashid::Rails
40
+ end
41
+ ```
42
+
43
+ 2. Continue using `Model#find` passing in either a hashid or regular 'ol id.
36
44
 
37
45
  ```ruby
38
46
  @person = Person.find(params[:hashid])
39
47
  ```
40
48
 
49
+ ## Get hashid of model
50
+
51
+ You can access the hashid of any model using the `hashid` method.
52
+
53
+ ```ruby
54
+ model = Model.find(params[:hashid])
55
+ #=> <Model>
56
+ model.hashid
57
+ #=> "yLA6m0oM"
58
+ ```
59
+
60
+ Additionally, the `to_param` method is overriden to use hashid instead of id.
61
+ This means methods that take advantage of implicit ID will automatically work
62
+ with hashids.
63
+
64
+ ```erb
65
+ Passing a hashid model to `link_to`…
66
+ <%= link_to "Model", model %>
67
+
68
+ will use `hashid` instead of `id`.
69
+ <a href="/models/yLA6m0oM">Model</a>
70
+ ```
71
+
41
72
  ## Alternative Usage
42
73
 
43
74
  You can use the `Model#find_by_hashid` method to find a record without falling
44
- back on the standard `find` method. This can be useful in cases where the hashid
45
- might be misinterpreted by the `find` method, such as using a hashid containing
46
- only numbers that could be both interpreted as either an id and or a hashid.
75
+ back on the standard `find` method.
76
+
47
77
 
48
78
  ```ruby
49
79
  # When a record is found, it returns the record.
50
80
  @person = Person.find_by_hashid(params[:hashid])
81
+ #=> <Person>
82
+
83
+ # When no record, it returns nil
84
+ @person = Person.find_by_hashid(params[:hashid])
85
+ #=> nil
51
86
 
52
- # When no record, is found it raises an exception.
53
- ActiveRecord::RecordNotFound
87
+ # A bang (!) version is also available and raises an exception when not found.
88
+ @person = Person.find_by_hashid!(params[:hashid])
89
+ #=> ActiveRecord::RecordNotFound
54
90
  ```
55
91
 
56
- ## Configuration
92
+ ## Configuration (optional)
57
93
 
58
- To customize the Hashids seed and ensure that another user of the gem cannot
59
- easily reverse engineer your ids, create an initializer and:
94
+ You can add an initializer for Hashid::Rails to customize the options passed to
95
+ the Hashids gem. This is completely optional. The configuration below shows the
96
+ default options.
60
97
 
61
98
  ```ruby
62
99
  Hashid::Rails.configure do |config|
63
- config.secret = 'my secret'
64
- config.length = 6
65
- # config.alphabet is optional, hashids provides a default
66
- # alphabet that consists of all characters [a-zA-Z0-9]
67
- config.alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
68
-
69
- # If your alphbet contains any numerals [0-9], then we recommend diabling the find method
70
- #config.disable_find = true
71
- end
72
- ```
73
- ### Disable Find Method
100
+ # The salt to use for generating hashid. Prepended with table name.
101
+ config.salt = ""
74
102
 
75
- If your alphabet includes numerals (0-9) and if the ids in your database are the same length as your hashes, then there could be valid
76
- hashids that are identical to valid ids. This ambiguity could lead the `find` method to behave unpredictably. Since `find` accepts both
77
- hashids and ids, an input argument that is potentially both a valid hashid and id, will cause `find` to treat the argument as a hashid
78
- in some cases, and as an id in others. This unpredictably is usually not desired and can lead to subtle bugs appearing at runtime
103
+ # The minimum length of generated hashids
104
+ config.min_hash_length = 6
79
105
 
80
- In order to avoid this problem, users can add `config.disable_find = true` to their initializer. This will disable the hashid
81
- functionality of the `find` method and force `find` to only accept normal (unhashed) ids. Under this configuration, programmer
82
- will need to use the `find_by_hashid` method when desiring to explicitly search by hashid.
106
+ # The alphabet to use for generating hashids
107
+ config.alphabet = "abcdefghijklmnopqrstuvwxyz" \
108
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
109
+ "1234567890"
83
110
 
84
- It is recommended that `config.disable_find = true` be set when the alphabet contains any numerals.
111
+ # Whether to override the `find` method
112
+ config.override_find = true
113
+ end
114
+ ```
85
115
 
86
116
  ## Development
87
117
 
data/hashid-rails.gemspec CHANGED
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
30
30
  spec.add_development_dependency "bundler"
31
31
  spec.add_development_dependency "rake"
32
32
  spec.add_development_dependency "rspec", "~> 3.4.0"
33
- spec.add_development_dependency "codeclimate-test-reporter"
33
+ spec.add_development_dependency "codeclimate-test-reporter", "~> 1.0.0"
34
34
  spec.add_development_dependency "sqlite3"
35
35
  spec.add_development_dependency "rubocop"
36
36
  spec.add_development_dependency "byebug"
data/lib/hashid/rails.rb CHANGED
@@ -5,6 +5,14 @@ require "active_record"
5
5
 
6
6
  module Hashid
7
7
  module Rails
8
+ # Arbitrary value to verify hashid
9
+ # https://en.wikipedia.org/wiki/Phrases_from_The_Hitchhiker%27s_Guide_to_the_Galaxy#On_the_Internet_and_in_software
10
+ HASHID_TOKEN = 42
11
+
12
+ def self.included(base)
13
+ base.extend ClassMethods
14
+ end
15
+
8
16
  # Get configuration or load defaults
9
17
  def self.configuration
10
18
  @configuration ||= Configuration.new
@@ -20,31 +28,12 @@ module Hashid
20
28
  @configuration = Configuration.new
21
29
  end
22
30
 
23
- def self.included(base)
24
- base.extend ClassMethods
25
- end
26
-
27
- def encoded_id
31
+ def hashid
28
32
  self.class.encode_id(id)
29
33
  end
30
-
31
- def to_param
32
- encoded_id
33
- end
34
- alias hashid to_param
34
+ alias to_param hashid
35
35
 
36
36
  module ClassMethods
37
- def hashids
38
- secret = Hashid::Rails.configuration.secret
39
- length = Hashid::Rails.configuration.length
40
- alphabet = Hashid::Rails.configuration.alphabet
41
-
42
- arguments = ["#{table_name}#{secret}", length]
43
- arguments << alphabet if alphabet.present?
44
-
45
- Hashids.new(*arguments)
46
- end
47
-
48
37
  def encode_id(ids)
49
38
  if ids.is_a?(Array)
50
39
  ids.map { |id| hashid_encode(id) }
@@ -55,40 +44,52 @@ module Hashid
55
44
 
56
45
  def decode_id(ids)
57
46
  if ids.is_a?(Array)
58
- decoded_ids = ids.map { |id| hashid_decode(id) }
59
- decoded_ids.any? ? decoded_ids : nil
47
+ ids.map { |id| hashid_decode(id) }
60
48
  else
61
49
  hashid_decode(ids)
62
50
  end
63
51
  end
64
52
 
65
- def find(hashid)
66
- if model_reload? || Hashid::Rails.configuration.disable_find
67
- super(hashid)
53
+ def find(*ids)
54
+ expects_array = ids.first.is_a?(Array)
55
+
56
+ uniq_ids = ids.flatten.compact.uniq
57
+ uniq_ids = uniq_ids.first unless expects_array || uniq_ids.size > 1
58
+
59
+ if Hashid::Rails.configuration.override_find
60
+ super(decode_id(uniq_ids))
68
61
  else
69
- super(decode_id(hashid) || hashid)
62
+ super
70
63
  end
71
64
  end
72
65
 
73
66
  def find_by_hashid(hashid)
74
- find_by!(id: hashid_decode(hashid))
67
+ find_by(id: decode_id(hashid))
68
+ end
69
+
70
+ def find_by_hashid!(hashid)
71
+ find_by!(id: decode_id(hashid))
75
72
  end
76
73
 
77
74
  private
78
75
 
79
- def model_reload?
80
- caller.any? { |s| s =~ %r{ active_record/persistence.*reload } }
76
+ def hashids
77
+ Hashids.new(*Hashid::Rails.configuration.for_table(table_name))
78
+ end
79
+
80
+ def hashid_encode(id)
81
+ hashids.encode(HASHID_TOKEN, id)
81
82
  end
82
83
 
83
84
  def hashid_decode(id)
84
- hashids.decode(id.to_s).first
85
+ decoded_hashid = hashids.decode(id.to_s)
86
+ return id unless valid_hashid?(decoded_hashid)
87
+ decoded_hashid.last
85
88
  end
86
89
 
87
- def hashid_encode(id)
88
- hashids.encode(id)
90
+ def valid_hashid?(decoded_hashid)
91
+ decoded_hashid.size == 2 && decoded_hashid.first == HASHID_TOKEN
89
92
  end
90
93
  end
91
94
  end
92
95
  end
93
-
94
- ActiveRecord::Base.send :include, Hashid::Rails
@@ -1,13 +1,19 @@
1
1
  module Hashid
2
2
  module Rails
3
3
  class Configuration
4
- attr_accessor :secret, :length, :alphabet, :disable_find
4
+ attr_accessor :salt, :min_hash_length, :alphabet, :override_find
5
5
 
6
6
  def initialize
7
- @secret = ""
8
- @length = 6
9
- @alphabet = nil
10
- @disable_find = false
7
+ @salt = ""
8
+ @min_hash_length = 6
9
+ @alphabet = "abcdefghijklmnopqrstuvwxyz" \
10
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
11
+ "1234567890"
12
+ @override_find = true
13
+ end
14
+
15
+ def for_table(table_name)
16
+ ["#{table_name}#{salt}", min_hash_length, alphabet]
11
17
  end
12
18
  end
13
19
  end
@@ -1,5 +1,5 @@
1
1
  module Hashid
2
2
  module Rails
3
- VERSION = "0.7.0".freeze
3
+ VERSION = "1.0.0".freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hashid-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Cypret
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-02-16 00:00:00.000000000 Z
11
+ date: 2017-04-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -56,16 +56,16 @@ dependencies:
56
56
  name: codeclimate-test-reporter
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: 1.0.0
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: 1.0.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: sqlite3
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -183,7 +183,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
183
183
  version: '0'
184
184
  requirements: []
185
185
  rubyforge_project:
186
- rubygems_version: 2.5.1
186
+ rubygems_version: 2.5.2
187
187
  signing_key:
188
188
  specification_version: 4
189
189
  summary: Use Hashids in your Rails app models.