可排序的UUID并覆盖ActiveRecord :: Base

时间:2015-06-14 03:08:40

标签: ruby-on-rails postgresql ruby-on-rails-4 activerecord uuid

我想在我正在构建的应用中使用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

参考:

3 个答案:

答案 0 :(得分:5)

首先,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会增加新的订购条件,但他们不会替换已经存在的订单。

我认为你这一切都错了。每当我看到M.first时,我都会认为某些东西已被遗忘。按id订购内容几乎没用,因此在使用firstlast等方法之前,您应始终手动指定所需的订单。

答案 1 :(得分:1)

Rails 6(当前为6.0.0rc1版本)将通过implicit_order_column进行救援!

要按http://www.google.com/ 订购并让created_at.first.last等尊重,就很简单:

.second

答案 2 :(得分:0)

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

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