Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoid: 'update_attribute' with [models, ...] vs with [model_ids, ...]

I was writing some tests and I ran into something I'm trying to understand.

What is the difference underneath when calling:

.update_attributes(:group_ids, [group1.id, group2.id])

vs

.update_attributes(:groups, [group1, group2])

These 2 models in question:

group.rb

class Group
  include Mongoid::Document
  has_and_belongs_to_many :users, class_name: "Users", inverse_of: :groups
end

user.rb

class User
  include Mongoid::Document
  has_and_belongs_to_many :groups, class_name: "Group", inverse_of: :users
end

test code in question:

g1 = create(:group)
u1 = create(:user, groups: [g1])
g1.update_attribute(:users, [u1])
# at this point all the associations look good
u1.update_attribute(:group_ids, [g1.id])
# associations looks good on both sides when i do u1.reload and g1.reload
u1.update_attribute(:groups, [g1])
# g1.reload, this is when g1.users is empty and u1 still has the association

Hope I made sense, thanks

like image 357
pk1m Avatar asked Aug 21 '15 01:08

pk1m


1 Answers

  1. Are all your attributes white listed properly?

Without schema for the models, your join object, and the actual tests I'm grasping at straws, but based purely on that example my guess would be that the first model contains an attribute that is mapping to an unintended field on your second model, and overwriting it when you pass an entire object, but not when you specify the attribute you want updated. Here's an example: (I'm not assuming you forgot your join table, I'm just using that because its the first thing that comes to mind)

so we create 2 models, each that have a field that maps to user_id

group.create(id:1, user_id:null)
group_user.create(id:1, group_id: 1, user_id:null)

group.update_attributes(user_id: (group_user.id)) 

So at this point, when you call group.users, it checks for a user with the id of 1, because that's the id of the group_user you just created & passed it, and assuming you have a User with that ID in your database, the test passes.

group_user.update_attributes(group_id: group.id) 

In this case the method ONLY updates group_id, so everything still works.

group_user.update_attributes(group_id: group, user_id: group) 

In this case you pass an entire object through, and leave it up to the method to decide what fields get updated. My guess is that some attribute from your group model is overwriting the relevant attribute from your user model, causing it to break ONLY when NO user_ids match whatever the new value is.

Or an attribute isn't white listed, or your test is wonky.

like image 129
Benjamin Linville Avatar answered Nov 15 '22 09:11

Benjamin Linville