ruby-on-rails 可排序的UUID和重写ActiveRecord::Base

5cnsuln7  于 2023-10-21  发布在  Ruby
关注(0)|答案(4)|浏览(117)

我想在我正在构建的应用程序中使用UUID,但遇到了一点问题。由于UUID(v4)是随机生成的,所以无法排序,我试图首先覆盖ActiveRecord::Base#,但Rails对此不太满意。它对我大喊ArgumentError: You tried to define a scope named "first" on the model "Item", but Active Record already defined a class method with the same name.如果我想排序并让它正确排序,我必须使用不同的方法吗?
这是酱料:

# lib/sortable_uuid.rb
module SortableUUID
  def self.included(base)
    base.class_eval do
      scope :first, -> { order("created_at").first }
      scope :last, -> { order("created_at DESC").first }
    end
  end
end

# app/models/item.rb
class Item < ActiveRecord::Base
  include SortableUUID
end

Rails 4.2、Ruby 2.2.2
参考文件:

camsedfj

camsedfj1#

Rails 6(当前版本为6.0.0rc1)提供了implicit_order_column!
created_at排序,生成.first.last.second等。尊重就像这样简单:

class ApplicationRecord < ActiveRecord::Base
  self.implicit_order_column = :created_at
end
zour9fqk

zour9fqk2#

首先,firstlast并不像你想象的那么简单:你完全忽略了这两个方法都支持的limit参数。
其次,scope只不过是添加用于返回查询的类方法的一种奇特方式。您的作用域滥用了scope,因为它们返回单个模型示例而不是查询。你根本不想使用scope,你只是想替换firstlast类方法,那么为什么不直接覆盖它们呢?但是,您需要正确地覆盖它们,这将需要阅读和理解Rails源代码,以便正确地模仿find_nth_with_limit的功能。你会想要覆盖secondthird,.还有其他那些愚蠢的方法
如果你觉得不应该替换firstlast(这在IMO是件好事),那么你可以添加一个默认作用域来按需排序:

default_scope -> { order(:created_at) }

当然,默认作用域也有其自身的问题,像这样偷偷地把东西放入ORDER BY中可能会迫使您在任何时候真正想要指定ORDER BY时调用reorder;记住,多次调用order会添加新的排序条件,它们不会替换已经存在的条件。
或者,如果您使用的是Rails 6+,您可以使用Markus's implicit_order_column solution来避免默认作用域可能导致的所有问题。
我觉得你完全搞错了。每当我看到M.first时,我都认为有些东西被遗忘了。通过id排序几乎是无用的,所以你应该在使用firstlast这样的方法之前,总是手动指定你想要的顺序。

z5btuh9x

z5btuh9x3#

在将id替换为uuid之后,我在关联分配外键的方式上遇到了一些奇怪的情况,并不是.last.first,而是因为我忘记了使用uuid将default: 'gen_random_uuid()'添加到其中一个表中。一旦我修好了,问题就解决了。

create_table :appointments, id: :uuid, default: 'gen_random_uuid()' do |t|
jjhzyzn0

jjhzyzn04#

根据这里链接的rails文档,最好的方法是确保为您想要使用的UUID添加默认选项。关于选择UUID链接here的好文章。我使用了ULID,因为它们是可排序的,并且将我的UUID选项指定为ULID,我的记录是可排序的!

相关问题