Rails find_or_create_by где выполняется блок в случае поиска?

#ruby-on-rails #activerecord #dynamic-finders

#ruby-on-rails #activerecord #динамические средства поиска

Вопрос:

Метод динамического поиска ActiveRecord find_or_create_by позволяет мне указать блок. В документации это неясно, но, похоже, что блок выполняется только в случае создания, а не в случае поиска. Другими словами, если запись найдена, блок не выполняется. Я тестировал это с помощью этого консольного кода:

 User.find_or_create_by_name("An Existing Name") do |u|
  puts "I'M IN THE BLOCK"
end
  

(ничего не было напечатано). Есть ли какой-либо способ запустить блок в обоих случаях?

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

1. Я слишком часто сталкивался с таким поведением, поэтому обычно я отказываюсь от использования блока. Вместо этого я бы присвоил переменной результат find_or_create_by_... , а затем впоследствии оперировал бы с этой переменной.

Ответ №1:

Насколько я понимаю, блок будет выполнен, если ничего не найдено. Вариант его использования выглядит следующим образом:

 User.find_or_create_by_name("Pedro") do |u|
  u.money = 0
  u.country = "Mexico"
  puts "User is created"
end
  

Если пользователь не найден, он инициализирует нового пользователя с именем «Pedro» и всем этим материалом внутри блока и вернет нового созданного пользователя. Если пользователь существует, он просто вернет этого пользователя без выполнения блока.

Также вы можете использовать «стиль блока» и другие методы, такие как:

 User.create do |u|
  u.name = "Pedro"
  u.money = 1000
end
  

Он будет делать то же самое, что и User.create( :name => "Pedro", :money => 1000 ) , но выглядит немного приятнее

и

 User.find(19) do |u|
  ..
end
  

и т. Д

Ответ №2:

Мне не кажется, что на этот вопрос действительно дан ответ, поэтому я так и сделаю. Я думаю, это самый простой способ, которым вы можете этого добиться:

 User.find_or_create_by_name("An Existing Name or Non Existing Name").tap do |u|
  puts "I'M IN THE BLOCK REGARDLESS OF THE NAME'S EXISTENCE"
end
  

Приветствия!

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

1. Вы использовали tap который вернет результат find_or... , так что фактически блок передается не в find, а в tap!

2. Обратите внимание, что в случае, если ваша таблица имеет ограничение not null, которому не удовлетворяют поля, по которым вы выполняете поиск, вызов tap вызовет ActiveRecord::StatementInvalid