Ключ заключается в том, чтобы использовать запрос подсчета, чтобы получить количество записей для этого конкретного года:
class Thing < ApplicationRecord
before_commit :create_number!, if: -> { number.nil? }
private
def count_records_from_same_year
self.class.where(
created_at: (created_at.beginning_of_year..created_at.end_of_year)
).count
end
def create_number!
loop do
year = (created_at + 1.year).strftime("%y")
self.number = year.concat(sprintf '%02d', count_records_from_same_year)
break unless self.class.where(number: self.number).exists?
end
end
end
Как вы можете видеть, он генерирует последовательные числа:
irb(main):001:0> Thing.create
(0.3ms) BEGIN
Thing Create (1.3ms) INSERT INTO "things" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id" [["created_at", "2018-10-12 09:57:24.527527"], ["updated_at", "2018-10-12 09:57:24.527527"]]
(1.2ms) SELECT COUNT(*) FROM "things" WHERE "things"."created_at" BETWEEN $1 AND $2 [["created_at", "2018-01-01 00:00:00"], ["created_at", "2018-12-31 23:59:59.999999"]]
Thing Exists (1.4ms) SELECT 1 AS one FROM "things" WHERE "things"."number" = $1 LIMIT $2 [["number", "1901"], ["LIMIT", 1]]
(0.7ms) COMMIT
=> #<Thing id: 1, number: "1901", created_at: "2018-10-12 09:57:24", updated_at: "2018-10-12 09:57:24">
irb(main):002:0> Thing.create
(0.3ms) BEGIN
Thing Create (0.8ms) INSERT INTO "things" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id" [["created_at", "2018-10-12 09:57:26.402797"], ["updated_at", "2018-10-12 09:57:26.402797"]]
(0.7ms) SELECT COUNT(*) FROM "things" WHERE "things"."created_at" BETWEEN $1 AND $2 [["created_at", "2018-01-01 00:00:00"], ["created_at", "2018-12-31 23:59:59.999999"]]
Thing Exists (0.8ms) SELECT 1 AS one FROM "things" WHERE "things"."number" = $1 LIMIT $2 [["number", "1902"], ["LIMIT", 1]]
(0.7ms) COMMIT
=> #<Thing id: 2, number: "1902", created_at: "2018-10-12 09:57:26", updated_at: "2018-10-12 09:57:26">
irb(main):003:0> Thing.create
(0.5ms) BEGIN
Thing Create (0.7ms) INSERT INTO "things" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id" [["created_at", "2018-10-12 09:57:27.537635"], ["updated_at", "2018-10-12 09:57:27.537635"]]
(1.6ms) SELECT COUNT(*) FROM "things" WHERE "things"."created_at" BETWEEN $1 AND $2 [["created_at", "2018-01-01 00:00:00"], ["created_at", "2018-12-31 23:59:59.999999"]]
Thing Exists (0.6ms) SELECT 1 AS one FROM "things" WHERE "things"."number" = $1 LIMIT $2 [["number", "1903"], ["LIMIT", 1]]
(0.7ms) COMMIT
=> #<Thing id: 3, number: "1903", created_at: "2018-10-12 09:57:27", updated_at: "2018-10-12 09:57:27">