Count only datasets that are associated through HABTM - ruby-on-rails

I have two models with a HABTM associaton called LegacyDatum and Category Now I want to count how many Objects of LegacyDatum are associated with one or more categories. When I call LegacyDatum.joins(:categories) that works but it also returns the datasets with no category. How can I only get the datasets that have at least one category associated?
The Model is really simple, no unconventional associations...
LegacyDatum:
class LegacyDatum < ActiveRecord::Base
has_and_belongs_to_many :categories
.....
....
...
end

I believe it's because all is loading everything before the joins method is called. What do you get if you drop the all portion, or tack it on the end instead?

Related

Get children of different models in one single query

class Category
has_many :images
has_many :articles
end
class Image
belongs_to :category
end
class Article
belongs_to :category
end
I'm trying to understand what solutions there are in Rails for children of different models to be queried by the same parent?
E.g. I'd like to get all images and articles that belong to the same category and sort them all by created_at.
You can try 'includes' in rails
Article.includes(:Category)
As I said it seems to me you can use eager loading multiple associations. In your case it could be something like this:
Category.where(id: 2).includes(:images, :articles).sort_by(&:created_at)
Basically you pass your desired Category ID and get :images, :articles which belongs_to Category with particular ID. sort_byprobably should do the sorting thing.
This blog post on eager loading could help you as well.
You can't simply force Active Record to bring all their dependences in a single query (afaik), regardless if is lazy/eager loading. I think your best bet is:
class Category
has_many :images, -> { order(:created_at) }
has_many :articles, -> { order(:created_at) }
end
categories = Category.includes(:images, :articles)
As long as you iterate categories and get their images and articles, this will make three queries, one for each table categories, images and articles, which is a good tradeoff for the ease of use of an ORM.
Now, if you insist to bring all that info in just one query, for sure it must be a way using Arel, but think twice if it worths. The last choice I see is the good old SQL with:
query = <<-SQL
SELECT *, images.*, articles.*
FROM categories
-- and so on with joins, orders, etc...
SQL
result = ActiveRecord::Base.connection.execute(query)
I really discourage this option as it will bring A LOT of duplicated info as you will joining three tables and it really would be a pain to sort them for your use.

Looking for a way to track history in rails database

I'm considering this an add-on question of sorts to the thread below:
Using join tables in ruby on rails
So we have 'Student' and 'Course' scaffolds joined by a many-to-many association, but in addition there is also a 'Semester' scaffold and what I wish to do is, for each student that is added to a course, for the application to search for previous iterations of the same course through past semesters, to that it's known how many times a student has taken that class before. I'm kind of mixed up at the moment as to how to implement this, so I was hoping someone could help me pin down the logic and code I should be operating by.
Some underlying assumptions I have so far:
'Course' and 'Semester' should, like 'Student' and 'Course', be joined
by a many-to-many association (many courses are taught per semester,
and a course is taught for more than one semester).
There should be an action (let's say get_student) within the course
controller to locate the student via student_id. This would be the main area I'm scratching my head as to what to do. What would this method look like in code?
Within the student-course join table I should have an attribute
'attempts' which increments each time get_student finds this
student_id combined with the course_id that calls the method.This
would be the mechanism that actually tells how many times the course
had been attempted by the student.
I initially wondered if there should be a 'semester' controller
action to activate get_student across all semesters, but now I'm
thinking that get_student should work fine without that.
Appreciate any help I can get on this. Thanks.
This is not a good answer, just a comment.
I would comment, but hear will be more clear. I ll update for the other points. This is just an ongoing feedback/discussion, not an answer.
class Semester < ApplicationRecord
has_many :courses
end
class Course < ApplicationRecord
has_many :students
end
And
semester.courses[0].students => outputs the students array for that
This could be the method to calculate the number of student that did that course:
def studentForCourse
#input_params.course_id => course id you are selecting
semester = Semester.find(input_params)
semester.courses.each do |course|
if course.id = input_params.course_id
nstudents = course.students.size
end
end

Rails has_and_belongs_to_many query for all records

Given the following 2 models
class PropertyApplication
has_and_belongs_to_many :applicant_profiles
end
class ApplicantProfile
has_and_belongs_to_many :property_applications
end
I have a query that lists all property_applications and gets the collection of applicant_profiles for each property_application.
The query is as follows and it is very inefficient.
applications = PropertyApplication.includes(:applicant_profile).all.select |property_application| do
property_application.applicant_profile_ids.include?(#current_users_applicant_profile_id)
do
assume #current_users_applicant_profile_id is already defined.
How can I perform one (or few) queries to achieve this?
I want to achieve something like this
PropertyApplication.includes(:applicant_profile).where('property_application.applicant_profiles IN (#current_users_applicant_profile))

Is many-to-many association still apply here?

When an entity isn't associated with many other entity at the same time, should I still use many-to-many association?
For example, I understand that Author-Book relationship is a many to many, An author can write many books, a book can be written by many authors. This holds for all time.
Consider this situation. A Batch has many students at one particular time. If a student fails, he should move to the next junior batch. In other word, A student cannot belong to more than one batch at the same time. In this case, is this a many to many association?
Alternative Solution I thought:
I was thinking about putting two columns in students table. initial_batch and current_batch. I can get the student's Batch history, by checking the gaps between current and initial batch, because of the rule A student must drop to the next immediate batch. Also, batch.students exists with a has_many association in rails. So, I think that would not be a big deal.
By Batch, I mean batch of students get admitted in the same year.
I think you'd still want to use an association table (many-to-many association) because you might want to keep a history of which classes the student has taken.
If you want it to be a many-to-one and have a student belong to one class at a time, you'd have to add a class_id field to your student table. This allows you to call student.class to find their current class, but you wouldn't be able to do class.students because that relation doesn't exist. For this reason, I think it should be a many-to-many.
is this a many to many association
Yep.
An ActiveRecord association is simply a way for you to create two connected objects (ActiveRecord is an ORM -- Object Relationship Mapper).
Remember, as Ruby is object orientated, each "Model" (class) is counted as an object, invoked every time you want to populate it with data. Each ActiveRecord association for each object is accessed through a method in the object...
#app/models/student.rb
class Student < ActiveRecord::Base
has_many :subjects #-> AR appends the "subjects" method to your Student object
end
Simply, this means that even if you have the functionality for a number of different objects, you don't need to have the method populated with data.
If you have the following...
#app/models/student.rb
class Student < ActiveRecord::Base
has_and_belongs_to_many :subjects
end
#app/models/subject.rb # "class" is a reserved word
class Subject < ActiveRecord::Base
has_and_belongs_to_many :students
end
This simply provides the functionality / capacity for #students.subjects etc.
What's contained inside this method is up to you to determine:
<% if #students.subjects.any? %>
<% #students.subjects.each do |subject| %>
...
<% end %>
<% end %>

Proper Rails Association for this setup

Just starting out with rails and I have a question. My grasp on associations is weak.
Lets say I have a model Cars
some cars will be rentals and some will not. So I created a table and a model called Rentals
which just has the car_id in it, designating that at car_id is a rental.
Right now I have a belong_to :cars line in my Rental model. And I'm not sure that's right. I am attempting to get a list of all the rentals easily. So grabbing the car_ids from the rental table and getting all the car information from the cars table the most efficient way.
Can someone help out?
The following:
Car.joins(:rentals).all # try with :rental if not working
Will output all the cars that have a rental object associated with ;)
It depends on what you will exactly need to do with it.
For simplicity, this is how I would do it.
class CarType #better than Rentals and more meaningful [:type => [rental, lease, own]]
belongs_to :car
end
class Car
has_one :car_type
end
So, now for the cars table, it will have a car_type_id pointing to the type in car_types table.

Resources