Created
May 15, 2010 00:31
-
-
Save rbranson/401870 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # | |
| # To use this, drop it into your lib directory and add a require to an initializer | |
| # in config/initializers. | |
| # | |
| # This little extension to Mongoid allows belongs_to_related associations to | |
| # have an "in" option, which will traverse the object graph to find the | |
| # collection that will contain the related model object. | |
| # | |
| # The goal is to allow relations to be created that reference objects embedded | |
| # in documents, instead of only objects that are contained within collections. | |
| # | |
| # For instance, if you have an object model defined as such (totally contrived): | |
| # | |
| # class Blog | |
| # ... | |
| # embeds_many :authors | |
| # embeds_many :posts | |
| # end | |
| # | |
| # class Author | |
| # ... | |
| # embedded_in :blog, :inverse_of => :authors | |
| # embeds_many :pictures | |
| # end | |
| # | |
| # class Picture | |
| # ... | |
| # embedded_in :author, :inverse_of => :pictures | |
| # end | |
| # | |
| # class Post | |
| # ... | |
| # embedded_in :blog, :inverse_of => :posts | |
| # belongs_to_related :author, :in => :blog | |
| # end | |
| # | |
| # post.author can now be used to relate to any author within Blog. The accessor | |
| # uses the blog method on the Post instance and looks for an authors method on | |
| # whatever the blog method returned. | |
| # | |
| # For relations on objects that are embedded several layers deep, an array can | |
| # be passed to :in, and it will traverse the objects, calling the passed methods | |
| # in order to arrive at the object with the accessor that will return the embedded | |
| # collection that will contain the object we're looking for. Phew. | |
| # | |
| module Mongoid | |
| module Associations | |
| class Options | |
| def in | |
| @attributes[:in] | |
| end | |
| end | |
| end | |
| end | |
| module Mongoid | |
| module Associations | |
| class BelongsToRelated < Proxy | |
| def initialize(document, foreign_key, options, target = nil) | |
| @options = options | |
| if target == nil and options.in | |
| if options.in.is_a?(Array) | |
| # If in is an array, traverse the object graph to find the | |
| # right container. | |
| container = options.in.inject(document) do |obj, sym| | |
| obj.send(sym) | |
| end | |
| else | |
| # If not, just access it directly | |
| container = document.send(options.in) | |
| end | |
| okdcpts = options.klass.name.downcase.pluralize.to_sym | |
| # Look for a has_many style plural method | |
| if container.respond_to?(okdcpts) | |
| @target = container.send(okdcpts).find(foreign_key) | |
| else | |
| raise "belongs_to_related :in target does not contain the method :#{okdcpts.to_s}" | |
| end | |
| else | |
| @target = target || options.klass.find(foreign_key) | |
| end | |
| extends(options) | |
| end | |
| end | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment