Here is my story:
I have two models that represent people or groups that can "own" things. One is Person, the other is Group. Then, I have stuff that can be owned by either a Person or a Group, like a Post for instance:
class Post belongs_to :owner, :polymorphic => true end
class Person has_many :posts, :as => :owner end
class Group has_many :posts, :as => :owner end
For my own reasons, I have a form where I create/edit a Post, including selecting the owner (yes, it may seem odd to have to "select" an owner, but that is the way it is). I first tried using the 'select' form helper, attaching it to the owner attribute:
...<%= f.select :owner, @owners.map { |o| [o.displayname, o.id] } %>...
I soon realized my obvious mistake, I need both the id AND type for the owner. So, I created a read/write custom attribute for Post:
def owner_string "#{owner.id}:#{owner.class.base_class}" # base_class just in case owner using STI end def owner_string=(ref) i, t = ref.split(':') owner = eval(t).find(i.to_i) end
Then I updated my view code to use my pseudo-attribute: owner_string instead...
...<%= f.select :owner_string, @owners.map { |o| [o.displayname, "# {o.id}:#{o.class.base_class}"] } %>...
This seems to work all right. However, I've got a lot of models that can be "owned" just like the Post class. I've also got polymorphism going on in a few other places.
So, to avoid repetition, my next step was to write some code, throw it in config/initializers, and use it to extend ActiveRecord::Base. I'll include the code at the bottom and explain the problem here. My code adds an instance method to AR::Base called "polymorphic" that returns, for that instance a string holding the instances id and type (the base AR type). Also, there is a class AR::Base method also named "polymorphic" that takes a string containing an id/type as previously shown above ("id:type") and loads the instance if it exists.
Finally I *tried* to "override" (not sure if this is the correct ruby term for this) the belongs_to macro method so that, when called (in my model definitions) it will first perform the default behavior, then it will detect if the belongs_to call is for a polymorphic association, and if so, also create pseudo attribute methods such as "owner_string" and "owner_string=(val)" (replacing "owner" w/the association name, of course) so that I can immediately have these "attributes" as I demonstrated above.
That last part, "overriding" belongs_to is what I can't make work. The following code works with the exception of the alias_method_chain call. There doesn't appear to be a method named belongs_to in AR::Base.
So, anyone know how things really work here? How, perhaps, I can get this to work? I also welcome general commentary/insights as to how I can better deal with any of the above issues.
I'm very grateful, in advance, to anyone who actually reads this whole thing and responds.
WARNING: Long code listing (excuse the verbose param-checking used for debugging) ---------- file: config/initializers/polymorphic_references.rb