SsPay
SsPay

Reputation: 191

How to combine two activerecord relations

I have model User and User has column provider.

Provider can be google, facebook or nil.

I want to make scope, that will output all users, except users with provider google and older that some time.

I tried to do it with two scopes:

scope :not_google_authorised, -> { where(provider: [nil, 'facebook']) }
scope :newest_google, -> { where(provider: 'google').where("created_at < ?", Time.now)}
...
users = User.not_google_authorised
users << User.newest_google

It get right results, but it changed class of users. I need that users will be activerecord relations, not array. I tried do:

users = User.not_google_authorised
users.merge(User.newest_google)
#or
users.or(User.newest_google)

But it doesn't work for me.

How can i combine this 2 scopes, so users will be activerecord relations, or how can i write one scope instead their?

I use ruby v3.3.7 and rails v4.1

Upvotes: 1

Views: 2069

Answers (3)

Eyeslandic
Eyeslandic

Reputation: 14910

One way is to do this, not super optimized but gets the job done.

not_google_auth_ids = User.not_google_authorized.ids
newest_ids = User.newest_google.ids
ids = not_google_auth_ids + newest_ids

users = User.where(id: ids)

Upvotes: 2

kamal mehra
kamal mehra

Reputation: 9

we can right in a single scope that way:

scope :not_authorised, -> { where("(provider = ? and created_at < ?) or provider != ?",'google', Time.now, 'google' }

Upvotes: 0

engineersmnky
engineersmnky

Reputation: 29598

ActiveRecord::QueryMethods#or did not exist until rails 5.

Also the current stable ruby version is 3.0.0 which means you cannot be using 3.3.7 as it does not exist yet (and may never exist).

merge will combine using AND (intersection).

So your best bet is to use raw SQL where or Arel like:

where(
  User.arel_table[:provider].eq(nil).or(
    User.arel_table[:provider].eq('facebook')
  ).or(
    User.arel_table[:provider].eq('google').and(
      User.arel_table[:created_at].lt(Time.now)
    )
  )
)

This should result in:

SELECT 
  "users".*
FROM 
  "users" 
WHERE 
  ("users"."provider" IS NULL OR "users"."provider" = 'facebook')
   OR ( "users"."provider" = 'google' AND "users"."created_at" < [SOME TIME]

Upvotes: 2

Related Questions