Reputation: 13
I have a basic has_many relationship, modeled as such:
class Term < ActiveRecord::Base
has_many :acroynms
end
And
class Acronym < ActiveRecord::Base
belongs_to :term
end
I would like to write an arel relation that will pull terms based on the term's name, or an acronym's name. My relation is incorrect, but I'm looking to do something that would look like this:
terms = Term.arel_table
relation = terms[name].matches("%#{params['a']}%")
relation = relation.or(terms[:acronyms.name].matches("%#{params['a']}%"))
@results = Term.where(relation)
I would like to keep it in the relation, because I have many other composed conditions combined into that one relation (that I'm omitting here for brevity).
I'm using the relation, rather than just composing everything together on the final line is that the items that need to composed won't be known until runtime, depending on user input. My thought is using this model I'll be able to set up my relation, however complex it may be, and then just have that one line to set @results, regardless of the user input.
Is there a way to write this all in a relation? Otherwise, I suppose I'll need to resort to using arel's joins, but only join in situations where the user input calls for it, correct?
Upvotes: 1
Views: 409
Reputation: 13
To get around using an OR operator, I resolved this by using 3 queries, which is sub-optimal, but functional.
My first query looks for acronyms where the name is like the search parameter.
acronymQuery = query.includes(:acronyms).where('acronyms.name like ?', wildcard_search).select("terms.id")
The second looks for terms where the name is like the search parameter.
termQuery = query.where('terms.name like ?', wildcard_search).select("terms.id")
I then combine the unique IDs from each query, and my third query searches for those ids.
acronymQueryResults = acronymQuery.all.map {|row| row.id}
termQueryResults = termQuery.all.map {|row| row.id}
ids = (acronymQueryResults + termQueryResults).uniq
query = Term.where('id' => ids)
Upvotes: 0
Reputation: 13354
I'm not entirely sure how to do this using arel, but you could do something like this if you wanted to chain where
clauses based on parameters (or other input) the execute once it's built:
query = User.scoped
query = query.where("name like ?", "%#{params[:name]}%") if params[:name].present?
query = query.where("email like ?", "%#{params[:email]}%") if params[:email].present?
@users = query.all
Again, I know this is not exactly what you're going for, but could be a possible alternative.
Note: This won't do what you expect if you run it in console because the print
step of the REPL will execute each step, making it look like multiple queries when in a Rails app it will actually perform just one.
Upvotes: 1