Массив как условие для find_or_create_by в Rails

#ruby-on-rails #ruby-on-rails-4

#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
  

Это не работает. Новые записи не создаются. Но когда я переписываю его, чтобы он выглядел так:

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

это работает.

Есть идеи, почему find_or_create_by не работает с массивом в качестве условия?

Комментарии:

1. Вы хотите создать 1 новый объект класса Phone или 2 новых объекта? find_or_create_by предназначен специально для 1 объекта и только для 1 объекта.

2. Я хотел бы создать 2 новых объекта. Есть ли что-то подобное find_or_create_by , что создало бы 2 новых объекта?

3. Нет. Вы либо используете итератор во втором блоке кода, как показано, либо перемещаете эту логику в пользовательский метод, если собираетесь вызывать его в нескольких разных местах.

4. Можете ли вы описать проблему в простой истории пользователя? Например, «Пользователь должен иметь возможность создать свою учетную запись с несколькими номерами телефонов …».

Ответ №1:

Хороший вопрос, вот мое объяснение с примером.

find_or_create_by сначала выполняется 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 this, генерируется запрос.

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, игнорируя not found(второе электронное письмо)

Теперь, если я запускаю его в цикле,

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

Запрос 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')**
  

Это тот же случай и в вашем случае.