Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I write a Rails finder method where none of the has_many items has a non-nil field?

I'm using Rails 5. I have the following model ...

class Order < ApplicationRecord
    ...
    has_many :line_items, :dependent => :destroy

The LineItem model has an attribute, "discount_applied." I would like to return all orders where there are zero instances of a line item having the "discount_applied" field being not nil. How do I write such a finder method?

like image 975
Dave Avatar asked Feb 25 '20 18:02

Dave


People also ask

How do I find a specific record in rails?

In Rails, you can query the database through your models to access your data. You can do this using ActiveRecord methods. Like where, find, or find_by. If you’re expecting one record (a specific user), use find_by, for multiple records (a list of users) use where.

How to get the comment ID of a book in rails?

FROM "books" WHERE "books"."id" IN (1, 2, 3) You’ll find this query in the rails logs. If you’re looking to match based on an association value, you’ll have to make that association available with the joins method. With this query you get all the books, which have a comment, and the comment id is 2.

Can I use where in my Rails applications?

No problem! We’re going to take a look at the different ways you can use where in your Rails applications. The purpose of using where is to build a query that filters the information in your database, so you only get the rows you want. Given a Book model, with title, author & category.

How to query the database through models in rails?

In Rails, you can query the database through your models to access your data. You can do this using ActiveRecord methods. Like where, find, or find_by. As a result you get:


1 Answers

First of all, this really depends on whether or not you want to use a pure Arel approach or if using SQL is fine. The former is IMO only advisable if you intend to build a library but unnecessary if you're building an app where, in reality, it's highly unlikely that you're changing your DBMS along the way (and if you do, changing a handful of manual queries will probably be the least of your troubles).

Assuming using SQL is fine, the simplest solution that should work across pretty much all databases is this:

Order.where("(SELECT COUNT(*) FROM line_items WHERE line_items.order_id = orders.id AND line_items.discount_applied IS NULL) = 0")

This should also work pretty much everywhere (and has a bit more Arel and less manual SQL):

Order.left_joins(:line_items).where(line_items: { discount_applied: nil }).group("orders.id").having("COUNT(line_items.id) = 0")

Depending on your specific DBMS (more specifically: its respective query optimizer), one or the other might be more performant.

Hope that helps.

like image 180
Clemens Kofler Avatar answered Sep 28 '22 00:09

Clemens Kofler