Code Monkey home page Code Monkey logo

hashid-rails's People

Contributors

alexford avatar drakula2k avatar fauxparse avatar jcypret avatar jrasanen avatar mfamilia avatar mzrnsh avatar olliebennett avatar taranda avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

hashid-rails's Issues

Rails own 'form_for' / 'form_with' helper

Hey there,

nice to see hashid turning into its own rails gem. But what about form_for and form_with helpers in Rails? If i want to obscure ID's within URL's it works fine. Using form_for would generate its CLASS and ID automatically by using to_key and reveal the original ID within the DOM. What do you think, is that something that should be addressed?

support for "-" in id

so you can do params like:
def to_param
"#{hashid}-#{title}"
end

anyone else need this?

model.reload uses wrong id when real id happens to match hashid format

ActiveRecord's reload method uses find. When the model's id happens to match the hashid format, the Hashid::Rails.find method 'decodes' the real id and calls super. Super then queries for an id that typically does not exist in the database and can even be too long for an integer column.

The obfuscate_id gem seems to handle this condition by overriding reload (see here)

A spec to reproduce is in a commit here

Why finding if decoding return nil?

Hi there,

When I pass an Hashid that decodes to nil, the find method is still called thus an extra unneeded database query. Is this expected behaviour?

Cheers!

ability to not override to_param

I use hashid on most models, but there are a few models I want to use it without overriding to_param because the particular model is used in many places and I dont have time to test if adding hashid will break all those places. How can I tell hashid not to override to_param?

RecordNotFound with fixtures, when secret is configured

Hi,

When working without any Hashid configuration, things work properly.

After adding an initializer with this:

# config/initializers/hashids.rb
Hashid::Rails.configure do |config|
  config.secret = 'hello'
  # config.length = 8
end

I am getting this error:

ActiveRecord::RecordNotFound: Couldn't find SomeModel with an out of range ID

The call that makes it fail is always a fixtures call, like:

task = tasks :some_task

Changing the secret string, makes it fail for different fixtures, and succeed for previously failing fixtures.

A little byebug session to further illustrate:

[43, 52] in /.../task_policy_test.rb
   46:   test "fotbid change_notification" do
   47:     byebug
=> 48:     refute_permit users(:user), tasks(:patrol), :change_notification?
   49:   end

(byebug) tasks :patrol # fail
*** ActiveRecord::RecordNotFound Exception: Couldn't find Task with an out of range ID

nil

(byebug) Task.find_by subject: 'Patrol the building' # pass
#<Task id: 201007985, subject: "Patrol the building", ...>

Supporting disabling of hashid signing

I am attempting to migrate a production app from v0.7.0 to v1.0.0.

The improvements in 1.0.0 seem very worthwhile and well thought out, and address various other problems - thanks!

The "hashid signing" feature that this gem has implemented (see issue and PR) is causing a totally new set of hashids to be generated.

Would you consider a disable_hashid_signing config option? I appreciate that v 1.0 is not backward-compatible with 0.x but without this option, it seems there is no way to migrate at all?

Another reason to support disabling this feature is that - although useful, and good to enable by default - it's a totally arbitrary solution for the problem, and it prevents compatibility with other hashid tools which would not be encoding using the [HASHID_TOKEN, id] format.

How to encode ID?

This is probably a very silly question. But how do I encode an ID into the HashID?

I've added the initializer with my own seed. But I can't seem to find out how to do this

Consistent between db loads?

More of a question than an issue... I'm just wondering if the database is wiped, is there a way to make the hashes generate the same each time for a given model? Perhaps based on a unique field like a name? I see the salt config but it is more of a global config and only part of the generation picture. Just wondering if there's a way to do that. Thanks!

find fails with array of ids

The default behaviour of Model#find is to take a single id and returns a single element or take
an array of ids and returns an array of elements (though duplicate ids in the array are not in the result).

Expected behaviour:

using the code below will work with hashid-rails installed

Model.find([1,2])
=> [#<Model id: 1>,  #<Model id: 2>]

Actual Result

Get an error

ActiveRecord::RecordNotFound: Couldn't find Role without an ID
        from /Users/drb/.gem/ruby/2.3.0/gems/activerecord-5.0.0.1/lib/active_record/relation/finder_methods.rb:454:in `find_with_ids'
        from /Users/drb/.gem/ruby/2.3.0/gems/activerecord-5.0.0.1/lib/active_record/relation/finder_methods.rb:66:in `find'
        from /Users/drb/.gem/ruby/2.3.0/gems/activerecord-5.0.0.1/lib/active_record/querying.rb:3:in `find'
        from /Users/drb/.gem/ruby/2.3.0/gems/activerecord-5.0.0.1/lib/active_record/core.rb:151:in `find'
        from /Users/drb/.gem/ruby/2.3.0/gems/hashid-rails-0.5.0/lib/hashid/rails.rb:66:in `find'
        from (irb):1
        from /Users/drb/.gem/ruby/2.3.0/gems/railties-5.0.0.1/lib/rails/commands/console.rb:65:in `start'
        from /Users/drb/.gem/ruby/2.3.0/gems/railties-5.0.0.1/lib/rails/commands/console_helper.rb:9:in `start'
        from /Users/drb/.gem/ruby/2.3.0/gems/railties-5.0.0.1/lib/rails/commands/commands_tasks.rb:78:in `console'
        from /Users/drb/.gem/ruby/2.3.0/gems/railties-5.0.0.1/lib/rails/commands/commands_tasks.rb:49:in `run_command!'
        from /Users/drb/.gem/ruby/2.3.0/gems/railties-5.0.0.1/lib/rails/commands.rb:18:in `<top (required)>'
        from /Users/drb/.gem/ruby/2.3.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:293:in `require'
        from /Users/drb/.gem/ruby/2.3.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:293:in `block in require'
        from /Users/drb/.gem/ruby/2.3.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:259:in `load_dependency'
        from /Users/drb/.gem/ruby/2.3.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:293:in `require'
        from /Users/drb/Code/project/mafia-rails/bin/rails:9:in `<top (required)>'
        from /Users/drb/.gem/ruby/2.3.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:287:in `load'
        from /Users/drb/.gem/ruby/2.3.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:287:in `block in load'
        from /Users/drb/.gem/ruby/2.3.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:259:in `load_dependency'
        from /Users/drb/.gem/ruby/2.3.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:287:in `load'
        from /Users/drb/.rbenv/versions/2.3.3/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
        from /Users/drb/.rbenv/versions/2.3.3/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
        from -e:1:in `<main>'

Environment

This was found to occur on Ruby on Rails 5.0.1 and ruby 2.3.3 on macOS

Error: `uninitialized constant Hashid` when using Rails from `main` branch.

Failure/Error: include Hashid::Rails

       NameError:
         uninitialized constant Hashid

           include Hashid::Rails
                   ^^^^^^^^
         Did you mean?  Hashids

This only happens when using rails from main branch.

    gem "rails", github: "rails/rails", branch: "main"
    gem "activestorage", github: "rails/rails", branch: "main"
    gem "hashid-rails", "~> 1.4", ">= 1.4.1"

Sign hashids created with hashids to prevent decoding ambigious ids

There are some cases where a standard integer can be decoded as a hashid. A solution to this would be to encode hashids as an array. This is already built in functionality for Hashids (https://github.com/peterhellberg/hashids.rb#encoding-several-numbers). A constant integer (72 = H in ascii) could be set in the first array position and used as a check, then the second would be the actual integer. If the array is not two positions, or if the first position in the array is not 72, then we know the hashid should not be decoded.

HASHID_KEY = 72
#=> 72
id = 518
#=> 518
hashids.encode(HASHID_KEY, id)
#=> "gB0NV05e"
decoded = hashids.decode("gB0NV05e")
#=> [72, 518]
decoded.first == HASHID_KEY && decoded.last == id
#=> true

overriding to_param not working after 6.1 upgrade

Hi, thanks for the excellent gem!
Unfortunately, after i upgraded to Rails 6.1 the overriding methods don't work for me any more.
Accessing via .hashid still works.
I don't think i've changed anything else.
Thanks

Handle finding of nested resources

Suppose my routes are as follows:

resources :posts do
    resources :comments
end

That is to say, a Comment is nested below the Post resource.

I have the following URL for viewing a comment on its own page:

/posts/ABC/comments/XYZ

The following works perfectly:

@post = Post.find(params[:post_id])

However, when attempting to retrieve a specific comment, based on the post:

@post = Post.find(params[:post_id])
@comment = Post.comments.find(params[:id])

I see the following error:

ActiveRecord::RecordNotFound at /posts/ABC/comments/XYZ
Couldn't find Comment with 'id'=XYZ [WHERE "comments"."post_id" = 123]
- - -
SELECT  "comments".* FROM "comments" WHERE "comments"."post_id" = $1 AND "comments"."id" = $2 LIMIT 1  [["post_id", 123], ["id", 0]]

Another attempt was the following:

@comment = Comment.where(post: @post).find(params[:id])

which errored with:

Couldn't find Comment with 'id'=XYZ [WHERE "comments"."post_id" = 123]
- - -
SELECT  "comments".* FROM "comments" WHERE "comments"."post_id" = 123 AND "comments"."id" = $1 LIMIT 1  [["id", 0]]

Note that in each case the ID is 0 because I'm passing the HashID which is converted to the integer 0.

It would be great to support this without requiring me to refactor my code and manually handle the HashID <--> ID conversion. Any thoughts?

Model#find_by_hashid method is falling back on the standard find method

Hi!

Currently using version 1.0.0 and just noticed that the Model#find_by_hashid method returns my models even if I pass the original integer id values...

If I open the rails console and type Company.find_by_hashid(1) I get my company with id=1... same thing with other ids... Normally, passing 1 as the argument here should not return the company...

Simplify installation instructions

I think just having the Gemfile installation instructions and not the gem install would be better. The gem is not really useful outside the context of the app. The existing installation instructions are pretty much boilerplate.

Uncaught exception: uninitialized constant Hashid

I've been using your gem w/o any issue in my code until I decided to move configuration in an initializer:

/config/initializers/hashid.rb

Hashid::Rails.configure do |config|
  # The salt to use for generating hashid. Prepended with table name.
  config.salt = "this is my salt"

  # The minimum length of generated hashids
  config.min_hash_length = 6

  # The alphabet to use for generating hashids
  config.alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
end

I get following error on startup: Uncaught exception: uninitialized constant Hashid

#find through non-hashid parent association does not work

If you have a has_many association where the parent does not use hashids, find through the association doesn't return the associated record. I added a failing test case to demonstrate.

It seems that to solve this, apart from overriding .find on the model class, we would have to override ActiveRecord::Associations::CollectionProxy's #find method.

Originally posted by @ahawrylak in #55 (comment)

Breakage when allowing integers in HashIDs alphabet

If configured with integers in the HashIDs alphabet, we have run into various problems resulting from the overridden find method.

Basically, certain hashids are created from numbers only (no letters), and it just so happens that those numbers can be correctly "decoded" into a valid integer.

A specific example for us was a Job which is passed the record's ID, and used find to retrieve that record. The ID passed in was 197895 but the error returned was Couldn't find Post with 'id'=70459792. Notice the completely different ID!

It's too late for us to change our HashID alphabet (it would break all existing IDs), but we can workaround this issue by relying on find_by_id (which is not overridden).

I propose this caveat of the system be prominently added to the README, as well as defaulting the alphabet to be letters only, to avoid risking this problem for other users.

How do I pass hashids as FKs to CRUD methods?

Assuming I have two classes:

Animal < ApplicationRecord
  has_many :dogs
end

Dog < ApplicationRecord
  belongs_to :animal
end

I can do
Animal.find(<hashid>)

...but not
Dog.create(animal_id: <hashid>)

Is this intended?

Compatibility with hashids Javascript

Hi @jcypret , apologies for n00b question. I was hoping to use hashids on both server (Rails-API) and client (Javascript). I am fairly new to hashing and I wasn't sure if I would get reliably consistent results on both server-side and client-side when encoding/decoding the hashids using the JS and this version. Should that be the case?

Thank you!

Allow configurable model-level salt independent of table_name

The fact that the model name is incorporated into the Hashids config is the main reason I rolled my own instead of using this. I'd love to see this so that I could remove some custom code, though I would encourage not tying this configuration concept to "table" and instead just generally allow a different "seed"/"salt" per-model to be mixed in.

My own version of this gem allows for something like:

class Author < ApplicationRecord
  # `salt`, `alphabet`, etc fallback to global but `pepper` is required
  hashes_ids pepper: 'authors'
end

Originally posted by @bjeanes in #47 (comment)

Pack as concern

Not all models need this functionality, I think it would be better convert it to model concern. And include when it needed.

Hashid and Rails 5?

Hi first off, thanks for this gem. I had a question regarding using this with Rails 5. Rails5 requires activerecord 5 (duh) but it looks like this gem depends on activerecord (~> 4.0). This causes Bundler to not find compatible versions for activerecord.

Any way to get this working in Rails5? (I'm new to this process so apologies if I missed something or this isn't the right forum for this).

Thanks!

Make to_param override optional

I'm trying hashid-rails without overriding the find method. I'd like to be explicit. Unfortunately, to_params is still overridden so can't use any code like Model.find(model.to_params) anymore. ActiveAdmin for instance does this and thus breaks.

Could you remove the to_params alias when config.override_find = false is set, or make it a separate option (override_to_params)?

Trouble with eager loading

Having trouble with eager loading and using hashid.

@item = Item.includes(:addons, {:addons => :sides}).find_by_hashid(params[:id])
This will work only if params is a hashid, not an integer id. Otherwise "Couldn't find Item"

@item = Item.includes(:addons, {:addons => :sides}).find(params[:id])
This will work only if params is an integer id, not a hashid. Otherwise "record is not found"

Hashids::InputError: unable to unhash

Hey,

Trying to see if I can drop this beautiful gem on my project without making too many (or any if possible) changes to it.

At first look, things seemed to be working immediately after adding the gem with zero change.

Only when running my tests I get to a point where this error appears:

Hashids::InputError: unable to unhash

This happens when I try an update operation on a controller that operates on a special case model. Not sure it is related though, but its the only obvious difference between this failing test and other passing tests.

It is a PeopleController that updates a User model.

The error of course originates from the hashids gem, specifically from this line, but to my understanding it is simply getting an invalid input.

Any thought as to why this happens and maybe a fix?

EDIT:
The immediate suspect is this line with table_name (seems not...)

Use secure salt for generating HashIDs object

This gem uses the table_name of the model as the salt for encoding HashIDs. It's great that the hash used differs between models (by depending on the table name), but it would be more secure to use something unique to the server in addition.

What do you think about concatenating a secret server key into the salt, like so:

hashids = Hashids.new("#{table_name}#{ENV['SECRET_KEY_BASE']}")

We should use something more secure; if not the SECRET_KEY_BASE then something configured via initializers/hashids.rb or similar?

Update:

I'm considering using ENV['HASHIDS_SALT'] - the reason being, if I ever need to reset my secret_key_base, I will not invalidate all my HashIDs. I also feel slightly uncomfortable using my secret key as (part of) my salt, because I know HashIDs aren't designed for security, and - although I doubt it's feasible - I can imagine someone reverse engineering my secret_key_base if they had a set of my HashIDs from which to brute force it.

Query return on Select

hi there is there any way for it to return on .select query? example

Person.where(name: "Jason").select(:name, :hashid)

Disable find(hashid)

Is there a way to disable find(hashid)?

I have set up a 6 character hashid with [a-z][0-9]. However, if I do a find for a unhashed id (123456), hashid will hash it and return an ActiveRecord::RecordNotFound exception.

It would be helpful for the find method to either catch the exception and try a non-hashed find or to have a configuration option to disable the find method.

Add Rails 5 support

Not sure what it needs, but the build fails against the ActiveRecord 5.x series.

ActiveRecord's ```exists?``` method always return false

Rails ActiveRecord has a method called exists? which returns a boolean true if the record exists or false if not.
This method now always returns ```false` ' if I give it a hashid instead of a normal ID.

Example code:

context.cart[:items] = context.cart[:items].select do |cart_item_hashid|
    Shop::Item.exists?(cart_item_hashid) # always false, Cart is emptied
  end

It should generate the following SQL:

SELECT 1 AS one FROM `shop_items` WHERE `shop_items`.`id` = 14 LIMIT 1

The current solution I'm using:

context.cart[:items] = context.cart[:items].select do |cart_item_hashid|
  Shop::Item.find(cart_item_hashid).present?
end

This generates the following SQL:

SELECT `shop_items`.* FROM `shop_items` WHERE `shop_items`.`id` = 14 LIMIT 1

This returns the whole record from the DB to check in Ruby code that it is not ```nil` '; it would be much more efficient just to return a boolean.

Another workaround is to do the following:

context.cart[:items] = context.cart[:items].select do |cart_item_hashid|
    Shop::Item.exists?(Shop::Item.decode_id(cart_item_hashid))
  end

It works fine; however, it is a bit redundant.

hashid in json response

Hi, when the model is represented as json, it still has the id from the database rather than the hashid. I'm noob in rails, so I was wondering if there is an easy way to ovveride it for all models?

FYI - 1.0 breaks compatibility with 0.5

Hi there,

I resolved this for myself by downgrading back to 0.5 but just figured I'd leave a little note here for anyone who follows.

I have a project in production using HashIDs -- it's how we resolve URLs. Thousands of URLs. Today I upgraded to Rails 5 and in the process upgraded from 0.4.1 to 1.0.0. The config key names changed, I updated them (couldn't find anything in the docs for that but it was pretty simple to figure out).

But even though I kept the values the same (only updated names), old HashIDs just stopped resolving. The secret is the same ,min length is the same, etc -- but find_by_hashid with a valid old hash ID just wouldn't work.

As mentioned, the fix was to drop back to 0.5.0 (so 0.4.1 -> 0.5.0 is fine).

model-level-config not working through ActiveRecord_Relation

I have been trying with the new hashid_config, as I have just renamed a table that I has using with hashid-rails setting the pepper on the model. I love the functionality. Unfortunately it does not work when querying an ActiveRecord_Relation.

The hashid_config parameters are set using the model parameters correctly as long as the model is queried directly, eg:

Post.hashid_configuration
=> returns correct pepper that is set in the model

But when if the ActiveRecord_Relation is in between it does not work, eg:

Post.all.hashid_configuration
=> returns the original table_name as pepper (overriding the one set on the model)

The hashid_config gets called on the ActiveRecord_Relation, and the options are empty.

This means that this works

Post.find("hashid")

but this doesn't

Post.includes(:comments).find("hashid")

Error ActiveRecord::RecordNotFound with fixtures - 2018 edition

Hi,

It seems like an old bug I found a year and a half ago (in #16) has resurfaced.
It is now easily reproducible.

When using fixtures, and setting config.sign_hashids to false, tests fail with an error like this:

ActiveRecord::RecordNotFound: Couldn't find User without an ID

For convenience, I have created an example repo that demonstrates the problem.

Also, for context, I should probably mention that I am disabling sign_hashids since I need compatibility with previous version, since I cannot afford my IDs to change (at least in one of my apps).

If any additional information is required, let me know.

ArgumentError: invalid range "r-0" in string transliteration

I ran into this rare issue where I have a model PlaylistTrack and when I call find(id) it throws this error: ArgumentError: invalid range "r-0" in string transliteration.

The error is thrown from the hashids gem with @guards being "r-0" https://github.com/peterhellberg/hashids.rb/blob/b729fe514e492e18d9f69473b53eb59a3b5aee4b/lib/hashids.rb#L117

The issue was resolved after adding an explicit pepper to something else instead of the implicit "playlist_tracks":

class PlaylistTrack < ApplicationRecord
  include Hashid::Rails
  hashid_config pepper: "playlisttracks"
  ...
end

Using this pepper resulted in the @guards being "y7d" instead which is accepted.

I guess its just by chance that "playlist_tracks" produces a problematic pepper but this could potentially be a problem with other table names as well.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.