Is there a way to rewrite the process below, which currently uses find_or_initialize_by
, using the joins
method?
For context - I have users
(employees) who record their attendances
in the system (a user
has many attendances
, and an attendance
record belongs to a user
).
Attendance.find_or_initialize_by(
user: User.find_by(name: 'Bob'),
date: Time.zone.today
)
.update(...) # Update some columns after this
I'm trying to rewrite it using .joins
like this:
Attendance.joins(:user)
.where(users: {name: 'Bob'}, date: Time.zone.today)
.first_or_initialize
.update(...) # Update some columns after this
My tests come back with mixed results:
updated
passattendance
record doesn't exist yet (i.e. cases when I have to initialize
) failThe error message is
ActiveRecord::RecordInvalid: Validation failed: User must exist
.
But I'm confused because the user actually exists - if I debug using byebug
, the user is there.
Rather than starting from the Attendance model, I would tend to start from the User, like this:
User.find_by(name: 'Bob').attendances.find_or_initialize_by(date: Time.zone.today).update(...)
That keeps things easy to read. You could add an association extension method to make things more convenient:
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)
Depending on what you're doing with that attendance record, you could also have your for_date
method take extra arguments.
Thanks to @engineersmnky for the correction. The method is undocumented, but that looks likes a mistake.first_or_initialize
has been removed according to: https://api.rubyonrails.org/classes/ActiveRecord/Relation.html.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With