Combining Multiple Named Scopes with Or

How to combine multiple scopes with OR

Rails supports #or for ActiveRecord::Relation from 5.

scope :combined_abc, -> { a.or(b).or(c) }

Note: a/b/c must be structurally compatible.

How to combine two scopes with OR

Answering my own question. I think I figured out a way.

where("pages.id IN (?) OR pages.id IN (?)",
Page.where(
"user_id IN (?) OR user_id = ?",
user.watched_ids, user.id
),
Page
.joins(:attachments)
.where("attachments.tag_id IN (?)", user.tags)
.select("DISTINCT pages.*")
)

It seems to be working so far, hope this is it!

Combine multiple scope or where queries with OR

Since you're open to using a third party library, how about Ransack?

It has a very robust implementation allowing for all kinds of and and or condition combinations and works well with associated models as well.

For a use case like yours where there are a few predefined queries/scopes that I want the user to be able to select from and run the or combination of them, I use ransack's out of the box implementation and then on the view level, I use javascript to insert hidden fields with values that will result in the structured params hash ransack is expecting in the controller.

All of your scopes are simple to define in a view using ransack helpers. Your code should look like:

Controller

def index
@q = Patient.search(params[:q])
@patients = @q.result(distinct: true)
end

View

<%= search_form_for @q do |f| %>
<%= f.label :older_than %>
<%= f.date_field :dob_lt %>
<%= f.label :with_gender %>
<%= f.text_field :gender_eq %>
<%= f.label :with_name_like %>
<%= f.text_field :name_cont %>
<%= f.label :in_arrears_exceeding %>
<%= f.text_field :accounts_total_due_gte %>
<%= f.submit %>
<% end %>

Also, if you want more control over the anding and oring take a look at the complex search form builder example using ransack.

Combining two named scopes into an aggregate scope

This appears to work:

scope :past_two_years_and_order_by_end_date, -> {self.past_two_years.order_by_end_date}

Is there a way to combine named scopes into a new named scope?

Well I'm still new to rails and I'm not sure exactly what you're going for here, but if you're just going for code reuse why not use a regular class method?


def self.ab(a, b)
a(a).b(b)
end

You could make that more flexible by taking *args instead of a and b, and then possibly make one or the other optional. If you're stuck on named_scope, can't you extend it to do much the same thing?

Let me know if I'm totally off base with what you're wanting to do.

Rails3: combine scope with OR

From Arel documentation

The OR operator is not yet supported. It will work like this:
users.where(users[:name].eq('bob').or(users[:age].lt(25)))

This RailsCast shows you how to use the .or operator. However, it works with Arel objects while you have instances of ActiveRecord::Relation.
You can convert a relation to Arel using Product.name_a.arel, but now you have to figure out how to merge the conditions.

Rails 5 joining activerecord scopes with OR


A scope represents a narrowing of a database query, such as where(color: :red).select('shirts.*').includes(:washing_instructions) (https://api.rubyonrails.org/classes/ActiveRecord/Scoping/Named/ClassMethods.html#method-i-scope)

Joining scopes using OR condition is not possible. A scope narrows resultset with some filter. Chaining scopes together is equivalent to using scope filters at the same time, ie SQL's AND condition.

For your case when 2 scopes need to be joined with OR you could merge their resultsets:

Vehicle.unassigned.to_a | Vehicle.driverless.to_a

but it's better to write another scope, as you already did.

In Rails5, how do I return the union of two scopes or combine them into one?

This blog has good explanation of issue you are facing.

To summarize here, you have to make sure the joins, includes, select (in short structure of AR data to be fetched) is consistent between both the scopes.

This syntax is the way to go as long as you make sure both the scopes have same joins.

Order.with_seller_like('pete').or(Order.with_customer_like('pete'))

To take first step, check if this works(not recommended though):

Order.where(id: Order.with_seller_like('pete')).or(Order.where(id: Order.with_customer_like('pete')))

I would recommend to move away from joins and use sub-query style of querying if you are looking for only Order data in output.



Related Topics



Leave a reply



Submit