find_or_create_by multiple attributes not finding records when called in context of belongs_to object (AR bug in 2.3.11?)
I am adding omniauth to a rails 2.3.11 application with devise. I'm basically following Ryan Bate's railscast (with appropriate modifications for rails 2.3). But I'm seeing something very odd in testing this part of the code:
class AuthenticationsController < ApplicationController
...
def create
auth = request.env["omniauth.auth"]
current_user.authentications.find_or_create_by_provider_and_uid(auth['provider'], auth['uid'])
flash[:notice] = "Authentication successful."
redirect_to authentications_url
end
...
end
The find_or_create always creates. In the log, I see this select:
SELECT * FROM `authentications` WHERE (`authentications`.`provider` IN ('facebook','XXXXXXX') AND `authentications`.`uid` IS NULL) AND ((`authentications`.`user_id` = 10)) LIMIT 1
That is not the right select for that method. auth['provider'] and auth['uid'] are populated correctly (and it creates the new record just fine).
More perplexing: If I go into the console and do Authentication.find_or_create_by_provider_and_uid('facebook', 'XXXXX')
, it works fine (it finds the existing record). But if I get a user and do user.authentications.find_or_create_by_provider_and_uid('facebook', 'XXXXX')
, it creates a new record and I see the same problematic query statement in the log.
I know I can work around this (and Ryan Bates changes this code later anyway), but this is very troubling. Am I missing something or does this look like a bug in ActiveRecord?
This is not specific to OmniAuth or Devise. Before submitting this, I tried it with two other classes (rather simple classes). Same result [ Klass.find_or_create_by_a_and_b('A','B') works but parent.klasses.find_or_create_by_a_and_b('A','B') generates a select that wants b to be null and a in ('A开发者_StackOverflow社区','B')].
Now I'm definitely thinking this is a bug 2.3.11. Before I submit a bug, does anybody see anything I'm missing? Has anyone seen this problem?
I just updated an app from Rails 2.3.10 to 2.3.11 and I ran into this bug, too.
In our code, we have:
rate_plan = lodging.rate_plans.find_or_create_by_primary_code_and_secondary_code(rate_plan_code, inv_type_code)
which worked fine under 2.3.10. Under 2.3.11, rate_plan winds up being a new record, even though find_by_primary_code_and_secondary_code(rate_plan_code, inv_type_code) will find an existing record. Not only is rate_plan a new record in 2.3.11, but it's not saved because our uniqueness validation isn't met.
Ugh. I'll go back to 2.3.10 for now.
What are the values of auth['provider'] and auth['uid']? Maybe I am wrong, but it looks to me that auth['provider'] is ['facebook','XXXXXXX'] and auth['uid'] is nil.
It definetely must be, like Tudor Constantin says, a problem with the auth['provider'] value, as it seems to be an array. Have you tried to make a puts call over this variable? What is the result?
Also I hope that you know that this:
Authentication.find_or_create_by_provider_and_uid('facebook', 'XXXXX')
is not the same as this:
user.authentications.find_or_create_by_provider_and_uid('facebook', 'XXXXX')
In the first case you're searching through all Authentication instances / rows, while in the second one you're reducing the search scope so it only looks for Authentication instances / rows that belong to that concrete instance of User.
Check
auth['uid']
I guess it is coming blank for you. That is why
`authentications`.`uid` IS NULL) AND ((`authentications`.`user_id` = 10))
is conflicting
精彩评论