map(&:id)工作但不拔(:id)

时间:2015-08-06 09:04:37

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

在我的部分代码中,我需要获取用户的ID,但pluck不会抓取它们。只有map(&:id)才能做到。我想知道为什么。

我写了一个快速而又脏的代码块来查找发生了什么

  def remove_users user_ids
    p users_to_remove.class
    users_to_remove = self.users.where(id: user_ids)
    if users_to_remove.present?
      self.users -= users_to_remove
      self.save

      p users_to_remove.class
      p users_to_remove
      Rails::logger.info "\n#{users_to_remove}\n"
      users_to_remove_map = users_to_remove.map(&:id)
      p users_to_remove_map
      Rails::logger.info "\nmap id: #{users_to_remove_map}\n"
      users_to_remove_pluck = users_to_remove.pluck(:id)
      p users_to_remove_pluck
      Rails::logger.info "\npluck id: #{users_to_remove_pluck}\n"
      #...
    end
    self.user_ids
  end

谁在我的test.log中返回

#<User::ActiveRecord_AssociationRelation:0x007fb0f9c64da8>


map id: [144004]

   (0.3ms)  SELECT "users"."id" FROM "users" INNER JOIN "groups_users" ON "users"."id" = "groups_users"."user_id" WHERE "groups_users"."group_id" = $1 AND "users"."id" IN (144004, 144005)  [["group_id", 235819]]

pluck id: []

在我的测试中

User::ActiveRecord_AssociationRelation
User::ActiveRecord_AssociationRelation
#<ActiveRecord::AssociationRelation [#<User id: 144004, created_at: "2015-08-06 08:55:11", updated_at: "2015-08-06 08:55:11", email: "user_2@test.com", token: "rpf5fqf5bs1ofme6aq66fwtcz", reset_password_token: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, disabled: false, first_name: "John_2", last_name: "Rivers_4", is_owner: false, organisation_id: 235826, encrypted_password: "$2a$04$8ev1j...f6ICL.ezS....", reset_password_sent_at: nil, default_language: nil, uid: nil, api_key: "rmhh...noyn">]>
[144004]
[]

奇怪的是。我有id的用户。 map可以获得它们。 pluck没有。

我也不了解sql日志。如何在sql日志中没有任何选择的情况下获得map id结果?缓存?

2 个答案:

答案 0 :(得分:3)

pluck无法在数组上运行,它适用于ActiveRecord::Relation,其目标是避免进行完整查询以仅获取ID。

从db中检索完所有列后,您只需map即可。

您在执行self.users -= users_to_remove时创建数组,或者甚至在执行.present?时创建数组,因为您应该使用.exists?

答案 1 :(得分:1)

这一行:

users_to_remove = self.users.where(id: user_ids)

不会立即触发SQL查询。只要您需要这些用户的某些详细信息,它就会发送请求。它将结果缓存在SQL缓存中(因此当同一个请求再次进入DB时,它会被Rails截获并且永远不会到达数据库)。

所以当你打电话时:

users_to_remove.map(&:id)

它使用缓存的结果。但是当你使用

users_to_remove.pluck(:id)

它重新获取结果,因为实际的SQL查询不同。 #mapSELECT * FROM ...#pluckSELECT id FROM...。当查询到达数据库时,ID不属于“自我”。不久之后(你之前就删除了它们),所以它们不会被退回。