So I have a somewhat confusing relationship here, between a Note, Group, and User. And I ended up with has_many twice in my model. But I'm currently focused on the Note & Group relationship.
Background: A Group can have a note. A User can also have a note. Which is why my Note is polymorphic. However, I also created a join model called a Tag, so that a Note can belong to multiple groups. In my code though, I ended up with multiple 'has_many :notes'. See all of my code below. What would be the proper way to do something like this?
Thanks in advance!
note.rb
belongs_to :notable, :polymorphic => true
has_many :tags
has_many :groups, :through => :tags
user.rb
has_many :notes, :as => :notable
group.rb
has_many :notes, :as => :notable
has_many :tags
has_many :notes, :through => :tags
tag.rb
belongs_to :note
belongs_to :group
You just need to give it a different name.
class Group
has_many :notes, :as => :notable
has_many :tags
has_many :tagged_notes, :class_name => 'Note', :through => :tags
end
If you only want a single note for the :as => :notable part (this wasn't very clear in your question), you could just do this:
class Group
has_one :note, :as => :notable
has_many :tags
has_many :notes, :through => :tags
end
The names just have to be different. Although with note vs. notes it might not be very clear what the distinction is in other parts of your code.
Related
I have 3 tables:
User class
User has_many :project_assignments
User has_many :projects, through: :project_assignments
ProjectAssignment class
ProjectAssignment belongs_to :user
ProjectAssignment belongs_to :project_owner, class_name: 'User', foreign_key: 'user_creator_id'
ProjectAssignment belongs_to :project
Project
has_many :project_assignments
has_many :users, through: :project_assignments
ProjectAssignment has the columns:
project_id, user_id, creator_user_id
I want to get all the projects, for a user through creator_user_id
ex: current_user.created_projects
The query: ProjectAssignment.where(creator_user_id: current_user.id)
Can it be done when defining the relations in the models, the same as I did with projects but the foreign_key should be creator_user_id
I think you just need another couple of associations in User which leverage the creator_user_id field (as opposed to user.projects which will return the projects the user is a member of)
Try this -
#in User class
has_many :owned_project_assignments, :class_name => "ProjectAssignment", :as => :project_owner, :foreign_key => "user_creator_id"
has_many :owned_projects, :through => owned_project_assignments, :class_name => "Project", :source => :project, :as => :project_owner
the :source and :as options can be a bit tricksy, so this might not work, it's just off the top of my head...
In my case this was the correct solution:
has_many :owned_project_assignments, class_name: "ProjectAssignment", foreign_key: 'user_creator_id'
has_many :owned_projects, through: :owned_project_assignments, source: :project
I have two tables for tagging so that I can attach tags to any models, it works likes so…
There's a tagged item join table which has a tag_id column and then two other columns for polymorphism: taggable_type and taggable_id…
class TaggedItem < ActiveRecord::Base
attr_accessible :taggable_id, :taggable_type, :tag_id
belongs_to :taggable, :polymorphic => true
belongs_to :tag
end
There's also all of the things that can have tags, for example here's a product and image model with tags attached:
class Product < ActiveRecord::Base
has_many :tagged_items, :as => :taggable, :dependent => :destroy
has_many :tags, :through => :tagged_items
end
class Image < ActiveRecord::Base
has_many :tagged_items, :as => :taggable, :dependent => :destroy
has_many :tags, :through => :tagged_items
end
The problem is with the tag model, I can seem to get the reverse work, on the tag modle I want to have a has_many images and has_many products like so:
class Tag < ActiveRecord::Base
has_many :tagged_items, :dependent => :destroy
has_many :products, :through => :tagged_items
has_many :images, :through => :tagged_items
end
This is causing an error, I was wondering how I can fix this. So the tag table works through the polymorphic tagged items table.
Any help would be much appreciated. Thanks!
Edit:
Could not find the source association(s) :product or :products in model TaggedItem. Try 'has_many :products, :through => :tagged_items, :source => <name>'. Is it one of :taggable or :tag?
The has_many :through associations in your Tag model are not able to get the source association for Product and Image from the TaggedItem Model. e.g. has_many :products, :through => :tagged_items will look for a direct association belongs_to :product in TaggedItem which in case of polymorphic association is written as belongs_to :taggable, :polymorphic => true. So for the Tag model to understand exact source of the association we need to add an option :source and its type as :source_type
So change your Tag model associations to look like
class Tag < ActiveRecord::Base
has_many :tagged_items, :dependent => :destroy
has_many :products, :through => :tagged_items, :source => :taggable, :source_type => 'Product'
has_many :images, :through => :tagged_items, :source => :taggable, :source_type => 'Image'
end
This should fix your problem. :)
you do not need the as option when you set up the Tag association to TaggedItem. :as => :taggable would mean that tag on tagged item is polymorphic which it is not. Instead the other side is, ie., the items that are taggable as your name cleverly suggests :).
class Tag < ActiveRecord::Base
has_many :tagged_items, :dependent => :destroy
has_many :products, :through => :tagged_items
has_many :images, :through => :tagged_items
end
I have this polymorphic association where a user can have many comments, a school can have many comments, and a comment can have many comments (or in my naming case replies):
class Comment < ActiveRecord::Base
attr_accessible :content
has_many :replies, :as => :commentable, :class_name => "Comment" # replies to comments
belongs_to :commentable, :polymorphic => true
belongs_to :commentor, :class_name => "User", :foreign_key => "user_id"
end
class User < ActiveRecord::Base
has_many :comments, :as => :commentable
has_many :commentors, # all users who commented on a user
:through => :comments,
:source => :commentor
end
class School < ActiveRecord::Base
has_many :comments, :as => :commentable
has_many :commentors, # all users who commented on a school
:through => :comments,
:source => :commentor
end
In the User, I can retrieve all who commented on a user using #user.commentors. Same goes for School, i.e. #school.commentors.
For the comments model, I would like to acheive the same thing for the Comments model where I can find all the commentors (or I guess repliers) to a comment; however, I have no idea what kind of association to create since a has_many :through association will not work like how it worked for the User and School model.
Use this:
has_many :reply_commentors, :through => :replies, :source => :commentor
This question is about the naming style of polymorphic relationships.
My database has three types of person: a 'Company', a Client, and an Employee. Each of the three are in polymorphic relationships with tasks and events, and projects.
According to the Rails guides, this would be done like (I've omitted some classes for brevity):
Person.rb
has_many :tasks, :as => :taskable
has_many :events, :as => :eventable
has_many :projects, :as => :projectable # awkward names
Task.rb
belongs_to :taskable, :polymorphic => true
These lead to the rather strange:
#person = #task.taskable
I feel that the following would be far more grammatical and elegant... would it work, and if so, is there a reason that official sources use words like projectable rather than words like owner?
Person.rb
has_many :tasks, :as => :owner
has_many :events, :as => :owner
has_many :projects, :as => :owner
Task.rb
belongs_to :owner, :polymorphic => true
This creates the elegant:
#person_1 = #task.owner
#person_2 = #project.owner
I personally try to keep it as generic as possible.
So :as => :owner does make more sense to me.
In case of doubt, I'd just use
:as => :parent
which I've already seen in some projects.
I have a User Model(:name, :password, :email), and Event model(:name, :etc) and Interest model (:name) [>all singular<]
Then I created two join tables -> UsersInterests and EventsInterests; each not containing a primary key and only comprised of the user_id/interest_id and event_id/interest_id respectively. [>plural<]
My Models Use the Nested Has Many Through Plugin
user.rb => has_many :users_interests
has_many :interests, :through => :users_interests
has_many :events_interests, :through => :interests
has_many :events, :through => :events_interests
event.rb => has_many :events_interests
has_many :interests, :through => :events_interests
has_many :users_interests, :through => :interests
has_many :users, :through => :users_interests
interest.rb => has_and_belongs_to_many :users
has_and_belongs_to_many :events
events_interests.rb => belongs_to :interests
belongs_to :events
users_interests.rb => belongs_to :users
belongs_to :interests
Whew..ok So I wanted to created a named_scope of that find all the events that share interest with a particular user. Here is some code someone helped me with.
named_scope :shares_interest_with_users, lambda {|user|
{ :joins => :users_interests,
:conditions => {:users_interests => {:user_id => user}}
}}
When i run from the controller =>
#user = User.find(1)
#events = Event.shares_interest_with_user(#user)
I get the error :
uninitialized constant Event::EventsInterest
Can anyone see what i messed up?
You must have named something wrong along the way. At a glance I'd say you have a file or class named incorrectly. Remember model names MUST always be singular, both in file and class names or else Rails won't make the connection. Another source of your problem is that arguments to belongs_to must also be singular. Even if you had got things right, the HABTM relationship in interests with users would have thrown an error when you ran the named scope.
I was able to solve your error with the following models.
user.rb
class User < ActiveRecord::Base
has_many :users_interests
has_many :interests, :through => :users_interests
has_many :events_interests, :through => :interests
has_many :events, :through => :events_interests
end
users_interest.rb
class UsersInterest < ActiveRecord::Base
belongs_to :user
belongs_to :interest
end
interest.rb
class Interest < ActiveRecord::Base
has_many :users,:through => :users_interests
has_many :users_interests
has_many :events_interests
has_many :events, :through => :events_interests
end
**events_interest.rb
class EventsInterest <ActiveRecord::Base
belongs_to :interest
belongs_to :event
end
event.rb
class Event <ActiveRecord::Base
has_many :events_interests
has_many :interests, :through => :events_interests
has_many :users_interests, :through => :interests
has_many :users, :through => :users_interests
named_scope :shares_interest_with_users, lambda {|user|
{ :joins => :users_interests,
:conditions => {:users_interests => {:user_id => user}}
}
}
end