hashid-rails 0.7.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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.