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.
Frage
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')"
Lösung
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.
Andere Tipps
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"]>