#225 ✓resolved
Jan Molic

DataMapper::Base class inside another class doesn't work

Reported by Jan Molic | April 30th, 2008 @ 07:29 AM

This doesn't work as expected, because it is inside a Foo class:

class Foo
  class Author < DataMapper::Base
    has_many :articles
  end
  class Article < DataMapper::Base
    belongs_to :author
  end
end

------

I looked for a solution, found two problems:

1. in associations/has_n_association.rb

1.1. There is a problem with Kernel.get_const() in associated_constant(). It expect only "Foo" or "Author", but fails when get "Foo::Author".

The solution is to split the string constant by :: and start from the top Object:

def associated_constant
  @associated_constant || begin
    klass = Object
    associated_constant_name.to_s.split( /::/ ).each { |const_name|
      const_name = const_name.to_sym
      if klass.const_defined?( const_name )
        klass = klass.const_get( const_name )
      else
        raise "constant #{klass.to_s}::#{const_name} missing"
      end
    }
    @associated_constant = klass
  end
end

1.2. Then if :class or :class_name is not defined, associated_constant_name() guess it from @association_name. This works when Article or Author is the top class, but not if it is inside Foo. The solution could be to use the same parent classes as the @constant and guess it like this

 def associated_constant_name
    #...
    else
      @associated_constant_name = @constant.to_s.split( /::/ )[0..-2].join( '::' ) + '::' + Inflector.classify (@association_name)
    end
    #...
 end

2. in dependency_queue.rb

In resolve! there is the same problem as in 1.1. The solution could be again to start from the top:

    def resolve!
      @dependencies.each_pair do |class_name, callbacks|
        klass = Object
        class_name.split( /::/ ).each { |const_name|
          const_name = const_name.to_sym
          if klass.const_defined?( const_name )
            klass = klass.const_get( const_name )
          else
            raise "constant #{klass.to_s}::#{const_name} missing"
          end
        }
        # klass found
        callbacks.each do |b|
            b.call(klass)
        end
        callbacks.clear
      end
    end

Maybe it would be better to create Object.full_const_get() which could resolve 'Foo::Author' (I think it is in more places)

Comments and changes to this ticket

  • Sam Smoot

    Sam Smoot May 2nd, 2008 @ 04:34 AM

    • Assigned user set to “Scott Bauer”

    Nested constants won't be fully back-ported to 0.3.x, but is targeted for resolution in 0.9.x. Some specs have already been written and updates made.

    If you would like to submit a patch I will be happy to apply it to 0.3.x though.

    In the mean-time, we can make the simple change you suggest above.

    Scott, please back-port http://github.com/sam/dm-core/tr... and make the above tweak to SVN DM on Rubyforge.

    Thanks, -Sam

  • Sam Smoot

    Sam Smoot May 8th, 2008 @ 04:43 PM

    • Assigned user changed from “Scott Bauer” to “Adam French”

    Adam, please apply (to 0.3.x SVN) and close this out.

  • Sam Smoot

    Sam Smoot May 20th, 2008 @ 08:34 PM

    Adam, didn't you take care of this already? Can we close it out?

  • Sam Smoot

    Sam Smoot May 20th, 2008 @ 08:37 PM

    • State changed from “new” to “resolved”

    Adam sayeth it's done.

Please Sign in or create a free account to add a new ticket.

With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.

New-ticket Create new ticket

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

People watching this ticket

Pages