【问题标题】:hash instead of id哈希而不是 id
【发布时间】:2014-10-07 12:47:34
【问题描述】:

我想在我的活动记录中使用自动生成的哈希而不是自动递增的整数作为主键。这提出了两个问题:

  1. 如何在 最有效的方法?
  2. 如何处理这种可能性 生成的哈希已经存在 桌子?

问候, 马特乌斯

【问题讨论】:

  • 我认为您应该将主键单独放在数据库性能上,您应该使用 slug,就像 Holde 说的那样,带有主键。例如“#{ self.id }-#{ SecureRandom.hex(4) }”

标签: ruby-on-rails activerecord


【解决方案1】:

如果你想要这个,因为你不想在 web url 中显示 id。你可以使用像https://github.com/peterhellberg/hashids.rb这样的宝石

它从您的数据库 id 创建一个可逆哈希,因此不需要将哈希存储在数据库中。

在你的模型中使用它to_param 方法。

class MyModel < ActiveRecord::Base

  def to_param
    Hashids.new("salt").encode(id)
  end
end

并在从数据库中找到记录之前解码散列。

def show
  id = Hashids.new("salt").decode(params[:id]).try(:first)
  record = MyModel.find(id)
end

【讨论】:

    【解决方案2】:

    这可能不是您所要求的。但是我有一个类似的问题,我想在 URL 中使用哈希而不是 ID。我的解决方案如下

    1. 我在表中添加了一个名为 privatelink 的列
    2. 在我的模型中我写道:
      #changes the url to use privatelink instead of the id
      def to_param
        privatelink
      end
    
      #calls the private method set_privatelink
      before_create :set_privatelink
    
      private
    
      #generates a unique hash looking something like this: c24bea1693d9e56a1878cb83f252fba05532d9d0
      def set_privatelink
        self.privatelink = Digest::SHA1.hexdigest([Time.now, rand].join)
      end
    

    来源: Railcast #63 Model Name in URL - 展示了如何使用 to_param 方法

    【讨论】:

      【解决方案3】:

      这不是你的问题的重复,但我认为你想做同样的事情:

      Assigning Each User a Unique 100 character Hash in Ruby on Rails

      【讨论】:

      • 对,这涵盖了我的大部分问题。我将使用类似:[ActiveSupport::SecureRandom.random_bytes(35)].pack("m*").delete("\n/+=")[0..31].downcase,因为我想在 url 中使用它。
      【解决方案4】:

      在使用 Oracle 时,我想自己创建 ID(而不是使用序列),并在 this post 中提供了我如何做到这一点的详细信息。简而言之,代码:

      # a small patch as proposed by the author of OracleEnhancedAdapter: http://blog.rayapps.com/2008/05/13/activerecord-oracle-enhanced-adapter/#comment-240
      # if a ActiveRecord model has a sequence with name "autogenerated", the id will not be filled in from any sequence
      ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.class_eval do
        alias_method :orig_next_sequence_value, :next_sequence_value
      
        def next_sequence_value(sequence_name)
          if sequence_name == 'autogenerated'
            # we assume id must have gotten a good value before insert!
            id
          else
            orig_next_sequence_value(sequence_name)
          end
        end
      end
      

      虽然此解决方案特定于 Oracle 增强型,但我假设在其他适配器中您可以否决相同的方法 (next_sequence_value)。

      【讨论】:

      • 哦,谢谢。对于 postgresql,我使用了this link。它还会覆盖 ConnectionAdapter。现在我使用 uuidtools gem 在 Rails 中生成 uuid,因为我不想在 postgresql 中安装额外的模块。 Oracle 版本将来可能会非常有用。
      • 良好的链接。所以你仍然有一个:id 和一个额外的:uuid 字段。也许这确实是最好的解决方案。我提出的想法是,您将用您自己生成的值覆盖正常的:id,它通常是从一个序列中填充的。为了完整起见:我认为您应该提供它作为您自己问题的答案。原生 uuid 生成确实是一个最优的解决方案。让数据库完成繁重的工作。
      • 你是对的,你的答案在甲骨文方面是最正确的。不幸的是,它没有为其他数据库提供解决方案。为什么我离开了:id? a) 由于互联网上的大多数 cmets 使用 uuid 作为主键会减慢具有大量数据集的数据库。 b)从 Rails 框架的角度来看,使用其他东西然后 auto_incremented 整数值作为主键是错误的。
      • 这些绝对是有效点。我需要的情况是因为我们在遗留数据库之上使用 Rails。
      猜你喜欢
      • 1970-01-01
      • 2012-11-26
      • 1970-01-01
      • 2018-08-31
      • 1970-01-01
      • 2014-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多