Rails find and calculate using has_many through releationship - ruby-on-rails

I have following models:
Product:
class Product < ActiveRecord::Base
has_many :product_recommendations, :dependent => :destroy
has_many :recommendations, :through => :product_recommendations
end
ProductRecommendation:
class ProductRecommendation < ActiveRecord::Base
belongs_to :recommendation
belongs_to :product
end
Recommendation:
class Recommendation < ActiveRecord::Base
has_many :product_recommendations, :dependent => :destroy
has_many :products, :through => :product_recommendations
has_many :recommendation_ratings, :dependent => :destroy
has_many :ratings, :through => :recommendation_ratings
end
Rating:
class Rating < ActiveRecord::Base
has_many :recommendation_ratings, :dependent => :destroy
has_many :recommendations, :through => :recommendation_ratings
end
RecommendationRating:
class RecommendationRating < ActiveRecord::Base
belongs_to :recommendation
belongs_to :rating
end
How would I be able to calculate the average rating for a given recommendation? My ratings table contains just 4 records, (Ratings 1-4), and I have an action in my recommendation controller which updates the RecommendationsRatings join table to associate a rating with a recommendation. Thanks!

have you tried:
class Product < ActiveRecord::Base
has_many :product_recommendations, :dependent => :destroy
has_many :recommendations, :through => :product_recommendations
has_many :ratings, :through => :recommendations
end
and then
p = Product.find 1
p.ratings.average(:rating)
this is assuming the Ratings model has an int / float called rating which stores the rating

Related

Rails has_many through seems to not work

I need a second set of eyes on this. When I create a Match between two players, Tournament.players returns an empty array.
Code
class Tournament < ActiveRecord::Base
has_many :player_matches
has_many :matches
has_many :players, :through => :player_matches
end
class PlayerMatch < ActiveRecord::Base
belongs_to :player
belongs_to :match
belongs_to :tournament
end
class Player < ActiveRecord::Base
has_many :player_matches
has_many :matches, :through => :player_matches
has_many :tournaments, :through => :player_matches
end
You need to have a double :through relation:
player_matches through matches and players through player_matches.
class Tournament < ActiveRecord::Base
has_many :matches
has_many :player_matches, :through => :matches
has_many :players, :through => :player_matches
end
class PlayerMatch < ActiveRecord::Base
belongs_to :player
belongs_to :match
end
class Player < ActiveRecord::Base
has_many :player_matches
has_many :matches, :through => :player_matches
has_many :tournaments, :through => :player_matches
end
class Match < ActiveRecord::Base
belongs_to :tournament
has_many :player_matches
has_many :players, :through => :player_matches
end

Rails Relationship Help

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

How do I model these relationships?

I have a contact model, this includes name, address, phone number, etc.
I have a user model which should have_one contact.
I have a Customer model which has_many contacts.
I have a Producer model which has many contacts.
A contact can be only a user, a user and a customer, a user and a producer, or any combination of these three. I also need to be sure that the same contact record is linked when a contact is linked to multiple models for data integrity.
how should I create the associations?
This looks like a good application for a polymorphic association:
class User < ActiveRecord::Base
has_one :contact, :as => :contactable
end
class Customer < ActiveRecord::Base
has_many :contacts, :as => :contactable
end
class Producer < ActiveRecord::Base
has_many :contacts, :as => :contactable
end
class Contact < ActiveRecord::Base
belongs_to :contactable, :polymorphic => true
end
EDIT
It seems I didn't read the specs all the way through :) To associate the same contact with multiple Users, Customers, etc, you could use a has_many :through:
class User < ActiveRecord::Base
has_one :user_contact, :dependent => :destroy
has_one :contact, :through => :user_contact
end
class Customer < ActiveRecord::Base
has_many :customer_contacts, :dependent => :destroy
has_many :contacts, :through => :customer_contacts
end
class Producer < ActiveRecord::Base
has_many :producer_contacts, :dependent => :destroy
has_many :contacts, :through => :producer_contacts
end
class UserContact
belongs_to :user
belongs_to :contact
end
class CustomerContact
belongs_to :customer
belongs_to :contact
end
class ProducerContact
belongs_to :producer
belongs_to :contact
end
class Contact < ActiveRecord::Base
has_many :user_contacts, :dependent => :destroy # might use 'has_one' here depending on your requirements
has_many :users, :through => :user_contacts
has_many :customer_contacts, :dependent => :destroy
has_many :customers, :through => :customer_contacts
has_many :producer_contacts, :dependent => :destroy
has_many :producers, :through => :producer_contacts
end
That gives you one join table for each of the three associations. Each Contact can belong to none, one, or many of the three other models by adding rows to the join tables.

:has_many relationship with :through on another relationship with :through

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)

Rails relation select

I have the following models:
class User < ActiveRecord::Base
has_many :results, :dependent => :destroy
has_many :participants, :dependent => :destroy
has_many :courses, :through => :participants
end
class Course < ActiveRecord::Base
has_many :tests, :dependent => :destroy
has_many :participants, :dependent => :destroy
has_many :users, :through => :participants
end
class Result < ActiveRecord::Base
belongs_to :test
belongs_to :user
end
class Test < ActiveRecord::Base
belongs_to :course
has_many :results, :dependent => :destroy
end
The Idea is that a user has_and_belongs_to_many courses, the course has_many tests, and every test has_and_belongs_to_many users (results).
So what is the best query to select every Result from a single Course (not test), and also the query to select every Result from a single Course, but from one user.
Thanks!
To get the results from a specific course - given that the only bridge between the two is the test model you will need to include the test in the query.
Result.find(:all, :conditions => ["tests.course_id = ?",#course.id], :include => :test)
For the second query:
Result.find(:all, :conditions => ["user_id = ? AND tests.course_id = ?",#user.id, #course.id], :include => :test)

Resources