简体   繁体   中英

Rails Active Record Queries - Not Equal and Blank/Empty Strings

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM