views:

323

answers:

2

I'm trying to define multiple polymorphic relations (has_many_polymorphs plugin) from a single parent to same children.

Note has many viewers
Note has many editors
Viewers could be either Users or Groups
Editors could be either Users or Groups
Permission is the association model with note_id, viewer_id, viewer_type, editor_id, editor_type fields

Everything works out as expect as long as I have only one has_many_polymorphs relation defined in Note model

class User < ActiveRecord::Base; end
class Group < ActiveRecord::Base; end

class Note < ActiveRecord::Base
    has_many_polymorphs :viewers, :through => :permissions, :from => [:users, :groups]
end

class Permission < ActiveRecord::Base
    belongs_to :note
    belongs_to :viewer, :polymorphic => true
end


Note.first.viewers << User.first # =>  [#<User id: 1, ....>]
Note.first.viewers << Group.first # =>  [#<User id: 1, ....>, #<Group ...>]
Note.first.viewers.first # => #<User ....>
Note.first.viewers.second # => #<Group ....>

Now, problems start to appear when I add the second relation

class Note < ActiveRecord::Base
    has_many_polymorphs :viewers, :through => :permissions, :from => [:users, :groups]
    has_many_polymorphs :editors, :through => :permissions, :from => [:users, :groups]
end

class Permission < ActiveRecord::Base
    belongs_to :note
    belongs_to :viewer, :polymorphic => true
    belongs_to :editor, :polymorphic => true
end

Note.first.viewers << User.first # => [#<User id: ....>]

# >>>>>>>>
Note.first.editors << User.first

NoMethodError: You have a nil object when you didn't expect it!
The error occurred while evaluating nil.constantize
... vendor/plugins/has_many_polymorphs/lib/has_many_polymorphs/base.rb:18:in `instantiate'


I've tried refining the definition of has_many_polymorphs but it didn't work. Not even with an STI model for ViewPermission < Permission, and EditPermission < Permission.

Any thoughts / workarounds / issue pointers are appreciated.

Rails 2.3.0

A: 

Dont you need to add

has_many :permissions

to your Note. FYI. I used has_many_polymorphs once but then dropped it, it wasn't working as expected.

Can you post the schema that you are using for Permission? My guess is the root of the problem lies there, you need to have multiple type, id pairs in the schema since you have two different belongs_to in the definition.

Edit:

I see you have posted the question on github as well. Not sure if you tried using the Double sided polymorphism. You probably have... like I said, I was not impressed by this plugin, as it brought in some instability when I used it.

== Double-sided polymorphism

Double-sided relationships are defined on the join model:

      class Devouring < ActiveRecord::Base
        belongs_to :guest, :polymorphic => true
        belongs_to :eaten, :polymorphic => true

        acts_as_double_polymorphic_join(
          :guests =>[:dogs, :cats], 
          :eatens => [:cats, :birds]
        )       
      end


Now, dogs and cats can eat birds and cats. Birds can't eat anything (they aren't <tt>guests</tt>) and dogs can't be 
eaten by anything (since they aren't <tt>eatens</tt>). The keys stand for what the models are, not what they do.
Ryan Oberoi
The `has_many :permissions` is not required. The schema as outlined in the second paragraph is: integer :note_id integer :viewer_id string :viewer_type integer :editor_id string :editor_type
Tamer Salama
Thanks Ryan - yes - I posted on github as an issue (http://github.com/fauna/has_many_polymorphs/issues/#issue/3)I'm not sure if Double-sided relationships would work. My _understanding_ they are intended for a polymorphic parent-relation. ie: instead of having only `Note` as a parent, I could also have say `Post` as a parent; which would make it a double-sided polymorphism. Note can have either User or Group viewer. Post can have User or Group viewer. The relationship table `Permission` would have to have `authorizable_id` and `authorizable_type` to stored either `Note` or `Post` references.
Tamer Salama
+1  A: 

@Tamer

I was getting the same error. The problem was that has_many_polymorphs creates the record in the join table using mass association and was failing. I added attr_accessible :note_id, :editor_id, and :editor_type to my Permission class and it worked afterwards. (Note: I substituted your model names for mine.)

I haven't looked too much into it, but I'd be curious if there's a way to alter this behavior. I'm fairly new to this framework and letting anything sensitive (like an Order-Payment association) be mass-assigned seems like asking to shoot myself in the foot. Let me know if this fixed your problem, and if you figure anything else out.

Best,
Steve