-2

I am having a tough time understanding this code from Devise, even though I've read the documentation and done some research.

def self.find_first_by_auth_conditions(warden_conditions)
  conditions = warden_conditions.dup
  signin = conditions.delete(:signin)
  where(conditions).where(["lower(username) = :value OR lower(email) =
    :value", {:value => signin.downcase }]).first
end

Please explain the components of this portion of the above method:

where(conditions).where(["lower(username) = :value OR lower(email) =
  :value", {:value => signin.downcase }]).first
SoAwesomeMan
  • 3,226
  • 1
  • 22
  • 25
theJava
  • 14,620
  • 45
  • 131
  • 172
  • 1
    The first result of the query running against the warden conditions plus the username or email equals the signin value. What's the issue? – Dave Newton Apr 14 '14 at 14:51
  • @DaveNewton: Thanks, can you break it down in a simpler form. I am not able to understand it as a whole. – theJava Apr 14 '14 at 14:54
  • `warden_conditions.dup` - duplicate the warden conditions. Then `conditions.delete(:signin)` delete the sign in value. Then find the first record with those conditions and the username or email is the signin value as Dave says – j-dexx Apr 14 '14 at 15:01
  • Maybe you are confused by the fact that `conditions.delete(:signin)` returns the deleted value? – mdesantis Apr 14 '14 at 15:03
  • Can anyone write the equivalent query for the same. where(conditions).where(["lower(username) = :value OR lower(email) = :value", { :value => signin.downcase }]).first – theJava Apr 14 '14 at 15:04
  • `where(conditions)` depends by `warden_conditions` contents; the rest is translated, when `signin` is f.e. `Alfred`, to `lower(username) = 'alfred' OR lower(email) = 'alfred'` – mdesantis Apr 14 '14 at 15:07
  • That *is* the query for it. Obviously you understand the username and email part, right? We don't *know* what the warden conditions are. "first" is the first one. There's nothing else left in the query. Plus your log will *show* the emitted SQL. – Dave Newton Apr 14 '14 at 15:34
  • Also, please don't ask the same question twice. – Dave Newton Apr 14 '14 at 15:35
  • @DaveNewton: I am sorry, i come from JS and PHP background and feel very hard to digest some part of code. We don't write code like this instead perform queries. – theJava Apr 14 '14 at 15:37
  • @theJava These *are* queries; it's an almost-direct translation to SQL. The only real difference is that you can "build up" queries using multiple `where` clauses. `first` does a `limit 1`. – Dave Newton Apr 14 '14 at 16:20

1 Answers1

2
# arg is Hash, so assign to variable and downcase
x = warden_conditions[:signin].downcase

# create duplicate to preserve orig
c = warden_conditions.dup

# delete `:signin`
c.delete(:signin)

# if email, only search for email
if x =~ /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/
  y = self.where(c).where(:email => x) # self is implied, but optional--so we use it here for clarity 

# if not email, only search for name
else
  y = self.where(c).where(:username => x)
end

# y is array, so should be only one AR obj or empty array considering they are unique
# `Array#first` will return `nil` or AR obj
return y.first

regex via: validate email with regex jquery

The above code considers all previous records for columns email and username to be stored as lowercase as follows:

before_save :downcase_fields

def downcase_fields
  self.email.downcase
  self.username.downcase
end
Community
  • 1
  • 1
SoAwesomeMan
  • 3,226
  • 1
  • 22
  • 25
  • Thanks for this whole code, but again what your code has to do with this.. where(conditions).where(["lower(username) = :value OR lower(email) = :value", { :value => signin.downcase }]).first – theJava Apr 14 '14 at 15:29
  • Can u write the equivalent query for it. – theJava Apr 14 '14 at 15:30
  • @theJava Basically it's not equivalent, but close enough for illustrative purposes. Hope it helps. `lower(username)` queries column as if it was all lowercase with `signin.downcase` so devise doesn't need to know if any records were stored with uppercase or lowercase chars. – SoAwesomeMan Apr 14 '14 at 15:36
  • where(["lower(username) = :value OR lower(email) = :value", { :value => signin.downcase }]).first Does this part of code perform check on where(condition) – theJava Apr 14 '14 at 15:39
  • @theJava the regexp is to explain the "long way" with two queries that the devise query turns into one using `OR` – SoAwesomeMan Apr 14 '14 at 15:39
  • @theJava No, `where(["lower(username) = :value OR lower(email) = :value", { :value => signin.downcase }])` is only performed on the records that remain after this separate query `where(conditions)` – SoAwesomeMan Apr 14 '14 at 15:41
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/50628/discussion-between-thejava-and-awesome) – theJava Apr 14 '14 at 15:42