Ruby on Rails
Tuesday, October 9, 2018
I can't figure out the right way to use find_or_create_by method which is not atomic.
-- In short, I have a before_action filter is used to either to find or create a User by its username.
def user
if decoded_auth_token && decoded_auth_token[:sub]
@user ||= User.find_or_create_by!(username: decoded_auth_token[:sub])
Rails.logger.silence do
@user.update_column(:token, http_auth_header)
end
@user
end
rescue ActiveRecord::RecordInvalid => e
raise(
ExceptionHandler::InvalidToken,
("#{Message.invalid_token} #{e.message}")
)
end
The problem is that the above method is called twice by different threads: 2 requests com from a JS front-end app, and I have the situation when 2 Users are created with the same username.
I tried to apply the suggested solution and wrap the method call in a transaction and use retry:
begin user = User.transaction(requires_new: true) do User.find_or_create_by(username: some_value) end rescue ActiveRecord::RecordNotUnique retry endcall_some_method to update other user attributes in User model:
def update_user_info(options) identifier = normalize_identifier(options[:sitenumber]) update( first_name: options[:givenName], last_name: options[:sn], shop_identifier: identifier, shop: user_shop(identifier) ) end
but it creates nevertheless the duplicate record. What am I missing ?
Used Rails version: 5.2.0
Ruby: 2.5.0
Thank you.
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-talk+unsubscribe@googlegroups.com.
To post to this group, send email to rubyonrails-talk@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rubyonrails-talk/579b1de8-8456-46d0-889f-f4569557ae44%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment