Model with more than one t_belongs_to association causes error #35

Closed
raphaelcm opened this Issue Mar 26, 2012 · 16 comments

Projects

None yet

2 participants

@raphaelcm

Steps to reproduce:

  1. Create a model with two t_belongs_to associations, e.g.:
class TenacityTest
  include Mongoid::Document
  include Mongoid::Timestamps
  include Mongoid::Slug
  include Tenacity

  t_belongs_to :organization
  t_belongs_to :avatar
end
  1. Try to create an instance of that class, e.g:
ree-1.8.7-2011.03 :031 > tt = TenacityTest.new

Expected behavior: tt object should have getters and setters for both organization and avatar.

Actual behavior:

NoMethodError: undefined method `_t_id_type' for #<Class:0xa82c79c>
    from /var/bundler/turtle/ruby/1.8/gems/activerecord-3.0.7/lib/active_record/base.rb:1009:in `method_missing'
    from /var/bundler/turtle/ruby/1.8/gems/tenacity-0.5.4/lib/tenacity/orm_ext/helpers.rb:9:in `id_class_for'
    from /var/bundler/turtle/ruby/1.8/gems/tenacity-0.5.4/lib/tenacity/orm_ext/mongoid.rb:94:in `_t_initialize_belongs_to_association'
    from /var/bundler/turtle/ruby/1.8/gems/tenacity-0.5.4/lib/tenacity/associations/belongs_to.rb:36:in `initialize_belongs_to_association'
    from /var/bundler/turtle/ruby/1.8/gems/tenacity-0.5.4/lib/tenacity/class_methods.rb:274:in `t_belongs_to'
    from /home/me/app/models/tenacity_test.rb:8
    from /var/bundler/turtle/ruby/1.8/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:454:in `load'
    from /var/bundler/turtle/ruby/1.8/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:454:in `load_file'
    from /var/bundler/turtle/ruby/1.8/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:596:in `new_constants_in'
    from /var/bundler/turtle/ruby/1.8/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:453:in `load_file'
    from /var/bundler/turtle/ruby/1.8/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:340:in `require_or_load'
    from /var/bundler/turtle/ruby/1.8/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:491:in `old_load_missing_constant'
    from /home/me/config/initializers/rails_patches.rb:10:in `load_missing_constant'
    from /var/bundler/turtle/ruby/1.8/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:183:in `const_missing'
    from /var/bundler/turtle/ruby/1.8/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:181:in `each'
    from /var/bundler/turtle/ruby/1.8/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:181:in `const_missing'
    from (irb):28ree-1.8.7-2011.03 :029 > tt = TenacityTest.new

NOTE: TenacityTest works just fine with only one t_belongs_to association.

@raphaelcm

Using Tenacity 0.5.4. Same issue occurs for MongoMapper-backed models. Haven't tested with any others.

@jwood
Owner
jwood commented Mar 26, 2012

Hi.

Could you please provide the class definitions for organization and avatar?

Thanks,
John

@raphaelcm

They're both standard-issue ActiveRecord models that inherit from ActiveRecord::Base:

class Avatar < ActiveRecord::Base

  has_attached_file (paperclip file parameters)

end

class Organization < ActiveRecord::Base

  # some vanilla AR associations and validations

end
@jwood
Owner
jwood commented Mar 28, 2012

The Tenacity module needs to be included in the target models as well. It adds some behavior to the models that allows tenacity to figure out how to setup the foreign keys.

Please include Tenacity in your Avatar and Organization models and see if that fixes the problem.

@raphaelcm

Thanks, that resolved that but now I face a different issue:

class TenacityTest
  include Mongoid::Document
  include Mongoid::Timestamps
  include Mongoid::Slug
  include Tenacity

  t_belongs_to :organization #works
  t_belongs_to :avatar #works
  t_belongs_to :slideshow, :class_name => "Community::Slideshow" #fails
end

Slideshow is a standard AR model, the only difference is the namespacing and a custom table name.

class Community::Slideshow < ActiveRecord::Base
  include Tenacity
  set_table_name 'community_slideshows'

  #...

end

Here's the exception:

> TenacityTest.new
NameError: wrong constant name Community::Slideshow
    from /var/bundler/turtle/ruby/1.8/gems/tenacity-0.5.4/lib/tenacity/association.rb:73:in `const_get'
    from /var/bundler/turtle/ruby/1.8/gems/tenacity-0.5.4/lib/tenacity/association.rb:73:in `associate_class'
    from /var/bundler/turtle/ruby/1.8/gems/tenacity-0.5.4/lib/tenacity/orm_ext/helpers.rb:9:in `id_class_for'
    from /var/bundler/turtle/ruby/1.8/gems/tenacity-0.5.4/lib/tenacity/orm_ext/mongoid.rb:94:in `_t_initialize_belongs_to_association'
    from /var/bundler/turtle/ruby/1.8/gems/tenacity-0.5.4/lib/tenacity/associations/belongs_to.rb:36:in `initialize_belongs_to_association'
    from /var/bundler/turtle/ruby/1.8/gems/tenacity-0.5.4/lib/tenacity/class_methods.rb:274:in `t_belongs_to'
    from /my/app/models/tenacity_test.rb:9
    ...
@jwood
Owner
jwood commented Apr 3, 2012

I just pushed a commit that should address this issue

c24a35a

Would you mind testing it out? If it solves your issue, I'll cut a new version of Tenacity.

@raphaelcm

Thanks for such a fast response! I'll test it out now. Hopefully I can familiarize myself enough with the codebase to contribute some fixes down the line.

@raphaelcm

Ok, just tested it out. Getting a different error now. Using same class definitions as above:

> t = TenacityTest.new
 => #<TenacityTest _id: 4f7b50c5e628f82349000005, created_at: nil, updated_at: nil, community/slideshow_id: nil, avatar_id: nil, _type: nil, organization_id: nil>
> t.avatar = Avatar.last
> t.organization = Organization.last
> t.slideshow = Community::Slideshow.last
> t
 => #<TenacityTest _id: 4f7b50c5e628f82349000005, created_at: nil, updated_at: nil, community/slideshow_id: 80145, avatar_id: 280, _type: nil, organization_id: 15189>
> t.valid?
 => true 
> t.save
NoMethodError: undefined method `find_by_id' for #<Class:0xab501a8>
    from /var/bundler/turtle/ruby/1.8/gems/activerecord-3.0.7/lib/active_record/base.rb:984:in `method_missing'
    from /var/bundler/turtle/ruby/1.8/bundler/gems/tenacity-c24a35aeb57f/lib/tenacity/orm_ext/activerecord.rb:60:in `_t_find'
    from /var/bundler/turtle/ruby/1.8/bundler/gems/tenacity-c24a35aeb57f/lib/tenacity/instance_methods.rb:23:in `_t_verify_associates_exist'
    from /var/bundler/turtle/ruby/1.8/bundler/gems/tenacity-c24a35aeb57f/lib/tenacity/instance_methods.rb:19:in `each'
    from /var/bundler/turtle/ruby/1.8/bundler/gems/tenacity-c24a35aeb57f/lib/tenacity/instance_methods.rb:19:in `_t_verify_associates_exist'
    from /var/bundler/turtle/ruby/1.8/bundler/gems/tenacity-c24a35aeb57f/lib/tenacity/orm_ext/mongoid.rb:79:in `_callback_before_1683'
    from /var/bundler/turtle/ruby/1.8/gems/activesupport-3.0.7/lib/active_support/callbacks.rb:422:in `_run_save_callbacks'
    from /var/bundler/turtle/ruby/1.8/gems/activesupport-3.0.7/lib/active_support/callbacks.rb:94:in `send'
    from /var/bundler/turtle/ruby/1.8/gems/activesupport-3.0.7/lib/active_support/callbacks.rb:94:in `run_callbacks'
    from /var/bundler/turtle/ruby/1.8/gems/mongoid-2.2.0/lib/mongoid/persistence/insertion.rb:24:in `prepare'
    from /var/bundler/turtle/ruby/1.8/gems/mongoid-2.2.0/lib/mongoid/persistence/insertion.rb:22:in `tap'
    from /var/bundler/turtle/ruby/1.8/gems/mongoid-2.2.0/lib/mongoid/persistence/insertion.rb:22:in `prepare'
    from /var/bundler/turtle/ruby/1.8/gems/mongoid-2.2.0/lib/mongoid/persistence/operations/insert.rb:26:in `persist'
    from /var/bundler/turtle/ruby/1.8/gems/mongoid-2.2.0/lib/mongoid/persistence.rb:44:in `insert'
    from /var/bundler/turtle/ruby/1.8/gems/mongoid-2.2.0/lib/mongoid/persistence.rb:149:in `save'
    from (irb):36
@jwood
Owner
jwood commented Apr 3, 2012

Interesting. This implies that the ActiveRecord based class in the association does not respond to find_by_id. Does either Avatar, Organization, or Community::Slideshow not have a field named id in their respective table? Perhaps one uses a primary key of a different name?

@raphaelcm

Ah yes. Community::Slideshow is a legacy model and its PK is show_id. I created a class method find_by_id that wraps find_by_show_id and it works!

One question though, the foreign key field is community/slideshow_id. Shouldn't it be slideshow_id (to be consistent with how AR names FK fields)?

@jwood
Owner
jwood commented Apr 3, 2012

Yeah, it probably should. As you may have guessed, it looks like Tenacity doesn't handle name spaced classes well. For now, you should be able to do the following

t_belongs_to :slideshow, :class_name => "Community::Slideshow", :foreign_key => "slideshow_id"

@raphaelcm

Great. Thanks so much for your help.

@jwood
Owner
jwood commented Apr 3, 2012

No problem. I'll take a stab at fixing the foreign key issue before cutting the new version of Tenacity.

Let me know if you run into any other issues.

@jwood
Owner
jwood commented Apr 4, 2012

I just pushed a fix that should take care of the foreign key issue (ac4e7ff). Would you mind giving it a try before I cut the new version of Tenacity?

@raphaelcm

Works! Thanks again.

> t = TenacityTest.new
 => #<TenacityTest _id: 4f7ef650e628f802e1000002, slideshow_id: nil, created_at: nil, updated_at: nil, avatar_id: nil, _type: nil, organization_id: nil> 
> t.slideshow = Community::Slideshow.last
 => #<Community::Slideshow id: 78, department_id: 162, created_at: "2012-02-22 17:39:58", updated_at: "2012-04-06 13:45:22", slideshowable_id: "4f7da1b6e628f85988000001", slideshowable_type: "CampusHub"> 
> t
 => #<TenacityTest _id: 4f7ef650e628f802e1000002, slideshow_id: 78, created_at: nil, updated_at: nil, avatar_id: nil, _type: nil, organization_id: nil>
@jwood jwood closed this Apr 6, 2012
@jwood
Owner
jwood commented Apr 6, 2012

Fixed in version 0.5.5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment