The following is going to start off sounding Rails-specific, but if you
read on, it turns into a Ruby question.
I’m in an interesting situation recently where it was suggested
internally that we introduce a concept in our Rails application somewhat
similar to Java’s entity reference:
http://docs.oracle.com/javase/1.5.0/docs/api/org/w3c/dom/EntityReference.html
But, really, the intent was the following:
- The normal version of a model had all its fields and was writable.
- The “ref” version of a model exposed a subset of its fields for
deserialization into JSON and would be read-only.
Beyond that, the desire was to have a concept similar to a model that
has some attributes and associations that can be both
updated/mass-assigned and deserialized into JSON, but also have some
attributes write only or de-serialize only (read-only). I posed that to
the Rails core list and it looks like Roar’s representers might work for
that. The other thing they want is to allow patch updates easily via
JSON service in a way that easily works with AngularJS, Ember, etc. to
allow certain columns of certain rows to be updated in the DB together
as a server-side DB transaction in various tables at once without
overwriting other columns in other columns of those same records. (In
addition, internally we wanted the JSON API in Rails to not require
_attributes at the end of JSON key names for attributes and to allow
passing in child JSON for association names and only have it look at the
id attribute in child JSON from an update to change associations vs.
using accepts_nested_attributes_for, but I implemented that already in a
project called restful_json in GitHub.)
To try to handle #1 and #2 above, at first I tried to implement by just
subclassing model and then having the model class have an association to
another model and that other model have an association to the “ref”
model instead of back to the first model, but I ran into a strange bug
when using subclass there (not a Ruby bug, but possibly an A.R. bug):
I ended up with something similar to the attached example.rb (split into
multiple files).
This may go away if we switch to Roar or similar, but for now, having a
separate class that differs only slightly from the original, it seems
like it would be helpful to be able to define something in Ruby that
would act like a class name pattern matcher so that when I referred to a
“FooRef” class, it would take the “Foo” class and add to it. This would
substantially reduce the number of files we would have to have to order
to have the concept of “*Ref” model classes.
An alternate way that would use existing Ruby and just extend
ActiveRecord to redefine associations such that you could pass options
into them that would try to override Rails class_accessors like we are
doing currently, e.g.:
self._accessible_attributes[:default] = [:name]
But, I was just curious- is there an existing way to hook into Ruby such
that you can say something like “if anyone asks for a classname that
ends in ‘Ref’ then take the class matching the first part of the name
and include or extend this and that”? Then you wouldn’t even have to
define the *Ref classes- they would be created and instantiated
dynamically.
I know that in this case, that probably wouldn’t work, since there would
be fields that would be specific to each Ref that at the very least
would have to be defined as part of the classname like:
“SomeRef{options…}”
where options would not be for initialize, but something available in
the scope of “Some” class’s block that it could use, perhaps.