solnic / virtus

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

Attribute value from super implementation? #250

Closed nybblr closed 10 years ago

nybblr commented 10 years ago

I have a REST based adapter for a User resource. When you ask it for user.created_at, it queries the API if necessary and returns the value. It also handles user.created_at=.

I'd like like to add Virtus on top of the setter/getter I have defined so I can coerce attributes coming from the JSON API (in this case, to a Date) -- is there anyway to do this? It seems like Virtus just creates its own ivars, but I'd like for it to use the get/set interface I've defined as the source.

Thanks! ~ Jonathan

elskwid commented 10 years ago

@nybblr, it sounds like you aren't using Virtus already. If you only want to coerce that single attribute, perhaps you could just use Coercible in your object.

nybblr commented 10 years ago

Thanks @elskwid, that looks pretty close to what I need. I have several other fields (~20) that need it too so I was hoping it would save me the tedium.

elskwid commented 10 years ago

Ah, well, you didn't say that in your issue. :wink:

We've recently used Virtus to do exactly what you describe. What we did was actually wire up Virtus to use a symbol for the default which makes it use a method. It might require some renaming on your part but it might work. I'm sure @solnic would have some ideas as well. (Something else to keep your eye on is Morpher. It is crazy powerful but lacking in documentation at the moment so you'll have to dig around the specs.

Here's an example of what we did in that project of ours:

class Product
  attribute :description, String,   default: :_description
  attribute :category,    [String], default: :_category
  attribute :color,       String,   default: :_color

  def _description
    row[:"description"]
  end

  def _category
    if row[:"categories"].present?
      row[:"categories"].split(",").map(&:strip)
    end
  end

  def _color
    row[:"item color"]
  end
end

Shortly after doing a bunch of these we saw the pattern and did something like this:

class Product
  include Connections
  include Row

  connect_attributes do
    description, "description", String
    category,    "categories",  [String]
    color,       "item color",  String
  end

  def _categories
    row_hash[:"categories"].split(",").map(&:strip)
  end
end
solnic commented 10 years ago

I would use a proxy object that would wrap "plain" virtus objects and handle lazy-loading through API there.

I think I have another mission for 2014 - un-active-recordify your minds ;)

elskwid commented 10 years ago

I would like to say that the examples above don't touch an API. The API data gets handed to them, this is an example of how we handled wiring up Virtus for lots of attributes.

See what you did @solnic? You made me all defensive.

solnic commented 10 years ago

I'm closing this one as it doesn't seem like there's anything we could do in virtus' itself.