数组作为Rails中find_or_create_by的条件

Mil*_*lan 2 ruby-on-rails ruby-on-rails-4

我有这样的事情:

types = ['landline', 'cell']
Phone.find_or_create_by(person_id: 1, type: types) do |record|
 record.number = '0'
end
Run Code Online (Sandbox Code Playgroud)

这行不通。不会创建新记录。但是当我重写它看起来像这样:

types = ['landline', 'cell']
types.each do |type|
 Phone.find_or_create_by(person_id: 1, type: type) do |record|
  record.number = '0'
 end
end
Run Code Online (Sandbox Code Playgroud)

有用。

有什么想法为什么find_or_create_by不能将数组作为条件?

Sra*_*van 5

很好的问题,这是我的示例解释。

find_or_create_by首先运行a select query,然后继续create method

api文档中有一个find_or_create_by注释,

请注意,此方法不是原子方法,它首先运行SELECT,如果没有结果,则尝试INSERT。如果还有其他线程或进程,则这两个调用之间存在竞争条件,并且最终可能会有两个相似的记录。

这是find_or_create_by的参考

因此,当运行此命令时,它将首先运行select查询

例如,让我获取一个用户表,并从控制台结果中显示该表。

我的用户test222@example.com数据库中有电子邮件,但没有test333@example.com

User.find_or_create_by(email: ['test222@example.com','test333@example.com'])

现在,当我运行时,find_or_create_by这是生成的查询。

User Load (175.5ms) SELECT用户.* FROM用户WHERE用户.电子邮件IN ('test222@example.com', 'test333@example.com') LIMIT 1

回应是

=> #<User id: 82, provider: "email", uid: "test222@example.com", name: nil, nickname: nil, image: nil, email: "test222@example.com", created_at: "2016-09-05 12:35:01", updated_at: "2016-09-05 12:35:01">

因此它返回找到的用户,并且没有运行create方法,而忽略了未找到(第二封电子邮件)

现在,如果我循环运行它,

emails = ['test222@example.com','test333@example.com']
emails.each do |email|
    User.find_or_create_by(email: email)
end
Run Code Online (Sandbox Code Playgroud)

将针对第二封电子邮件运行INSERT查询,

**INSERT INTO `users` (`email`,`created_at`, `updated_at`) VALUES ('test@ead.com', '2016-10-07 13:16:25', '2016-10-07 13:16:25')**
Run Code Online (Sandbox Code Playgroud)

您的情况也是如此。