solnic / virtus

[DISCONTINUED ] Attributes on Steroids for Plain Old Ruby Objects
MIT License
3.77k stars 228 forks source link

Using Virtus with Modules (multiple layer include) - calling attributes does not return all declared attributes #260

Closed spoptchev closed 10 years ago

spoptchev commented 10 years ago

I have the following structure:

module BaseAddress
  include Virtus.module
  attribute address1, String
  attribute ...
end

module ExtendedAddress
  include BaseAddress

  attribute ...
  attribute ...
end

module SomethingElse
  include Virtus.module
  attribute ...
end

class Entity
  include Virtus.model

  attribute ...
  attribute ...

end

class ExtendedEntity < Entity
  include ExtendedAddress, SomethingElse
end

extended_entity = ExtendedEntity.new
extended_entity.attributes

The last call to extended_entity.attributes does not return all declared attributes. The attributes from BaseAddress are missing. But I can still access the address1 attribute.

extended_entity.attributes # -> address1 is not in hash
extended_entity.address1 = "address1" # -> still works

You always get the attributes of the last included module and those that are declared on the class.

tjstankus commented 10 years ago
require 'virtus'

module BaseAddress
  include Virtus.module
  attribute :address1, String
end

module ExtendedAddress
  include BaseAddress
end

module SomethingElse
  include Virtus.module
end

class Entity
  include Virtus.model
end

class ExtendedEntity < Entity
  include ExtendedAddress, SomethingElse
end

extended_entity = ExtendedEntity.new(address1: '666 Pleasant Lane')
puts extended_entity.attributes # => {:address1=>"666 Pleasant Lane"}

Is it because you did not initialize ExtendedEntity with a hash as above?

spoptchev commented 10 years ago

No, try this:

# just copy paste it into a file
require 'virtus'

module BaseAddress
  include Virtus.module
  attribute :address1, String
  attribute :address2, String
end

module ExtendedAddress
  include BaseAddress

  attribute :base_address1, String
  attribute :base_address2, String
end

module SomethingElse
  include Virtus.module
  attribute :something_else1, String
  attribute :something_else2, String
end

class Entity
  include Virtus.model

  attribute :entity1, String
  attribute :entity2, String

end

class ExtendedEntity < Entity
  include ExtendedAddress, SomethingElse
end

extended_entity = ExtendedEntity.new(entity1: 1, something_else1: 'test', something_else2: 'testme')
puts extended_entity.attributes

In this case something_else1 and something_else2 are not in the attributes hash.

solnic commented 10 years ago

It's the same issue (probably) as described in #274 so I'll fix it there and it should fix this one too