define_schema for Active Resource

So, following on from the original discussion-thread here: http://groups.google.com/group/rubyonrails-core/browse_thread/thread/8600da28a92d83ba

I've built some baseline functionality for defining a schema for an Active Resource.

Code available as a patch here: http://pastie.org/743842

and a more-readable combined diff here: http://pastie.org/743843

What you can now do is this:

  class FlickrPhoto << ActiveResource::Base

    define_schema do |s|       s.string :photo, :title       s.integer :width, :height       s.float :some_other_attribute       s.attribute 'and_another', 'string'     end

    validates_presence_of :photo     validates_numericality_of :width, :height   end

  # this works   my_photo = FlickrPhoto.new(:photo => 'photo_stream_here', :title => 'eben', :tags => ['cat'])   my_photo.valid? # => true   my_photo.save # => true   my_photo.photo # 'photo_stream_here'

  # and now, so does this:   new_photo = FlickrPhoto.new()   new_photo.respond_to? :photo # => true   new_photo.photo # => nil   new_photo.valid? # => false

  new_photo.known_attributes # => ['photo', 'title', 'height', 'width', 'some_other_attribute', 'and_another']

  # and if you fetch and existing one:   a_photo = FlickrPhoto.find(1) # <FlickrPhoto><photo>abcdef</

<width>123</width><instance_attribute>456</instance_attribute></

  a_photo.photo # => 'abcdef'   a_photo.width # => '123' # note: still a string   a_photo.instance_attribute # => '456' # note: also a string

  a_photo.known_attributes # => ['photo', 'title', 'height', 'width', 'some_other_attribute', 'and_another', 'instance_attribute']

  new_photo.respond_to? 'instance_attribute' # => false (because it's not a known_attribute)

More details on what/how in the rdoc for define_schema :slight_smile:

To summarise: 1) You can define a schema using 'define_schema' and passing a block, or passing a hash to 'schema=' 2) this populates a set of 'known_attributes' that are added to the list of attributes currently on an instance (if there's no schema, this means that the known_attributes equals the existing attributes on the instance - as it always has done). 3) known attributes will return 'true' to a 'respond_to?' and will not cause a 'NoMethodError' if invoked 4) it will also store the 'attribute type' against each attribute - currently this does nothing... but my next step is to add a typecast based on this, along with "attributes_before_typecast" ala Active Record. This will be extremely useful for integer values as I've found my own code peppered with "to_i" checks for attributes that I already know are meant to be integers :stuck_out_tongue: 5) an extension will also allow us to pass in options. The only sensible one that I can see so far is ":default => 'blah') which will, of course, set up known attributes with their given defaults - unless otherwise specified.

Cheers, Taryn

Looks good.

DHH would recommend using instance_eval for the schema block just to clean up the "s."

Ah ok. I wasn't sure how to do that, and figured I'd follow the 'create_table' syntax. I'll have a go at the instance_eval version though. Always good to learn new stuff. :slight_smile: Cheers, Taryn