Какая разница между:
self.implicit_order_column = 'id'
и
default_scope { order('id ASC') }





self.implicit_order_column позволяет использовать другой столбец, а не первичный ключ, в качестве столбца неявного порядка. Это влияет на то, как работают такие методы, как .first и .last:
User.class_eval do
self.implicit_order_column = 'created_at'
end
User.first
# => SELECT "users".* FROM "users" ORDER BY "users"."updated_at" ASC LIMIT $1 [["LIMIT", 1]]
User.last
# => SELECT "users".* FROM "users" ORDER BY "users"."updated_at" DESC LIMIT $1 [["LIMIT", 1]]
Установка self.implicit_order_column = 'id' совершенно бессмысленна, поскольку по умолчанию в любом случае используется столбец первичного ключа. implicit_order_column, конечно, не используется, если вы указываете явный порядок. На самом деле это не изменяет никакие другие области видимости, порожденные классом.
default_scope, с другой стороны, прикрепляет область по умолчанию к любым областям, которые вы порождаете из класса.
irb(main):001:0> User.all
(0.5ms) SELECT sqlite_version(*)
User Load (0.1ms) SELECT "users".* FROM "users" LIMIT ? [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<User id: 1, role: "admin", created_at: "2020-11-08 19:31:31", updated_at: "2020-11-08 19:31:47">]>
irb(main):002:1* User.class_eval do
irb(main):003:1* default_scope { order(id: :asc) }
irb(main):004:0> end
=> [#<Proc:0x00000000043703a8 (irb):3>]
irb(main):005:0> User.all
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<User id: 1, role: "admin", created_at: "2020-11-08 19:31:31", updated_at: "2020-11-08 19:31:47">]>
irb(main):006:0>
Тут разница не сразу бросается в глаза. Но если учесть, что в мире SQL запрос без предложения порядка не будет возвращать записи в определенном порядке (зависит от его реализации), и здесь мы фактически получаем записи в определенном порядке. Во многих СУБД результаты будет трудно различить, поскольку они могут возвращать записи в том порядке, в котором они были изменены (если им так хочется).
Кажется блестящим, пока вы не поймете, насколько неинтуитивна default_scope и сколько ошибок она приводит в будущем.
irb(main):006:0> User.all.order(:created_at)
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC, "users"."created_at" ASC LIMIT ? [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<User id: 1, role: "admin", created_at: "2020-11-08 19:31:31", updated_at: "2020-11-08 19:31:47">]>
irb(main):007:0>
Или этот пример:
irb(main):001:1* User.class_eval do
irb(main):002:1* default_scope { where(admin: true) }
irb(main):003:0> end
=> [#<Proc:0x0000000002bde460 (irb):2>]
irb(main):004:0> User.new
(0.6ms) SELECT sqlite_version(*)
=> #<User id: nil, role: "visitor", created_at: nil, updated_at: nil, admin: true>
Ой! default_scope, таким образом, широко считается злом.
Видеть:
Применяется к ассоциациям, но только с first/last, например cat.whiskers.first. Он не применяется при повторении ассоциации, например, cat.whiskers.each (ни с Whisker.all.each).
@Zubin, это хорошее пояснение того, что я имел в виду под «на самом деле это не меняет никаких других областей, порожденных классом». - когда вы вызываете each, вы неявно создаете область видимости.
Спасибо, что написали! В вашем первом примере я сошел с ума или вы указали неправильный столбец в выводе SQL? Разве результат не будет ORDER BY created_at, а не ORDER BY updated_at?
@TobiasFünke да, скорее всего, это ошибка копипасты
Вот подсказка: к сожалению,
implicit_order_columnприменяется только к областям самого объекта, а не к ассоциациям, поэтому вам нужно указатьclass Cat; has_many :whiskers, -> { order(timestamp: "asc") }, даже еслиclass Whisker; self.implicit_order_column = 'timestamp'-- iircdefault_scopeтакже применяется к ассоциациям