簡體   English   中英

Rails回調在不同環境下的行為不同

[英]Rails callbacks behaving differently on different environments

我有兩個Rails環境。 一個運行Postgres和Rails 5.0.6的開發環境,以及一個在Heroku上幾乎相同的環境。

我有一個Administrator類,該類根據用戶的surnamesurname字段在before_save回調中為Administrator生成用戶forename

class Administrator < ApplicationRecord

  validates :username, uniqueness: true
  validates :forename, presence: true
  validates :surname, presence: true

  before_save :generate_username

  def generate_username
    return if username.present?
    proposed = "#{forename}#{surname}".downcase
    existing_count = Administrator.where("username ILIKE ?", "#{proposed}%").size
    self.username = existing_count.zero? ? proposed : "#{proposed}#{existing_count}"
  end
end

驗證用戶之后, FORENAMESURNAMEX的形式生成用戶名,其中X是遞增數字(或不遞增)。

這是我在開發機器上的Rails控制台中運行的命令。

irb(main):012:0> Administrator.create(email: 'edward@test.net', forename: 'Edward', surname: 'Scissorhands')
D, [2017-10-13T10:00:18.985765 #280] DEBUG -- :    (0.2ms)  BEGIN
D, [2017-10-13T10:00:18.987554 #280] DEBUG -- :   Administrator Exists (0.5ms)  SELECT  1 AS one FROM "administrators" WHERE "administrators"."email" = $1 LIMIT $2  [["email", "edward@test.net"], ["LIMIT", 1]]
D, [2017-10-13T10:00:18.988923 #280] DEBUG -- :   Administrator Exists (0.4ms)  SELECT  1 AS one FROM "administrators" WHERE "administrators"."username" IS NULL LIMIT $1  [["LIMIT", 1]]
D, [2017-10-13T10:00:18.990155 #280] DEBUG -- :    (0.4ms)  SELECT COUNT(*) FROM "administrators" WHERE (username ILIKE 'edwardscissorhands%')
D, [2017-10-13T10:00:18.992000 #280] DEBUG -- :   SQL (0.5ms)  INSERT INTO "administrators" ("email", "created_at", "updated_at", "username", "forename", "surname") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"  [["email", "edward@test.net"], ["created_at", "2017-10-13 10:00:18.990421"], ["updated_at", "2017-10-13 10:00:18.990421"], ["username", "edwardscissorhands"], ["forename", "Edward"], ["surname", "Scissorhands"]]
D, [2017-10-13T10:00:18.995845 #280] DEBUG -- :    (1.8ms)  COMMIT
=> #<Administrator id: 10, email: "edward@test.net", created_at: "2017-10-13 10:00:18", updated_at: "2017-10-13 10:00:18", role: nil, otp_public_key: nil, username: "edwardscissorhands", forename: "Edward", surname: "Scissorhands">

如您所見,將執行回調,並生成用戶的用戶名,並將其持久保存到數據庫中。

但是,當我在Heroku(和Heroku Postgres)上運行的測試環境中運行相同的代碼時,會發生以下情況:

irb(main):005:0> Administrator.create!(email: 'edward@test.net', forename: 'Edward', surname: 'Scissorhands')
   (1.9ms)  BEGIN
  Administrator Exists (1.1ms)  SELECT  1 AS one FROM "administrators" WHERE "administrators"."email" = $1 LIMIT $2  [["email", "edward@test.net"], ["LIMIT", 1]]
  Administrator Exists (0.9ms)  SELECT  1 AS one FROM "administrators" WHERE "administrators"."username" IS NULL LIMIT $1  [["LIMIT", 1]]
   (0.9ms)  ROLLBACK
ActiveRecord::RecordInvalid: Validation failed: Username has already been taken

(我在這里使用create!而不是create來顯示開發中不會發生的驗證錯誤。)

我不明白為什么行為在環境之間應該有所不同。 兩者都運行相同版本的Rails(5.0.6),並且運行相同的代碼庫。

您代碼中的邏輯有缺陷。 這是一個合法的錯誤; 您需要重新設計用戶名生成詞的方式。

例如,假設您的系統中有一個名為edwardscissorhands1 沒有edwardscissorhands ,也沒有edwardscissorhands2/3/4等。

該行: Administrator.where("username ILIKE ?", "edwardscissorhands%").size返回1 ,然后您的邏輯嘗試創建一個已經存在的新用戶。

...我不能肯定地說您的生產服務器上發生了什么,而沒有看到實際數據,但是我敢打賭,它是這樣的。 它可能會更復雜一些,例如用戶: tomtom3tomlord存在; 因此,您的邏輯嘗試創建第二個tom3用戶。

例如,如果您生成了一些edwardscissorhards用戶,然后刪除了其中一個或多個用戶,則可能會發生這種情況。

例如 ,這是重新設計邏輯的一種方法:

def generate_username
  return if username.present?
  proposed = "#{forename}#{surname}".downcase
  return proposed unless Administrator.exists?("username ILIKE ?", proposed)

  counter = 1
  while(Administrator.exists?("username ILIKE ?", "#{proposed}#{counter}"))
    counter += 1
  end

  "#{proposed}#{counter}"
end

盡管在實際應用程序中,這里的多個數據庫查詢不太可能成為主要問題(假設您沒有很多同名管理員!),這可能會提高性能。

驗證之后調用before_save,因此會出錯。

請嘗試使用before_validation。

供參考,以下是在創建對象時調用的訂單回調:

  • before_validation
  • after_validation
  • before_save
  • around_save
  • before_create
  • around_create
  • after_create
  • after_save的
  • after_commit / after_rollback

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM