[ruby-on-rails] 두 개의 ActiveRecord :: Relation 객체를 결합

다음 두 개체가 있다고 가정합니다.

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

두 관계를 결합하여 두 ActiveRecord::Relation조건을 모두 포함 하는 하나의 객체 를 생성 할 수 있습니까?

참고 :이 동작을 수행 할 수있는 곳을 연결할 수 있다는 것을 알고 있습니다. 실제로 관심이있는 것은 두 개의 개별 ActiveRecord::Relation객체 가있는 경우 입니다.



답변

AND(교차)를 사용 하여 결합 하려면 merge다음을 사용하십시오 .

first_name_relation.merge(last_name_relation)

OR(union)을 사용 하여 결합 하려면 †를 사용하십시오 .or

first_name_relation.or(last_name_relation)

ActiveRecord 5+에서만; 4.2의 경우 위치 또는 백 포트를 설치하십시오 .


답변

관계 객체는 배열로 변환 될 수 있습니다. 이것은 나중에 ActiveRecord 메소드를 사용할 수 없다는 것을 부정하지만, 그럴 필요는 없었습니다. 나는 이걸했다:

name_relation = first_name_relation + last_name_relation

루비 1.9, 레일 3.2


답변

merge실제로는 작동하지 않습니다 OR. 단순히 교차로입니다 ( AND)

이 문제를 해결하기 위해 ActiveRecord :: Relation 객체를 하나로 결합했지만 아무런 해결책이 없었습니다.

이 두 세트에서 합집합을 만드는 올바른 방법을 찾는 대신 대수 세트에 중점을 두었습니다. De Morgan의 법칙을 사용하여 다른 방법으로 할 수 있습니다

ActiveRecord는 병합 방법 (AND)을 제공하며, not method 또는 none_of (NOT)를 사용할 수 있습니다.

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

당신은 여기에 있습니다 (A u B) ‘= A’^ B ‘

업데이트 : 위의 솔루션은 더 복잡한 경우에 좋습니다. 귀하의 경우에는 그런 것만으로 충분합니다.

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


답변

Rails의 내장 Arel 을 사용하여 많은 이상한 상황 에서도이 작업을 수행 할 수있었습니다 .

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

Arel 또는 을 사용하여 두 ActiveRecord 관계를 병합합니다 .


여기에 제안 된 것처럼 병합은 나를 위해 작동하지 않았습니다. 결과에서 두 번째 관계 개체 집합을 삭제했습니다.


답변

당신이 찾고있는 것일 수도있는 active_record_union 이라는 보석 이 있습니다.

사용법은 다음과 같습니다.

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)


답변

pluck을 사용하여 각 레코드의 식별자를 가져 와서 배열을 결합한 다음 마지막으로 결합 된 ID에 대한 쿼리를 수행하는 경우 다음과 같이 처리합니다.

  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)


답변

활성 레코드 관계 배열이 있고이를 모두 병합하려면 다음을 수행하십시오.

array.inject(:merge)