Dalia William
Dalia William

Reputation: 89

Setting an attribute in mongoid

I am trying to set the attribute flag to false like this:

Model.where(:s_id => s_id).flag = false 

(I have s_id) but it didn't work and this one didn't work too :

Model.find(s_id).flag = false

Any help??

Upvotes: 1

Views: 618

Answers (2)

blm
blm

Reputation: 2466

While theTRON’s answer is correct, another part of the problem is that Model.find(id) returns the instance of Model with the given id (or throws an exception if there isn’t one), so immediately setting an attribute works (but isn’t persisted without doing something to do so as theTRON points out), while Model.where(...) returns a Criteria. For example:

$ rails c
[1] pry(main)> s_id="..."
[2] pry(main)> User.find(s_id)
=> #<User _id: BSON::ObjectId('...'), name: "User 1">
[3] pry(main)> User.find(s_id).name = "Some other user"
=> "Some other user"

User.find is returning a User instance, so you can set attributes on it. However:

[4] pry(main)> User.where(_id: s_id)
=> #<Mongoid::Criteria
  selector: {"_id"=>BSON::ObjectId('...')}
  options:  {}
  class:    User
  embedded: false>
[5] pry(main)> User.where(_id: s_id).name = "Someone else"
NoMethodError: undefined method `name=' for #<Mongoid::Criteria:0x00007feb9c04ec48>

User.where is returning a Criteria which doesn’t have a name attribute. Instead you can do something like:

[5] pry(main)> User.where(_id: s_id).first.name = "Someone else"
=> "Someone else"

That’s because Criteria.first returns the first instance. Once you have an instance, you can again set attributes.

Of course that’s just setting the attribute in memory, you still need to persist it (or set it in such a way it’s persisted automatically, theTRON’s answer covers that).

I’ve used the rails console just because it’s an easy way to demonstrate what’s going on, but the same thing goes on in regular ruby code.

Upvotes: 0

theTRON
theTRON

Reputation: 9659

The problem with your code is that you've changed the flag attribute, but not saved the document afterwards. There's lots of different ways you can handle this, most of which are detailed in the persistence section of the documentation.

If you're only updating one model, and you have the ID, you can use the update_attribute method:

Model.find(id).update_attribute(:flag, false)

The update_attribute method updates the attribute (obviously) but then also calls save on the document, persisting the changes in the database. You could achieve this the long way by doing:

m = Model.find(id)
m.flag = false
m.save

Alternatively, if you're wanting to update a set of models, from a criteria (like the where method), you can use update_all:

Model.where(:flag => true).update_all(:flag => false)

Upvotes: 2

Related Questions