Рельсы first_or_initialize, но с условиями

#ruby-on-rails #activerecord #orm

Вопрос:

У меня есть модель пользователя с полями электронной почты, имени и кода. Электронное письмо должно быть уникальным. Есть ли в rails метод, с помощью которого я могу сделать это одним выстрелом:

создайте пользователя с определенным адресом электронной почты и кодом, если электронное письмо еще не принято, или обновите код пользователя с помощью этого электронного письма, но имя должно быть равно «abc».

или это единственный выход?

 begin
  user.create!(code: ..., email:...)
rescue ActiveRecord::RecordInvalid => e
  if it is email taken error
    User.where(name: 'abc').update(code:...)
  end
end
 

Спасибо

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

1. вы, вероятно, ищете User.find_or_initialize_by(электронная почта: «электронная почта»). Я не совсем понимаю, чего вы добиваетесь … если электронная почта должна быть уникальной…, почему их вторичное ограничение заключается в том, что имя должно быть равно «abc»… что вы собираетесь делать в сценарии, когда электронное письмо было принято, но присвоено какому-либо другому имени?

2. @David в сценарии, где электронная почта была взята, но присвоена какому-то другому имени, я не должен обновлять код, потому что по праву они не должны запрашивать его

3. а, понятно … тогда, вероятно, лучше всего использовать, как я предлагаю, а затем проверить имя для полученной записи.

Ответ №1:

Думаю, это то, что вы могли бы искать

 user = User.find_by(email: ...) || User.new(email: ...)
user.assign_attributes(code: ...) if user.name == 'abc' || user.new_record?
user.save if user.changed?
 

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

1. user.changed? может работать не так, как предполагалось, если в вашей модели есть столбцы Json

Ответ №2:

Что вам нужно, так это #find_or_create_by блок:

 User.find_or_create_by(email: ....) do |user|
  user.code = ... if user.name == 'abc'
end
 

Если он найдет пользователя с указанным адресом электронной почты, блок не будет вызван.

Если он не найдет пользователя с указанным электронным письмом, он вызовет блок, который обновит код только при условии, что имя «abc»