Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails Rails回调在不同的环境中表现不同_Ruby On Rails_Ruby_Postgresql_Heroku - Fatal编程技术网

Ruby on rails Rails回调在不同的环境中表现不同

Ruby on rails Rails回调在不同的环境中表现不同,ruby-on-rails,ruby,postgresql,heroku,Ruby On Rails,Ruby,Postgresql,Heroku,我有两个Rails环境。一个运行Postgres和Rails 5.0.6的开发环境和Heroku上几乎相同的环境 我有一个Administrator类,它根据用户的forename和names字段在保存之前为管理员生成用户名 class Administrator < ApplicationRecord validates :username, uniqueness: true validates :forename, presence: true validates :su

我有两个Rails环境。一个运行Postgres和Rails 5.0.6的开发环境和Heroku上几乎相同的环境

我有一个
Administrator
类,它根据用户的
forename
names
字段在
保存之前为
管理员
生成用户名

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
正如您所看到的,回调被执行,用户的用户名被生成,并按预期保存到数据库中

但是,当我在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
,然后您的逻辑尝试创建一个已经存在的新用户

。。。在看不到实际数据的情况下,我无法确定您的生产服务器上发生了什么,但我敢打赌是这样的。它可能稍微复杂一些,例如用户:
tom
tom3
tomlord
存在;因此,您的逻辑尝试创建第二个
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

虽然此处的多个数据库查询在实际应用程序中不太可能是一个主要问题(假设没有许多管理员同名!),但这可能会提高性能。

在验证后调用\u save之前,因此会出现错误

请在验证之前尝试

以下是创建对象时调用回调的顺序,以供参考:

  • 验证前
  • 验证后
  • 在你保存之前
  • 关于保存
  • 在创建之前
  • 围绕你创造
  • 创建后
  • 保存后
  • 提交后/回滚后

这是打字错误还是代码中存在<代码>管理员。其中(“用户名ILIKE?”,“#{建议的}%”)。大小
ILIKE
应该是
LIKE
。ILIKE是LIKE,但不区分大小写。是的,这是正确的。事实证明,我们有脏的测试数据,这导致验证失败,因为我们为我们的情况选择了错误的回调。非常感谢。
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