Как использовать метод joins с first_or_initialize вместо find_or_initialize_by (Rails)? - PullRequest
4 голосов
/ 20 мая 2019

Есть ли способ переписать процесс ниже, который в настоящее время использует find_or_initialize_by, используя метод joins?

Для контекста - у меня есть users (сотрудники), которые записывают свои attendances в системе (user имеет много attendances, а запись attendance принадлежит user).

Attendance.find_or_initialize_by(
  user: User.find_by(name: 'Bob'),
  date: Time.zone.today
)
.update(...) # Update some columns after this

Я пытаюсь переписать его, используя .joins так:

Attendance.joins(:user)
  .where(users: {name: 'Bob'}, date: Time.zone.today)
  .first_or_initialize
  .update(...) # Update some columns after this

Мои тесты возвращаются со смешанными результатами:

  • Тестовые случаи, когда запись должна быть только updated pass
  • Тестовые случаи, когда запись attendance еще не существует (то есть, когда мне приходится initialize), сбой

Сообщение об ошибке ActiveRecord::RecordInvalid: Validation failed: User must exist. Но я запутался, потому что пользователь действительно существует - если я отлаживаю с помощью byebug, пользователь там.

Ответы [ 2 ]

1 голос
/ 20 мая 2019

Вместо того, чтобы начинать с модели посещаемости, я бы хотел начать с пользователя, например:

User.find_by(name: 'Bob').attendances.find_or_initialize_by(date: Time.zone.today).update(...)

Это позволяет легко читать вещи.Вы можете добавить метод расширения ассоциации, чтобы сделать вещи более удобными:

class User < ActiveRecord::Base
  has_many :attendances do
    def for_date(date)
      find_or_initialize_by(date: Time.zone.today)
    end
  end
end

# Then call with:
User.attendances.for_date(Time.zone.today)

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

first_or_initialize удалено в соответствии с: https://api.rubyonrails.org/classes/ActiveRecord/Relation.html. Спасибо @engineersmnky за исправление.Метод недокументирован, но выглядит как ошибка.

0 голосов
/ 20 мая 2019

Вы устанавливаете идентификатор Боба в вызове обновления?В основном, когда вы запускаете это, а предложение where возвращается пустым, создается пустая новая запись.На данный момент все ссылки на Боба ушли, поэтому вам нужно установить его снова в обновлении:

Attendance.joins(:user)
  .where(users: {name: 'Bob'}, date: Time.zone.today)
  .first_or_initialize
  .update(user: User.find_by(name: 'Bob'), #other stuff ) # Update some columns after this
...