为什么这个范围会为枚举返回错误的对象?

时间:2014-09-18 21:44:58

标签: ruby-on-rails activerecord ruby-on-rails-4

在我的Post.rb型号上,我有这个:

class Post < ActiveRecord::Base
  belongs_to :user
  enum is_published: [ :no, :yes ]

  scope :published, -> { where( is_published: "yes") }
  scope :unpublished, -> { where( is_published: "no") }
end

但是当我尝试在我的控制台中执行此操作时,它会给我错误的结果:

 > Post.published.count
   (0.7ms)  SELECT COUNT(*) FROM "posts"  WHERE "posts"."is_published" = 0
 => 5 
 > Post.published
  Post Load (1.0ms)  SELECT "posts".* FROM "posts"  WHERE "posts"."is_published" = 0
 => #<ActiveRecord::Relation [#<Post id: 20, title: "Chang calls for immediate removal of Davies, JUTC ...", photo: nil, body: "Opposition spokesperson on Transport, Horace Chang...", created_at: "2014-08-30 11:07:05", updated_at: "2014-08-30 20:03:56", user_id: 1, ancestry: nil, file: "Davies-Must-Go.pdf", status: 0, slug: "chang-calls-for-immediate-removal-of-davies-jutc-m...", is_published: 0, has_eyewitness: false>, #<Post id: 21, title: "PNP Chairman expresses shock, grief at Clarke’s pa...", photo: nil, body: "Chairman of the People’s National Party (PNP), the...", created_at: "2014-08-30 13:22:05", updated_at: "2014-08-30 20:03:56", user_id: 1, ancestry: nil, file: nil, status: 1, slug: "pnp-chairman-expresses-shock-grief-at-clarke-s-pas...", is_published: 0, has_eyewitness: false>, #<Post id: 22, title: "ALGAJ Pays Tribute to the Honourable Roger Clarke", photo: nil, body: "The Association of Local Government Authorities of...", created_at: "2014-08-30 16:19:12", updated_at: "2014-08-30 20:03:56", user_id: 1, ancestry: nil, file: nil, status: 2, slug: "algaj-pays-tribute-to-the-honourable-roger-clarke", is_published: 0, has_eyewitness: false>, #<Post id: 26, title: "PNPYO saddened at passing of Roger Clarke", photo: nil, body: "The People’s National Youth Organisation (PNPYO), ...", created_at: "2014-08-30 19:50:47", updated_at: "2014-08-30 19:50:47", user_id: 1, ancestry: nil, file: nil, status: 1, slug: "pnpyo-saddened-at-passing-of-roger-clarke", is_published: 0, has_eyewitness: false>, #<Post id: 25, title: "10PP 1 on 2", photo: "1-on-1-Icon.jpg", body: "10PP gives you a lot of one on one attention that ...", created_at: "2014-08-30 17:35:17", updated_at: "2014-08-30 20:09:05", user_id: 1, ancestry: nil, file: nil, status: 0, slug: "10pp-1-on-2", is_published: 0, has_eyewitness: false>]> 
 > Post.published.first.is_published
  Post Load (3.6ms)  SELECT  "posts".* FROM "posts"  WHERE "posts"."is_published" = 0  ORDER BY "posts"."id" ASC LIMIT 1
 => "no" 

如您所见,从Post.published返回的AR关系中的第一个对象实际上具有"no"的值。

同样,如果我做Post.unpublished,我会得到相同的数据集:

 > Post.unpublished.count
   (0.7ms)  SELECT COUNT(*) FROM "posts"  WHERE "posts"."is_published" = 0
 => 5 
 > Post.unpublished
  Post Load (0.6ms)  SELECT "posts".* FROM "posts"  WHERE "posts"."is_published" = 0
 => #<ActiveRecord::Relation [#<Post id: 20, title: "Chang calls for immediate removal of Davies, JUTC ...", photo: nil, body: "Opposition spokesperson on Transport, Horace Chang...", created_at: "2014-08-30 11:07:05", updated_at: "2014-08-30 20:03:56", user_id: 1, ancestry: nil, file: "Davies-Must-Go.pdf", status: 0, slug: "chang-calls-for-immediate-removal-of-davies-jutc-m...", is_published: 0, has_eyewitness: false>, #<Post id: 21, title: "PNP Chairman expresses shock, grief at Clarke’s pa...", photo: nil, body: "Chairman of the People’s National Party (PNP), the...", created_at: "2014-08-30 13:22:05", updated_at: "2014-08-30 20:03:56", user_id: 1, ancestry: nil, file: nil, status: 1, slug: "pnp-chairman-expresses-shock-grief-at-clarke-s-pas...", is_published: 0, has_eyewitness: false>, #<Post id: 22, title: "ALGAJ Pays Tribute to the Honourable Roger Clarke", photo: nil, body: "The Association of Local Government Authorities of...", created_at: "2014-08-30 16:19:12", updated_at: "2014-08-30 20:03:56", user_id: 1, ancestry: nil, file: nil, status: 2, slug: "algaj-pays-tribute-to-the-honourable-roger-clarke", is_published: 0, has_eyewitness: false>, #<Post id: 26, title: "PNPYO saddened at passing of Roger Clarke", photo: nil, body: "The People’s National Youth Organisation (PNPYO), ...", created_at: "2014-08-30 19:50:47", updated_at: "2014-08-30 19:50:47", user_id: 1, ancestry: nil, file: nil, status: 1, slug: "pnpyo-saddened-at-passing-of-roger-clarke", is_published: 0, has_eyewitness: false>, #<Post id: 25, title: "10PP 1 on 2", photo: "1-on-1-Icon.jpg", body: "10PP gives you a lot of one on one attention that ...", created_at: "2014-08-30 17:35:17", updated_at: "2014-08-30 20:09:05", user_id: 1, ancestry: nil, file: nil, status: 0, slug: "10pp-1-on-2", is_published: 0, has_eyewitness: false>]> 
 > Post.unpublished.first
  Post Load (0.6ms)  SELECT  "posts".* FROM "posts"  WHERE "posts"."is_published" = 0  ORDER BY "posts"."id" ASC LIMIT 1
 => #<Post id: 20, title: "Chang calls for immediate removal of Davies, JUTC ...", photo: nil, body: "Opposition spokesperson on Transport, Horace Chang...", created_at: "2014-08-30 11:07:05", updated_at: "2014-08-30 20:03:56", user_id: 1, ancestry: nil, file: "Davies-Must-Go.pdf", status: 0, slug: "chang-calls-for-immediate-removal-of-davies-jutc-m...", is_published: 0, has_eyewitness: false> 
 > Post.unpublished.first.is_published
  Post Load (0.7ms)  SELECT  "posts".* FROM "posts"  WHERE "posts"."is_published" = 0  ORDER BY "posts"."id" ASC LIMIT 1
 => "no" 

有趣的是,Post表中有is_published: "yes"的1条记录永远不会被返回。

从这里可以看出:

 > p = Post.first
  Post Load (0.4ms)  SELECT  "posts".* FROM "posts"   ORDER BY "posts"."id" ASC LIMIT 1
 => #<Post id: 1, title: "Fire at Bible College in Christian", photo: nil, body: "A massive fire is now raging at the Bible College ...", created_at: "2014-08-28 08:06:19", updated_at: "2014-09-18 20:56:32", user_id: 1, ancestry: nil, file: nil, status: 0, slug: "fire-at-bible-college-in-christian", is_published: 1, has_eyewitness: true> 
 > p.is_published
 => "yes" 

2 个答案:

答案 0 :(得分:1)

检查ActiveRecord::Enum文档显示了范围的以下语法:

class Post < ActiveRecord::Base
  belongs_to :user
  enum is_published: [ :no, :yes ]

  scope :published, -> { where( is_published: Post.is_publisheds[:yes] ) }
  scope :unpublished, -> { where( is_published: Post.is_publisheds[:no]) }
end

您的查询显示您正在获取0以获得&#34;是&#34;这看起来不正确。通过此建议的更改,您应该获得yesno的正确枚举值。另外在附注中,文档说明:

  

enum属性的条件必须使用a的序数值   枚举。

答案 1 :(得分:1)

tldr; is_published: [:yes, :no]不适用于enum


枚举和使用它的范围有很多错误。

首先,您不能以这种方式使用where。你完全回避enum,只是查询列。由于您要查询整数列,Rails会将查询值转换为整数。 "yes""no"都转换为整数0,因此这些范围无效。如果您要使用where,则需要手动生成正确的整数值。对于您的模型,它看起来像这样:

Post.where(is_published: Post.is_publisheds['yes'])

第二,注意is_publisheds的非常笨拙的复数化;这是一个提示,你的枚举使用了一个坏名称。

第三,您手动制作冗余范围。 Rails已经为您enum中的每个值提供了范围,但您选择了真正的错误名称。您的模型现在有yesno范围!您可以使用Post.yesPost.no来获取已发布/未发布的记录,但这显然是错误的。

这一切都源于你基本上枚举了一个布尔这一事实。这完全忽略了这一点。如果你真的只是在一个布尔值之后,enum不合适,你就不应该使用它。只需使用布尔列,并使用where(is_published: true)where(is_published: false)编写一对合理的范围。

如果您想使用枚举,而不是使用is_published,请使用enum status: [:published, :unpublished],甚至enum publication_status: [:published, :unpublished]。这就是你所需要的一切。 Rails将查看枚举值,并为您生成您想要的两个范围,而无需您做其他工作。

整个班级看起来像这样:

class Post < ActiveRecord::Base
  belongs_to :user
  enum status: [ :published, :unpublished ]
  # No need for scopes, enum gives you published/unpublished scopes already
end