I have an active record query with a Not Equal clause for a string. For example:
Post.where.not(title: "Rails 4")
or
Post.where("title != ?", "Rails 4")
However, if the title is empty or blank it will not be included in the results. How can I also include the records that have a blank or empty title?
For example:
Posts
id => 1, title => "Rails 4"
id => 2, title => ""
id => 3, title => "Rails 3"
Actual Result:
Post.where.not(title: "Rails 4") #=> [3]
Desired Result:
Post.where.not(title: "Rails 4") #=> [2, 3]
试试下面的查询
Post.where("title != ? OR title = ?", "Rails 4",'')
* NOTE I'm assuming you're using a database like postgres and that the issue you're having is with null values, not empty string values. If empty string values aren't being returned then you have an entirely different issue
The reason where.not(title: 'Rails 4')
doesn't return what you expect is that you have null values in the string field, and any comparison with null will be null, which is falsey.
Posts
id => 1, title => "Rails 4"
id => 2, title => ""
id => 3, title => "Rails 3"
id => 4, title => NULL
In order to include Post #4 in the results, you need to explicitly include null values. One way to do that is with IS NULL
.
# Original - excludes rows with null title
Post.where.not(title: "Rails 4") #=> [2,3]
# SELECT posts.* FROM posts WHERE posts.title != 'Rails 4'
# Option #1 - explicitly include null
Post.where.not(title: "Rails 4").or(Post.where(email: nil)) #=> [2,3,4]
# SELECT posts.* FROM posts WHERE (posts.title != 'Rails 4' OR posts.title IS NULL)
# Option #2 - replace null values with empty string
POST.where.not("coalesce(posts.title, '') = ?", 'Rails 4')
# SELECT posts.* FROM posts WHERE NOT (coalesce(posts.title, '') = 'Rails 4')
A third solution is to disallow null values in your string field entirely (with a NOT NULL
constraint). Allowing null values in a string field can have other unexpected side-effects - for example, if you order your posts by 'email' then posts with a null email will show up in a different spot than you posts with an empty string email, but to the user it just looks confusing.
You can manually type the SQL here and possibly create a database dependency, or use ActiveRecord combined with Arel , which is a bit less readable, but works nicely:
table = Post.arel_table
Post.where(table[:title].not_eq('Rails 4').or(table[:title].eq('')))
Pavans答案是正确的,只需使用它
Post.where("title != ? OR title = ?", "Rails 4",'')
I realise this is 7 years old but it still comes up on Google. A better solution is using reject instead of where.not
Post.all.reject{|x| x.title == "Rails 4"}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.