I have a rails 4.2.8 application with a number of relationships. My Interaction model has and belongs to many genes (specifically an interaction can have 2 genes while a gene can belong to any number of interactions) and the Gene model in turn has many drugs and diseases.
I am trying to allow users to filter Interactions based on whether one or the other of its genes has a drug and / or disease associated with it. The code below works as required if either the drug or disease 'filter' is selected in that all interactions with at least one gene with at least one of those associations are displayed.
However when both filters are checked I am only displaying interactions where one or both of the genes have at least one drug and at least one disease associated. What I would like is to also show interactions where one gene has drug/s but no disease and the other gene has disease/s but no drugs associated.
Models
class Interaction < ActiveRecord::Base
has_and_belongs_to_many :genes
...
scope :disease_associated, -> { joins(genes: :diseases) }
scope :drug_target, -> { joins(genes: :drugs) }
...
end
class Gene < ActiveRecord::Base
has_and_belongs_to_many :interactions
has_and_belongs_to_many :drugs
...
end
class Drug < ActiveRecord::Base
has_and_belongs_to_many :genes
end
class Disease < ActiveRecord::Base
has_and_belongs_to_many :genes
end
Interaction Controller
class InteractionsController < ApplicationController
...
@interactions = @interactions.disease_associated() if params[:filter_disease].present?
@interactions = @interactions.drug_target() if params[:filter_druggable].present?
...
I haven't found any approaches / questions that obviously address this though that may be a result of me not being able to find the words to address the problem concisely enough to search effectively.
Thanks in advance!
In Rails 4 I can propose two options:
ids = []
ids |= Interaction.disease_associated.pluck(:id) if params[:filter_disease].present?
ids |= Interaction.drug_target.pluck(:id) if params[:filter_druggable].present?
interactions = Interaction.where(id: ids)
Clear, but not good if there are many Interactions in database.
Gem active_record_union gem provides SQL UNION
support for Rails.
interactions = Interaction.none
interactions = interactions.union(Interaction.disease_associated) if params[:filter_disease].present?
interactions = interactions.union(Interaction.drug_target) if params[:filter_druggable].present?
P.S. Common Advise: Design your DB by common queries not by Domain.