İki ActiveRecord'u birleştirin :: İlişki nesneleri


174

Aşağıdaki iki nesneye sahip olduğumu varsayalım:

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

ActiveRecord::Relationher iki koşulu da içeren bir nesne üretmek için iki ilişkiyi birleştirmek mümkün mü?

Not: Bu davranışı elde etmek için nereye zincirleyebileceğimin farkındayım, gerçekten ilgilendiğim iki ayrı ActiveRecord::Relationnesnemin olduğu durum .


Yanıtlar:


202

AND(Kavşak) kullanarak birleştirmek istiyorsanız , şunu kullanın merge:

first_name_relation.merge(last_name_relation)

OR(Birleşim) kullanarak birleştirmek istiyorsanız kullanın :or

first_name_relation.or(last_name_relation)

Yalnızca ActiveRecord 5+ sürümlerinde; 4.2 için nereye veya backport'u yükleyin .


sonucun bir ActiveRecord::Relationtür olmasını istersem ne olur ?
Yeni İskenderiye

1
@NewAlexandria Evet, her durumda, Rails size nesnenin sınıfı hakkında yalan söylüyor.
Andrew Marshall

77
Birleştirme "OR" sürümü var mı?
Arcolye

8
Muhtemelen iki ilişkinizi birleştirmenin asıl sonucu budur. Unutmayın merge, bir kavşak değil, birleşme.
Andrew Marshall

5
Gelecekte #orbaşvurmak üzere, Ocak 2015'te ActiveRecord :: Relation'a yöntem eklenmiştir ve 2015'in sonlarında gönderilecek olan Rails 5.0'ın bir parçası olacaktır. OR operatörünün WHERE veya HAVING yan tümcelerini birleştirmek için kullanılmasına izin verir. Resmi sürümden önce ihtiyacınız varsa HEAD'a ödeme yapabilirsiniz. Bkz. Birleştirme Çekme Talebi # 16052 @Arcolye @AndrewMarshall @ Aldo-xoen-Giambelluca
Claudio Floreani

37

İlişki nesneleri dizilere dönüştürülebilir. Bu, daha sonra üzerlerinde herhangi bir ActiveRecord yöntemini kullanmayı reddeder, ancak ihtiyacım yoktu. Bunu ben yaptım:

name_relation = first_name_relation + last_name_relation

Yakut 1.9, raylar 3.2


Güncelleme: Yazık bu tarihe
Daniel Morris

68
Bir dizi gibi davranmaz, ilişkinizi bir diziye dönüştürür. O zaman artık .where () gibi ActiveRecord yöntemlerini kullanamazsınız ...
Augustin

1
Dönüş türünün ilişkiyi önemsemiyorsanız, birden çok sonucu first_name_relation | last_name_relation. "|" operatör de çoklu ilişkiler üzerinde çalışır. Sonuç değeri bir dizidir.
MichaelZ

11
Asıl soru şuydu: "Her iki koşulu da içeren bir ActiveRecord :: Relation nesnesi üretmek için iki ilişki birleştirilebilir mi?" Bu cevap bir dizi döndürür ...
courtsimas

Bu, birçok durum için mükemmel bir çözümdür. Yalnızca bir döngü numarasına ihtiyacınız varsa (örneğin, bir Array mı yoksa ActiveRecord :: İlişkisi mi olduğunu umursamıyorsanız) ve iki sorgunun yükünü önemsemiyorsanız, bu sorunu açık ve basit sözdizimi ile çözer. Keşke +2 yapabilseydim!
David Hempy

21

mergeaslında böyle çalışmıyor OR. Bu sadece kavşak ( AND)

Bu sorunla ActiveRecord :: Relation nesnelerini bir araya getirmek için mücadele ettim ve benim için herhangi bir çalışma çözümü bulamadım.

Bu iki kümeden bir birlik oluşturmak için doğru yöntemi aramak yerine kümelerin cebirine odaklandım. De Morgan yasasını kullanarak bunu farklı bir şekilde yapabilirsiniz

ActiveRecord birleştirme yöntemi (AND) sağlar ve ayrıca yöntem veya none_of (NOT) yöntemini de kullanabilirsiniz.

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

Buradasınız (A u B) '= A' ^ B '

GÜNCELLEME: Yukarıdaki çözüm daha karmaşık durumlar için iyidir. Sizin durumunuzda böyle bir şey yeterli olacaktır:

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

15

Bunu birçok tuhaf durumda bile Rails'in yerleşik Arel'sini kullanarak başardım .

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

Bu, hem ActiveRecord ilişkilerini Arel's veya .


Birleştirme, burada önerildiği gibi, benim için çalışmadı. Sonuçtan 2. ilişki nesnesini bıraktı.


2
Bu en iyi cevap, IMO. OR tipi sorgular için kusursuz çalışır.
thekingoftruth

Bunu işaret ettiğiniz için teşekkürler, bana çok yardımcı oldu. Diğer yanıtlar yalnızca küçük bir alan alt kümesi için çalışır, ancak IN deyimindeki on bin id'den yukarı doğru performans çok kötü olabilir.
onetwopunch

1
@KeesBriggs — bu doğru değil. Bunu Rails 4'ün tüm sürümlerinde kullandım.
6ft Dan

14

Aradığınız şey olabilir active_record_union adlı bir mücevher var .

Örnek kullanımları şöyledir:

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)

Paylaşım için teşekkürler. Gönderinizden dört yıl sonra bile, bu benim durumumdan bir birlik oluşturmam ransackve örneklerimi sağlam tutmam için tek çözüm oldu . acts-as-taggable-onActiveRecord
Benjamin Bojko

Bu taş kullanırken, modelde tanımlanmış kapsamlarınız varsa union () çağrısı tarafından döndürülen bir ActiveRecord :: İlişkisi alamayabilirsiniz. Bkz. Benioku içindeki ActiveRecord'daki Birliğin Durumu.
dechimp

9

Kayıtların her biri için bir tanımlayıcı almak, dizileri birlikte katılmak ve nihayet katılan bu kimlikleri için bir sorgu yapmak eğer pluck kullanırsanız ben bu şekilde "ele".

  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)

6

Bir dizi aktüatör-kayıt ilişkiniz varsa ve hepsini birleştirmek istiyorsanız,

array.inject(:merge)

array.inject(:merge)5.1.4. raylardaki aktiverecord ilişkileri dizisi için çalışmadı 5.1.4. Ama array.flatten!yaptı.
zhisme

0

Kaba kuvvet onu:

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

Rails3 'none' yöntemine sahip olmadığından bile, MyModel.none öğesini MyModel.where (1 = 2) olarak değiştirdikten sonra bile, Rails3'te # <MyModel: 0x ... için NoMethodError (tanımsız yöntem `stringify_keys '', - Rails3 'none' yöntemi olmadığından
JosephK
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.