2016-08-31 4 views
1

나는 다음 모델레일 5. 잘못된 결과

user.rb

class User < ApplicationRecord 
    has_many :user_tags, dependent: :destroy 
    has_many :tags, through: :user_tags 
    has_many :children, foreign_key: 'parent_id', dependent: :destroy 

tag.rb

class Tag < ApplicationRecord 
    has_many :user_tags, dependent: :destroy 
    has_many :users, through: :user_tags 

user_tag.rb

이 모델 사용자에
class UserTag < ApplicationRecord 
    belongs_to :tag 
    belongs_to :user 

child.rb

class Child < ApplicationRecord 
    belongs_to :parent, class_name: 'User' 

나는 여러 범위를 가지고있다. 필요한 모든 태그와 관련된

선택 사용자 :

scope :search_by_tags, -> (ids) { 
    joins(:tags).where(tags: {id: ids}).having('COUNT(tags.id) >= ?', ids.count).group('users.id') 
} 

어느 옆 SQL 요청을 생성

SELECT "users".* FROM "users" INNER JOIN "user_tags" ON "user_tags"."user_id" = "users"."id" INNER JOIN "tags" ON "tags"."id" = "user_tags"."tag_id" WHERE "tags"."id" IN (17, 37, 70, 8, 11, 3, 91, 64) GROUP BY users.id HAVING (COUNT(tags.id) >= 8) 

다른 범위를 사용자, 특정 연령대의 어린이와 관련된

scope :children_in_ages, -> (age_ranges) { 
    joins(:children).where(children_ages_query(age_ranges)) 
     .where.not(children: {gender: -1}).group('users.id') 
} 

def self.children_ages_query(age_ranges) 
    child_table = Child.arel_table 
    range_conditions = age_ranges.map { |r| child_table[:birth_date].in(r) } 
    range_conditions.inject(range_conditions.shift, &:and).to_sql 
end 

여기서 age_ranges은 날짜 배열입니다. 이 스코프는 다음 SQL 쿼리를 생성합니다 :

SELECT "users".* FROM "users" INNER JOIN "children" ON "children"."parent_id" = "users"."id" WHERE ("children"."birth_date" BETWEEN '2016-02-29 08:35:00.322919' AND '2016-08-31 08:35:00.327283') AND ("children"."gender" != $1) GROUP BY users.id 

별도로 스코프가 올바르게 작동하지만 스코프를 병합 할 때 잘못된 결과가 나타납니다.

User.children_in_ages(a).search_by_tags(ids) 
    User Load (85.2ms) SELECT "users".* FROM "users" INNER JOIN "children" ON "children"."parent_id" = "users"."id" INNER JOIN "user_tags" ON "user_tags"."user_id" = "users"."id" INNER JOIN "tags" ON "tags"."id" = "user_tags"."tag_id" WHERE ("children"."birth_date" BETWEEN '2016-02-29 08:35:00.322919' AND '2016-08-31 08:35:00.327283') AND ("children"."gender" != $1) AND "tags"."id" IN (17, 37, 70, 8, 11, 3, 91, 64) GROUP BY users.id HAVING (COUNT(tags.id) >= 8) 

어떤 아이디어가 잘못되었을 수 있습니까?

+0

당신은 실제로 "범위"병합하지 않습니다, 당신은 다른 검색 상단에 "검색"하고 출력 SQL을 분석하여 나는 그것이 잘 작동 말할 수 있습니다. 의도 한 결과는 무엇입니까? 하나의 응답으로 두 쿼리가 결합 된 결과를 원하십니까? – shlajin

+0

@shlajin 예를 들어,'search_by_tags'는 ids [1, 2, 3]로 배열을 반환하고, children_in_ages는 ids [2, 3, 4]로 배열을 반환합니다. 기대되는 결과는 ids [2, 3]를 가진 사용자 배열이어야한다. 그래, 두 쿼리의 결합이 필요해. – Derk153

+0

나는 'having ('COUNT (tags.id)> =? ', ids.count)'을 사용하여 무엇을 달성하려고하는지 거의 이해하려고하지는 않지만, 할 수 없다. 'search_by_tags' 메소드의 목적은 무엇입니까? 그것은 단지 "지정된 태그와 관련된 사용자 표시"가 아닙니다. – shlajin

답변

0

내 문제의 해결책을 찾았습니다.

모델/user.rb 모델/user_tag.rb 이런 식으로

scope :users_with_tags, -> (ids) { 
    select(:user_id).where(tag: ids).having('COUNT(user_id) >= ?', ids.count).group('user_id') 
} 

, 체인

scope :search_by_tags, -> (ids) { where(id: UserTag.users_with_tags(ids)) unless ids.blank? } 

: 특정 태그를 사용자에게 선택

적절한 방법 다른 범위의 경우 올바르게 작동 함