hashid 的 ActiveRecord 查询

如何解决hashid 的 ActiveRecord 查询

我们使用 https://github.com/peterhellberg/hashids.rb 在我们的 API 中混淆数据库 ID:

HASHID = hashids.new("this is my salt")

product_id = 12345
hash = HASHID.encode(product_id)
=> "NkK9"

在解码 hashids 时,我们必须这样做:

Product.find_by(id: HASHID.decode(params[:hashid]))

这种模式在我们的应用程序中重复了很多。我可以编写一些像 find_by_hashidwhere_hashid 这样的辅助函数来处理解码和可能的错误处理。但是当将它们与其他查询方法结合使用时,这很快就会变得脆弱。

所以我想知道,是否可以扩展 ActiveRecord 查询接口以支持特殊的虚拟列 hashid,以便这样的事情成为可能:

Product.where(hashid: ["Nkk9","69PV"])
Product.where.not(hashid: "69PV")
Product.find_by(hashid: "Nkk9")
Product.find("Nkk9")

# store has_many :products
store.products.where(hashid: "69PV")

这个想法很简单,只要找到 hashid 键,把它变成 id 并解码给定的 hashid 字符串。出错时,返回 nil

但我不确定 ActiveRecord 是否提供了一种方法来做到这一点,而无需大量的猴子修补。

解决方法

您可能可以按如下方式使用此基本选项,但我永远不会推荐它:

module HashIDable
  module Findable
    def find(*args,&block)
      args = args.flatten.map! do |arg| 
        next arg unless arg.is_a?(String)
        decoded = ::HASHID.decode(arg)
        ::HASHID.encode(decoded.to_i) == arg ? decoded : arg
      end
      super(*args,&block)
    end
  end
  module Whereable
    def where(*args)
      args.each do |arg| 
        if arg.is_a?(Hash) && arg.key?(:hashid) 
          arg.merge!(id: ::HASHID.decode(arg.delete(:hashid).to_s))
        end
      end 
      super(*args) 
    end
  end
end 

ActiveRecord::FinderMethods.prepend(HashIDable::Findable)
ActiveRecord::QueryMethods.prepend(HashIDable::Whereable)

您可以将此文件放在“config/initializers”中,看看会发生什么,但这种实现非常幼稚且非常脆弱。

上述情况可能有 101 个地方无法计算,包括但绝对不限于:

  • MyModel.where("hashid = ?","Nkk9")
  • MyModel.joins(:other_model).where(other_models: {hashid: "Nkk9"})

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?