Reputation: 102250
Is there an equivalent of Active Records Model.create_with
to pass creation parameters separate of find parameters in Mongoid?
# Find the first user named "Scarlett" or create a new one with
# a particular last name.
User.create_with(last_name: 'Johansson').find_or_create_by(first_name: 'Scarlett')
# => #<User id: 2, first_name: "Scarlett", last_name: "Johansson">
I find myself using a clunky workaround:
user = User.find_or_initialze_by(first_name: 'Scarlett')
user.update(last_name: 'Johansson') if user.new_record?
Upvotes: 2
Views: 295
Reputation: 434805
Mongoid's find_or_create_by
takes an optional block which is only used when it needs to create something. The documentation isn't exactly explicit about this behavior but if you check the code you'll see that find_or_create_by
ends up as a call to this find_or
method:
def find_or(method, attrs = {}, &block)
where(attrs).first || send(method, attrs, &block)
end
with method
being :create
and the block
isn't used if the document you're looking for is found by where
.
That means that you can say:
user = User.find_or_create_by(first_name: 'Scarlett') do |user|
user.last_name = 'Johansson'
end
to get the effect you're after.
Presumably this "the create
half uses the block" behavior is supposed to be obvious because create
takes a block to initialize the object but find
doesn't.
If you're paranoid about this undocumented behavior, you can include a check for it in your specs so you'll at least know when an upgrade breaks it.
Upvotes: 4