문제

I was previously using where(username: usernames) to take an array of usernames like and return an ActiveRecord::Relation of users. I've since created an Index on lower(username) and replaced User#find_by_username with the following:

def self.find_by_username(username)
  where("lower(username) = ?", username.downcase).first
end

This fails:

def self.find_by_usernames(usernames)
  where("lower(username) = ?", usernames.map(&:downcase))
end

It works when it's an array of one username, but not for multiple usernames. It generates SQL like "SELECT \"users\".* FROM \"users\" WHERE (lower(username) = 'joshsmith','vendiddy')"

도움이 되었습니까?

해결책

Update your method as below:

def self.find_by_usernames(usernames)
  where("lower(username) in (?)", usernames.map(&:downcase))
end

Use in instead of = because you want to check against multiple values in an array.

다른 팁

Some databases are not set case sensitive on text comparison as a default, like MySQL for example.

where("username in (?)", usernames.map(&:downcase))

The above delivers the desired result on MySQL unless default has been overwritten. See this post on Stackoverflow

I do agree however that adding the lower function should be the preferred method unless you like to gain a small speed advantage since the database server doesn't have to convert the string first.

> Contact.first
Contact Load (172.3ms)  SELECT `contacts`.* FROM `contacts` ORDER BY `contacts`.`id` ASC LIMIT 1
=> #<Contact id: 1, name: "John"> 

> Contact.where(name: "john")
Contact Load (171.9ms)  SELECT `contacts`.* FROM `contacts` WHERE `contacts`.`name` = 'john'
=> #<ActiveRecord::Relation [#<Contact id: 1, name: "John"]> 

> Contact.where(name: "JOHN")
Contact Load (172.3ms)  SELECT `contacts`.* FROM `contacts` WHERE `contacts`.`name` = 'JOHN'
=> #<ActiveRecord::Relation [#<Contact id: 1, name: "John"]> 
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top