Finding the number of models with a certain attribute - ruby-on-rails

Hi I have a model in my database User, a user can have zero, one or many Cars. I want to find all the Users in my database with one or more Cars. At the moment I have logic that says:
#car_user_count
for user in Users.all do
if user.cars.count > 0
#car_user_count = #car_user_count + 1
end
This seems like an overly complicated way of doing this. I assume there must be a way of doing something like:
User.where(Cars.count > 0).all.count
but I just can't seem to get it to work, any help with this would be greatly appreciated.

I want to find all the Users in my database with one or more Cars.
User.includes(:cars).where.not(cars: { id: nil })

For your example try joins with count:
User.joins(:cars).distinct.count

Related

Rails: chaining multiple filters together for has many through: relationships

I am in need of some help with chaining some filters involving has many through relationships.
Some background:
I have a model called product. A product has many categories. Vice versa, a category can have many products.
I have a model called colours, A product can have many colours. These 2 are also linked via has many through relationships.
My main goal is to somehow be able to filter items based on category and colour. I am receiving input from the user via a form.This would mean doing something in the controller like
#products= Product.includes(:categories).includes(:colours)
.where(categories: {id: params[:item][:category_ids]})
.where(colours: {id: params[:item][:colour_ids]})
However, this solution comes with a lot of problems apart from being real janky. Plus, if a user does not pass in any filters, it just filters with nils or "".
Is there a better way of chaining multiple has many through relationships like this? I've been trying to find any hints of how to do this online but I am still clueless on what to do here. Any help would be much appreciated. Also, I can edit this post if any additional code is needed.
Your implementation looks quite good). But i would suggest you this. If you just need filtering products then you can call left_joins and pass there your join tables(products_categories, products_colours) instead of target tables. Why? Because it will reduce LEFT JOIN clauses in your sql query and don't load objects into memory, hence you'll improve performance. But it only will work if you don't need to go through your products and take his categories or colours.
So query will look like.
Product
.left_joins(:products_categories, :products_colours)
.where(products_categories: { category_id: params[:item][:category_ids].presence || Category.ids } )
.where(products_colours: { colour_id: params[:item][:colour_ids].presence || Colour.ids }

Display Sorted Column on Static Page in Rails

I am creating a website that allows users to evaluate their coworkers. My boss would like the averages to be displayed from best to worst on a static page that she can print and hang up in our store, so the employees can see their results compared to other employees. I have been searching for awhile now on how to easily sort a column. I found a Railscast on sorting columns, but it seems a lot more detailed than I truly need. I found the order API, but I don't think I'm implementing it the way I need to. I am hoping that maybe there is a one-liner that can help me solve this problem, such as:
#user = User.all.order(average: :asc)
Where I can load a static page that prints the user's name and their score. Thank you in advance!
Have you tried that code of yours? It should do exactly what you're asking except from lowest score to highest score.
You could simplify it a little and sort from highest to lowest by doing:
#users = User.order(average: :desc)
Like MarsAtomic said, this assumes that you actually have a column in your users table called average. If not we need more information on how your database is set up.

How to remove some items from a relation?

I am loading data from two models, and once the data are loaded in the variables, then I need to remove those items from the first relation, that are not in the second one.
A sample:
users = User.all
articles = Articles.order('created_at DESC').limit(100)
I have these two variables filled with relational data. Now I would need to remove from articles all items, where user_id value is not included in the users object. So in the articles would stay only items with user_id, that is in the variable users.
I tried it with a loop, but it was very slow. How do I do it effectively?
EDIT:
I know there's a way to avoid doing this by building a better query, but in my case, I cannot do that (although I agree that in the example above it's possible to do that). That thing is that I have in 2 variables loaded data from database and I would need to process them with Ruby. Is there a command for doing that?
Thank you
Assuming you have a belongs_to relation on the Article model:
articles.where.not(users: users)
This would give you at most 100, but probably less. If you want to return 100 with the condition (I haven't tested, but the idea is the same, put the conditions for users in the where statement):
Articles.includes(:users).where.not(users: true).order('created_at DESC').limit(100)
The best way to do this would probably be with a SQL join. Would this work?
Articles.joins(:user).order('created_at DESC').limit(100)

Rails 4 returning rows with no through: relationship

I want to find a list of Surveys that the user hasn't taken
I have a UserAnswer model which is my has many through relationship to survey.
To find a list of surveys the user has taken I can simply write:
current_user.surveys
How can I get a list of Surveys the user hasn't taken?
I'm guessing I'm looking for something like
Surveys.where(!UserAnswer.survey_id: [current_user.surveys.ids])
So close!
Surveys.where.not(survey_id: [current_user.surveys.ids])
At least, it's the most direct path to valid code from yours. As of resulting SQL, I think there is a more performant way using joins. I'm still not perfect with joins, so I can't give any advice.

How can I code if I want to avoid n plus one issue?

I have these 3 models
Student
Gender
BloodType
Prefecture
Student has these three models such as Gender, BloodType, Prefecture.
and each of them belongs to Student.
Association is set up already in each model files.
In this case, how can I code if I want to avoid N + 1 issue?
Is it something like this?
#students = Student.find(:all).includes.includes(:gender, :blood_type, :prefecture)
You only need .includes once, and you can get rid of the find(:all) since Rails 3 does not require it.
students = Student.includes(:gender, :blood_type, :prefecture)
Having said that, it looks like these are just look up tables and I'd recommend checking out my gem ClassyEnum as a potential replacement if you are concerned about performance issues.

Resources