I have models in my app:
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => true
end
class Project < ActiveRecord::Base
has_many :discussions, :dependent => :destroy
has_many :tickets, :dependent => :destroy
end
class Discussion < ActiveRecord::Base
has_many :comments, :as => :commentable, :dependent => :destroy
end
class Ticket < ActiveRecord::Base
has_many :comments, :as => :commentable, :dependent => :destroy
end
Everything works fine, but sometimes it's not very convinient to get project from comment through commentable, i.e. comment.commentable.project.
Is there any way to make has_one project in Comment model?
I would add the following method to your class Comment:
def project
self.commentable ? self.commentable.project : nil
end
This will give you the same result without all the magic of ActivRecord.
Related
I have 3 modules Blog, News, Article and I gathering reviews for all.
class Review < ActiveRecord::Base
attr_accessible :reviewable_type,:reviewable_id,:description,:context,:language,:status, :title, :user_id,:review_category_id,:ratings
belongs_to :user
belongs_to :review_category
belongs_to :reviewable, :polymorphic => true
class Blog < ActiveRecord::Base
attr_accessible :description, :status, :title
has_many :reviews, :as => :reviewable, :dependent => :destroy
class News < ActiveRecord::Base
attr_accessible :description, :status, :title
has_many :reviews, :as => :reviewable, :dependent => :destroy
class Article < ActiveRecord::Base
attr_accessible:description, :status, :title
has_many :reviews, :as => :reviewable, :dependent => :destroy
My question is, how to get all the reviews posted on current user's blog, article, news etc?
Just like how you associate other has_many relations. Like this:
current_user.blogs.first.reviews
current_user.articles.first.reviews
current_user.news.first.reviews
In your blog show page,
#blog.reviews.each |r|
r.review_text
end
Because you're trying to call for a user, I'd recommend looking at the User model too:
#app/models/user.rb
Class User < ActiveRecord::Base
#User can submit many reviews
has_many :reviews
#User can submit many blogs / news / articles
has_many :blogs
has_many :news
has_many :articles
def first_blog
blogs.first
end
end
#app/models/review.rb
class Review < ActiveRecord::Base
belongs_to :user
belongs_to :review_category
belongs_to :reviewable, :polymorphic => true
end
#app/models/blog.rb
class Blog < ActiveRecord::Base
belongs_to :user
has_many :reviews, :as => :reviewable, :dependent => :destroy
def first_review
reviews.first
end
end
#app/models/news.rb
class News < ActiveRecord::Base
belongs_to :user
has_many :reviews, :as => :reviewable, :dependent => :destroy
end
#app/models/article.rb
class Article < ActiveRecord::Base
belongs_to :user
has_many :reviews, :as => :reviewable, :dependent => :destroy
end
Reviews
This will allow you to call:
#########
#Reviews#
#########
#Submitted
current_user.reviews
#Received
current_user.first_blog.first_review
current_user.first_blog.reviews
Basically I want a Topic to have many Posts and Posts to have many Comments. If a Post gets destroyed I want it's Comments to be destroyed. If a Topic is deleted, I want it's Posts and Comments destroyed. Does the code below accomplish this? And is the has_one :topic line necessary?
topic.rb:
class Topic < ActiveRecord::Base
has_many :posts, :dependent => :destroy
end
post.rb:
class Post < ActiveRecord::Base
belongs_to :topic, :dependent => :destroy, :touch => true
has_one :topic
has_many :comments, :dependent => :destroy
end
comment.rb:
class Comment < ActiveRecord::Base
belongs_to :post, :dependent => :destroy, :touch => true
end
Should I be using the Ancestry gem for this? Would that make this even more simple? Thanks for reading my questions. Any assistance would be greatly appreciated.
1) has_one :topic is unnecessary, with the belongs_to you already declare the association.
2) :dependent => :destroy goes on the has_many side for your requirements. If you place them on the belongs_to side you will destroy a Topic once destroying one of his posts, leaving orphan a lot of other posts.
This is the code you're looking for:
topic.rb:
class Topic < ActiveRecord::Base
has_many :posts, :dependent => :destroy
end
post.rb:
class Post < ActiveRecord::Base
belongs_to :topic, :touch => true
has_many :comments, :dependent => :destroy
end
comment.rb:
class Comment < ActiveRecord::Base
belongs_to :post, :touch => true
end
I have simplified my design to make this question more clear. (Design of models below)
What I am trying to do is from a CourseEnrollment get all the PatientCourseSteps for that enrollment only (An enrollment consists of a patient and a course).
Here is what I have tried:
#Gives me ALL the patient course steps regardless of the course
course_enrollment.patient.patient_course_steps
#Gives me ALL the patient course steps regardless of the patient
course_enrollment.course.patient_course_steps
Below is the models that are necessary
class CourseEnrollment < ActiveRecord::Base
belongs_to :patient
belongs_to :course
end
class Course < ActiveRecord::Base
has_many :course_steps, :dependent => :destroy
has_many :steps, :through => :course_steps
has_many :course_enrollments, :dependent => :destroy
has_many :patients, :through =>:course_enrollments
has_many :patient_course_steps, :dependent => :destroy
end
class Patient < ActiveRecord::Base
belongs_to :user, :dependent => :destroy
has_many :enrollments, :dependent => :destroy
has_many :clients, :through => :enrollments
has_many :course_enrollments, :dependent => :destroy
has_many :courses, :through => :course_enrollments
has_many :patient_course_steps, :dependent => :destroy
end
class Step < ActiveRecord::Base
belongs_to :step_type
belongs_to :client
has_one :step_quiz, :dependent => :destroy
has_one :step_survey, :dependent => :destroy
has_one :step_text, :dependent => :destroy
has_one :step_download, :dependent => :destroy
has_one :step_video, :dependent => :destroy
has_one :step_presentation, :dependent => :destroy
has_many :course_steps, :dependent => :destroy
has_many :courses, :through => :course_steps
has_many :patient_course_steps, :dependent => :destroy
end
class PatientCourseStep < ActiveRecord::Base
belongs_to :patient
belongs_to :course
belongs_to :step
end
What I ended up doing was adding a method to CourseEnrollment named patient_course_steps which queries for what I need.
def patient_course_steps
PatientCourseStep.where(:patient_id => self.patient_id, :course_id => self.course_id)
end
My setup is as follows:
class User < ActiveRecord::Base
has_many :owners, :dependent => :destroy
has_many :properties, :through => :owners
end
class Owner < ActiveRecord::Base
belongs_to :user
belongs_to :property
end
class Property < ActiveRecord::Base
has_many :owners, :dependent => :destroy
has_many :users, :through => :owners
has_many :datafiles, :dependent => :destroy
end
class Datafile < ActiveRecord::Base
belongs_to :property
end
Now I'd like to be able to do #user.datafiles.
I tried has_many :datafiles, :through => :properties, :source => :datafiles but there appears to be a problem with a :through on something that's already went to a :through. So how would I go about to try and manage what I'm trying to do here?
Thank you in advance.
2 approaches;
1>
class User < AR
has_many :owners, :dependent => :destroy
has_many :properties, :through => :owners
has_many datafiles
end
class Datafile < AR
belongs_to :user
belongs_to :property
end
Your requirement of user.datafiles should be fulfilled with this.
If you want a nested has_many through, you'll need to use a plugin which is the 2nd approach.
2>
You can find it here.
The plugin works out of the box and does the job.
How about something like:
#user.rb
def datafiles
Property.find(:all, :joins => :owners, :conditions => ['owners.user_id = self.id'], :include => :datafile).collect(&:datafile)
In my app I have the classes User, Video, and Vote. Users and Videos can relate to each other in two different ways: as a one-to-many or as a many-to-many. The former is when a User submits a Video (one user can submit many videos). The latter is when a user votes on a video (users have many videos through votes, and vice versa). Here is my code, which does not work (I think -- I may be doing something wrong in the view). Please help me understand the correct way to structure these associations:
class User < ActiveRecord::Base
has_many :videos, :as => :submissions
has_many :votes #have tried it without this
has_many :videos, :as => :likes, :through => :votes
end
class Vote < ActiveRecord::Base
belongs_to :video
belongs_to :user
end
class Video < ActiveRecord::Base
belongs_to :user
has_many :votes #have tried it without this . . . superfluous?
has_many :users, :as => :voters, :through => :votes
end
I haven't gone and checked, but it goes something like this:
Instead of
has_many :videos, :as => :likes, :through => :votes
Use
has_many :likes, :class_name => "Video", :through => :votes
Same with the bottom:
has_many :users, :as => :voters, :through => :votes
becomes
has_many :voters, :class_name => "User", :through => :votes
:as is used for polymorphic associations. See this chapter in docs for more info.
class User < ActiveRecord::Base
has_many :videos # Submitted videos
has_many :votes
has_many :voted_videos, :through => :votes # User may vote down a vid, so it's not right to call 'likes'
end
class Vote < ActiveRecord::Base
belongs_to :video
belongs_to :user
end
class Video < ActiveRecord::Base
belongs_to :user
has_many :votes
has_many :voters, :through => :votes
end
More details can be found here: http://guides.rubyonrails.org/association_basics.html
Hope it helps =)
Thanks for your help guys, definitely pointed me in the right direction. Here is the working code:
class User < ActiveRecord::Base
has_many :videos, :as => :submissions
has_many :votes
has_many :likes, :source => :video, :through => :votes
end
class Vote < ActiveRecord::Base
belongs_to :video
belongs_to :user
end
class Video < ActiveRecord::Base
belongs_to :user
has_many :votes
has_many :voters, :source => :user, :through => :votes
end
PS I kept it as :likes because in this app they won't be able to downvote, only upvote.