Combina due oggetti ActiveRecord :: Relation

Supponiamo che abbia i seguenti due oggetti:

first_name_relation = User.where(:first_name => 'Tobias') # ActiveRecord::Relation last_name_relation = User.where(:last_name => 'Fünke') # ActiveRecord::Relation 

è ansible combinare le due relazioni per produrre un object ActiveRecord::Relation contenente entrambe le condizioni?

Nota: sono consapevole di poter concatenare le posizioni per ottenere questo comportamento, ciò a cui sono realmente interessato è il caso in cui sono presenti due distinti oggetti ActiveRecord::Relation .

Se vuoi combinare usando AND (intersezione), usa merge :

 first_name_relation.merge(last_name_relation) 

Se si desidera combinare utilizzando OR (unione), utilizzare or (disponibile in ActiveRecord 5+ o in 4.2 tramite where-or backport ):

 first_name_relation.or(last_name_relation) 

Gli oggetti relation possono essere convertiti in array. Questo nega di essere in grado di utilizzare qualsiasi metodo ActiveRecord su di essi in seguito, ma non ne ho avuto bisogno. L’ho fatto:

 name_relation = first_name_relation + last_name_relation 

Ruby 1.9, rails 3.2

merge realtà non funziona come OR . È semplicemente intersezione ( AND )

Ho lottato con questo problema per combinare gli oggetti ActiveRecord :: Relation in uno e non ho trovato alcuna soluzione funzionante per me.

Invece di cercare il giusto metodo per creare un’unione da questi due set, mi sono concentrato sull’algebra degli insiemi. Puoi farlo in modo diverso usando la legge di De Morgan

ActiveRecord fornisce il metodo di unione (AND) e inoltre è ansible utilizzare non il metodo o none_of (NOT).

 search.where.none_of(search.where.not(id: ids_to_exclude).merge(search.where.not("title ILIKE ?", "%#{query}%"))) 

Hai qui (A u B) ‘= A’ ^ B ‘

AGGIORNAMENTO: la soluzione sopra è buona per i casi più complessi. Nel tuo caso questo sarà sufficiente:

 User.where('first_name LIKE ? OR last_name LIKE ?', 'Tobias', 'Fünke') 

Sono stato in grado di farlo, anche in molte situazioni strane, usando Arel integrato di Rails.

 User.where( User.arel_table[:first_name].eq('Tobias').or( User.arel_table[:last_name].eq('Fünke') ) ) 

Questo unisce entrambe le relazioni ActiveRecord usando Arel o .


Unire, come è stato suggerito qui, non ha funzionato per me. Ha abbandonato il secondo set di oggetti relazionali dai risultati.

C’è una gem chiamata active_record_union che potrebbe essere ciò che stai cercando.

Gli usi di esempio sono i seguenti:

 current_user.posts.union(Post.published) current_user.posts.union(Post.published).where(id: [6, 7]) current_user.posts.union("published_at < ?", Time.now) user_1.posts.union(user_2.posts).union(Post.published) user_1.posts.union_all(user_2.posts) 

Questo è il modo in cui l’ho “gestito” se si usa il trucco per ottenere un identificatore per ciascuno dei record, unire gli array e infine eseguire una query per gli ID uniti:

  transaction_ids = @club.type_a_trans.pluck(:id) + @club.type_b_transactions.pluck(:id) + @club.type_c_transactions.pluck(:id) @transactions = Transaction.where(id: transaction_ids).limit(100) 

Se disponi di una serie di relazioni tra dispositivi e desideri unirli tutti, puoi farlo

 array.inject(:merge) 

Forza brutale:

 first_name_relation = User.where(:first_name => 'Tobias') # ActiveRecord::Relation last_name_relation = User.where(:last_name => 'Fünke') # ActiveRecord::Relation all_name_relations = User.none first_name_relation.each do |ar| all_name_relations.new(ar) end last_name_relation.each do |ar| all_name_relations.new(ar) end 

Mi sono imbattuto in questo numero una manciata di volte e le risposte generalmente accettate non hanno mai funzionato per me.

La soluzione proposta nella risposta accettata sembrava funzionare meglio:

 first_name_relation.or(last_name_relation) 

Ma non potrei mai farlo funzionare e riceverei sempre un errore ‘metodo non definito’ per ‘o’.

La mia soluzione:

 combined_relation = first_name_relation + (last_name_relation - first_name_relation) 

Questo mi dà essenzialmente i risultati di una UNION tra le query originali e gli oggetti di relazione sono ancora gli oggetti ActiveRecord corretti.

Questo è simile alla risposta fornita da @thatmiddleway, anche se avevo bisogno di aggiungere la sottrazione per ottenere una collezione di oggetti DISTINCT. Ciò converte la raccolta combinata in un ARRAY, ma potrei comunque chiamare i metodi del modello sulle singole istanze in un “iteratore” ciascuno nella mia vista, che ha risolto il mio problema.

Questa è la mia prima risposta StackOverflow (sussulto!), Quindi accolgo con favore il tuo feedback!