问题
In part of my code I need to grab users's id but pluck doesn't grab them. Only map(&:id) can do it. I was wondering why.
I've wrote a quick and dirty block of code to find what's happen
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
Who return in my 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: []
And in my test
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]
[]
The strange thing is. I have user with id. map can get them. pluck not.
I don't understand sql log also. How can I get map id result without any select in sql log? Caching ?
回答1:
This line:
users_to_remove = self.users.where(id: user_ids)
Doesn't fire off SQL query immediately. It sends the request whenever you need some details of these users. And it caches the result in SQL cache (so when the same request goes to DB again, it intercepted by Rails and never reaches the database).
So when you call:
users_to_remove.map(&:id)
It uses that cached result. But when you use
users_to_remove.pluck(:id)
It re-fetches the result, because the actual SQL query differs. With #map it is SELECT * FROM ..., and with #pluck it's SELECT id FROM.... And when query reaches the database, IDs doesn't belong to 'self' any longer (you deleted them right before that), so they aren't returned.
回答2:
pluck doesnt work on an array, it works on an ActiveRecord::Relation, it's goal is to avoid to make a full query to only get the ids.
Once you've retrieved all columns from db, you can just map what you need.
You create the array when you do self.users -= users_to_remove, or maybe even when you do .present?, since you should use .exists?
来源:https://stackoverflow.com/questions/31851349/mapid-work-but-not-pluckid