Skip to content
This repository has been archived by the owner on Jun 16, 2020. It is now read-only.

Bitmask attributes are not reset when an object is reloaded #37

Open
sferik opened this issue Jan 9, 2013 · 3 comments
Open

Bitmask attributes are not reset when an object is reloaded #37

sferik opened this issue Jan 9, 2013 · 3 comments

Comments

@sferik
Copy link

sferik commented Jan 9, 2013

Unlike normal attributes, unsaved bitmask attributes are not reset when an object is reloaded. This was very surprising to me!

def test_bitmask_attributes_reload
  user = User.create(:name => "Bruce", :roles => [:publisher, :editor])

  # Normal attribute behavior
  assert_equal "Bruce", user.name
  user.name = "Erik"
  assert_equal "Erik", user.name
  user.reload
  assert_equal "Bruce", user.name

  # Bitmask attribute behavior (very surprising!)
  assert_equal [:publisher, :editor], user.roles
  user.roles << :writer
  assert_equal [:publisher, :editor, :writer], user.roles
  user.reload
  assert_equal [:publisher, :editor], user.roles
  #1) Failure:
  # <[:publisher, :editor]> expected but was
  # <[:publisher, :editor, :writer]>.
end
@spemmons
Copy link
Collaborator

I've found the same problem and have constructed a test for it to add to the project that will currently fail:

      should "update bitmask values currently in the database with reload" do
        instance1 = @campaign_class.create(:medium => [:web, :print])
        instance2 = @campaign_class.find(instance1.id)
        assert instance1.id == instance2.id
        assert instance1.object_id != instance2.object_id
        assert instance1.update_attributes(:medium => [:email])

        assert_equal [:web, :print],instance2.medium

        instance2.reload
        assert_equal [:email],instance2.medium
      end

However, I'm not sure what the fix is. In reviewing the AR code, there doesn't appear to be a clear way to detect this situation and refresh the ValueProxy objects used to cache the current set of symbols corresponding to the integer values of the model.

Any suggestions?

@spemmons
Copy link
Collaborator

So, to answer my own question: We could simply overload the "reload()" method for the model. That *should be okay. I'll work up a proposed solution and submit...

spemmons added a commit that referenced this issue Mar 25, 2013
…en overriding ActiveRecord::Base#reload and test it (issue #37)
joelmoss added a commit that referenced this issue Mar 25, 2013
fix for issue #37 where reloading a model doesn't refresh the ValueProxy objects
@justqyx
Copy link

justqyx commented Mar 28, 2017

Hi @spemmons @sferik

I found it is not compatible with activerecord 4.2.7.1. and it should overwrite the reload method in the included block like this.

included do
  alias_method :reload_without_bitmasks, :reload
  def reload(options = nil)
    super_result = reload_without_bitmasks(options)
    self.class.bitmasks.keys.each { |attribute| send("reload_#{attribute}") }
    super_result
  end
end

And I think it should be auto included by ActiveRecord::Base, it should be included by explicit declaration as follow

class Example < ActiveRecord::Base
  extend BitmaskAttributes
  # ...
end

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants