Search code examples
ruby-on-railsruby-on-rails-5has-manyfinder

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?


Solution

  • Not efficient but I thought it may solve your problem:

    orders = Order.includes(:line_items).select do |order|
      order.line_items.all? { |line_item| line_item.discount_applied.nil? }
    end
    

    Update:

    Instead of finding orders which all it's line items have no discount, we can exclude all the orders which have line items with a discount applied from the output result. This can be done with subquery inside where clause:

    # Find all ids of orders which have line items with a discount applied:
    excluded_ids = LineItem.select(:order_id)
                           .where.not(discount_applied: nil)
                           .distinct.map(&:order_id)
    
    # exclude those ids from all orders:
    Order.where.not(id: excluded_ids)
    

    You can combine them in a single finder method:

    Order.where.not(id: LineItem
                        .select(:order_id)
                        .where.not(discount_applied: nil))
    

    Hope this helps