ruby has many through two models - ruby-on-rails

Problem: In enrollment.attendances.count(:id) Enrollment must have access only to those attendances, that match it by both student_id and course_id.
Here are my 4 db dependancies:
class Enrollment < ActiveRecord::Base
belongs_to :course
belongs_to :student
has_many :attendances, through: :client
has_many :attendances, through: :course
,
class Student < ActiveRecord::Base
has_many :enrollments
has_many :attendances
,
class Course < ActiveRecord::Base
has_many :enrollments
has_many :attendances
,
class Attendance < ActiveRecord::Base
belongs_to :student
belongs_to :course
,
The schema of the model dependancies:

You can first find the object from Enrollment by student_id and course_id
and then check whether it attended or not
then you could find the count.
#enrolls = Enrollment.where(course_id: id1, student_id: id2)
#enrolls.each do |enrol|
if enrol.attended == true
puts Attendance.where(course_id: id1, student_id: id2).count
end
end

As mentioned here
putting the following line in enrollment.rb
has_many :attendances, ->(obj) { where("#{Attendance.quoted_table_name}.client_id = ?", obj.client_id)}, through: :course
perfectly solves the question

Related

Rails has_one association through mapping table

Given these 4 Rails models:
class Apple < ActiveRecord::Base
has_one: ?
end
class Banana < ActiveRecord::Base
has_one: ?
end
class FruitMapping < ActiveRecord::Base
belongs_to :fruit, polymorphic: true
has_one :cart
end
class Cart < ActiveRecord::Base
end
How can I connect the has_one of the Apple/Banana to Cart, so that when I write apple.cart I will get the relevant Cart (through the mappings table)?
class Apple < ActiveRecord::Base
has_one :fruit_mapping, as: :fruit
end
class Cart < ActiveRecord::Base
has_many :fruit_mappigns
has_many :apples, through: :fruit_mappings, source: :fruit, source_type: 'Apple'
has_many :bananas, through: :fruit_mappings, source: :fruit, source_type: 'Banana'
end
Using the source and source_type options, you can define the polymorphic relationships. If using source and source_type are depricated in the Rails version you're using you can try
has_many :apples, through: :fruit_mappings, class_name: 'Apple', foreign_key: :fruit_id

Rails Has_one and has_many relationship

I have Teacher model:
class Teacher < User
has_many :categories, dependent: :destroy
has_many :grades, through: :categories
end
Grade model:
class Grade < ApplicationRecord
has_many :categories, dependent: :destroy
has_many :teachers, through: :categories
end
Category model:
class Category < ApplicationRecord
belongs_to :teacher
belongs_to :grade
end
Student model:
class Student < User
end
Now i want to set up relationship between Grade model and Student model
(student has_one grade and a grade has_many students) with through model Category.
How can i do this?
class Student < User
has_one: :grade
end
and
class Grade < ApplicationRecord
has_many :categories, dependent: :destroy
has_many :teachers, through: :categories
has_many :students, through: :categories
end
and
class Category < ApplicationRecord
belongs_to :teacher
belongs_to :grade
belongs_to :student
end
Does the above not work..? You should put what you have tried in your post if you have run into issues.
Join tables are for many-to-many relationships. Since a student only has one grade, it is a many-to-one relationship, not a many-to-many relationship.
You do not need (and shouldn't use) a join table for this.
Instead add a grade_id column to the students (users) table and setup the associations like this:
class Student < User
belongs_to :grade
end
class Grade < ApplicationRecord
has_many :students
end
Don't use any through associations to connect students with grades.

Find records that have two exact instances of a many-to-many relation

I have an application with a business logic concerning products with multiple variants:
class Task < ApplicationRecord
belongs_to :variant
end
class Variant < ApplicationRecord
belongs_to :product
has_many :variant_option_values
has_many :option_values, through: :variant_option_values
has_many :prices
end
class Product < ApplicationRecord
has_many :product_option_types
has_many :option_types, through: :product_option_types
has_many :variants
end
class OptionValue < ApplicationRecord
belongs_to :option_type
end
class OptionType < ApplicationRecord
has_many :product_option_types
has_many :products, through: :product_option_types
has_many :option_values
end
class ProductOptionType < ApplicationRecord
belongs_to :product
belongs_to :option_type
end
class VariantOptionValue < ApplicationRecord
belongs_to :variant
belongs_to :option_value
end
The ERD looks like this:
Having a product product_1 how can I find its variants that have OptionValue instances option_value_1, option_value_2 and option_value_3? Note that the variant has to have all three option values at the same time and can have more than those three (but not necessarily).
option_values = [option_value_1, option_value_2, option_value_3]
Variant.include(product: [option_types: :option_values])
.where("option_values.id IN (?)", option_values.map(&:id))
.group("products.id")
.having("count(*) >= ?", option_values.size)

Ruby on Rails - Association

I have to create relationship between student, courses and enrolment.
One student can enrol in only one course.
A course can be enrolled by many students.
How to acheive this ?
I was able to create has_many_through relationship like this
class
Student < User
has_many :enrollments
has_many :course , through: :enrollments
end
class Course < ActiveRecord::Base
has_many :enrollments
has_many :students, through: :enrollments, class_name: "User"
end
class Enrollment < ActiveRecord::Base
belongs_to :student, class_name: "User"
belongs_to :course
end
But this works only for has_many on both the sides of students and courses.
But I want only one student to enrol in one course like this
class Student < User
has_one :enrollment
has_one :course , through: :enrollment
end
But this does not work. When I do this
Student.first.enrollment.create(course: Course.last)
I get an error like this
NoMethodError: undefined method `enrollment' for #<Student:0x007f7ff8baf4a8>
Thanks to Marek Lipka for suggesting this solution.
Add validation in Enrollment
class Enrollment < ActiveRecord::Base
belongs_to :student, class_name: "User"
belongs_to :course
validates :student , uniqueness: true
end
And use has_many enrollments
class Student < User
has_many :enrollments
has_many :course , through: :enrollments
end

Rails belongs_to through association

I'm trying to add a new model to an existing model mesh. The existing one works perfectly but I can't get the new one to work properly and am wondering if the association is able to work the way I'm trying to make it work. Update: As I just got asked: belongs_to through was something I've read while gooling about the problem. If it doesn't exist, would has_one through be the correct way? I tried it as well but it also didn't work.
Here is the existing mesh:
class Course
has_many :users, through: :enrollments
has_many :enrollments
end
class User
has_many :courses, through: :enrollments
has_many :enrollments
end
class Enrollment
belongs_to :course
belongs_to :user
# has fields :user_id, :course_id
end
Now a user should be able to rate a course he's completed. (If he has, there is an enrollment with his id and a course id.) I thought it would be best to write it as follows:
class Course
has_many :users, through: :enrollments
has_many :enrollments
has_many :ratings, through: :enrollments
end
class User
has_many :courses, through: :enrollments
has_many :enrollments
has_many :ratings, through: :enrollments
end
class Enrollment
belongs_to :course
belongs_to :user
has_one :rating
# has fields :user_id, :course_id
end
class Rating
belongs_to :enrollment
belongs_to :course, through: :enrollment
belongs_to :user, through: :enrollment
end
When I try to create a Rating in the console, I get the following error:
User.first.ratings.create(text: "test", course_id: Course.first.id)
ArgumentError: Unknown key: through
Update
When I use has_one through insted, I get the following error:
ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection: Cannot modify association 'User#ratings' because the source reflection class 'Rating' is associated to 'Enrolment' via :has_one.
Is it possible to do it this way at all? Thanks!
class Course
has_many :users, through: :enrollments
has_many :enrollments
has_many :ratings, through: :enrollments
end
class User
has_many :courses, through: :enrollments
has_many :enrollments
has_many :ratings, through: :enrollments
end
class Enrollment
belongs_to :course
belongs_to :user
belongs_to :rating
# has fields :user_id, :course_id, rating_id
end
class Rating
has_one :enrollment
has_one :course, through: :enrollment
has_one :user, through: :enrollment
end
Note: Add foreignkey columns
And if you there is just one/two columns in ratings table merge them into enrollments like this.
class Course
has_many :users, through: :enrollments
has_many :enrollments
end
class User
has_many :courses, through: :enrollments
has_many :enrollments
end
class Enrollment
belongs_to :course
belongs_to :user
# has fields :user_id, :course_id, rating-columns...
end
Structure
Maybe you're complicating this too much
class Enrollment
belongs_to :course
belongs_to :user
end
This means you have a join model which stores unique records, referencing both course and user. Your ratings are on a per user and course basis?
Why don't you just include rating as an attribute of your enrolment model?:
#enrolments
id | user_id | course_id | rating | created_at | updated_at
If you give rating a numeric value (1 - 5), it will give you the ability to rate the different enrolments like this:
user = User.first
course = Course.first
user.enrolments.create(course: course, rating: 5)
--
Ratings
This is, of course, based on your current model structure.
If you want to include ratings for courses by users (not tied to enrolment), you may wish to use a join model called course_ratings or similar:
#app/models/user.rb
Class User < ActiveRecord::Base
has_many :enrolments
has_many :courses, through: :enrolments
has_many :ratings, through: :courses, class_name: "CourseRating"
end
#app/models/course.rb
Class Course < ActiveRecord::Base
has_many :enrolments
has_many :students, through: :enrolments, class_name: "User"
has_many :ratings, class_name: "CourseRating"
end
#app/models/course_rating.rb
Class CourseRating < ActiveRecord::Base
belongs_to :course
belongs_to :user
end
This will allow you to call:
user = User.first
user.courses.first.ratings

Resources