Rails: Sanity check. Should I set model attributes like this?

ruby
rails

#1

My brain is shutting down. I think I need sugar. Sorry for having to ask such a basic question but I’ve lost the ability to think for myself!

Please could someone tell me if I’m doing this the right way? Can I set a model’s attribute by assigning a value to a class attribute like so:

class MailBox < ApplicationRecord
  ...

  def reset_message_count
    self.message_count = 0
  end
end

My tests tell me it’s okay. But I’m doubting myself and can’t find a references that says it’s the way to do it.

Why does the above work and not the following?

class MailBox < ApplicationRecord
  ...

  def reset_message_count
    update_attribute(message_count: 0)
  end
end

#2
class MailBox < ApplicationRecord
  ...

  def reset_message_count
    self.message_count = 0
  end
end

This isn’t setting a class attribute. The context of self matters. In this context, self refers to the instance of the Mailbox class. Since there’s an accessor or a column named message_count, you’re able to set its value.

Furthermore, there’s a big difference between the two pieces of code. In the first snippet, you’re changing the value of an attribute of an in-memory instance. Nothing is persisted to the database. The second snippet attempts to update the value of the column in the database. You didn’t explain why the second snippet doesn’t work, so I can’t help until you do.


#3

Let me shortly explain the difference between the two. The first

self.message_count = 0 

will set the value of the attribute to zero, but does not save it to the database. Not sure if that is required, I would assume it would be.

The second updates the database, but does not update the value of the attribute in memory. This is probably why your tests fail. Let me explain, if your test looks something like

 context "resetting the message count" do 
   before do 
     @mailbox.reset_message_count
   end 
   it "has set message count to zero" do 
     expect(@mailbox.message_count).to eq(0)
   end 

the test will fail. So to alleviate this, I propose two alternatives that will do the same thing, 1) set the message-count, and 2) save to the database

Alternative 1:

   self.message_count = 0 
   self.save 

Alternative 2:

   self.update_attribute message_count: 0 
   self.reload 

I hope I understood your question/problem correctly, and this explains the behaviour you are experiencing.