2013-03-07 2 views
0

У меня есть соглашение класса, который имеет два BELONGS_TO ассоциации к классу членов, - ссылаться как на первичные и вторичные:Multiple присоединяется к одной и той же модели, используя несколько ассоциаций BELONGS_TO

class Agreement < ActiveRecord::Base 
    belongs_to :primary, class_name: 'Member' 
    belongs_to :secondary, class_name: 'Member' 
    ... 

    def self.by_member(member_attribute_hash) 
    # returns any agreements that has a primary OR secondary member that matches any of the values 
    # in the member_attribute_hash 
    ... 
    end 
end 

Класс член не имеет никакого знания ассоциации с классом соглашения - это не нужно:

class Member < ActiveRecord::Base 
    # contains surname, given_names, member_number 
    ... 

    def self.by_any(member_attribute_hash) 
    # returns any member where the member matches on surname OR given_names OR member_number 
    ... 
    end 
end 

то, что я хотел бы сделать, это поиск по всем договорам, где первичный или вторичный элемент спичек набора критериев.

Из предыдущей работы (see question #14139609), я разобрался, как построить условное предложение where для Member.by_any().

Попытка повторно использовать этот метод в то время как поиск Соглашений привел меня попробовать это:

class Agreement < ActiveRecord::Base 
    ... 

    def self.by_member(member_attribute_hash) 
    Agreement.joins{primary.outer}.merge(Member.by_any(member_attribute_hash)).joins{secondary.outer}.merge(Member.by_any(member_attribute_hash)) 
    end 
end 

При управлении это в консоли, с member_attribute_hash = {surname: 'Freud'}, сгенерированный SQL не выполняет псевдоним сгенерированный для второго присоединиться члену:

SELECT "agreements".* 
FROM "agreements" 
    LEFT OUTER JOIN "members" 
     ON "members"."id" = "agreements"."primary_id" 
    LEFT OUTER JOIN "members" "secondarys_agreements" 
     ON "secondarys_agreements"."id" = "agreements"."secondary_id" 
WHERE "members"."surname" ILIKE 'Freud%' 
    AND "members"."surname" ILIKE 'Freud%' 

Обратите внимание на дублирующие условия в предложении WHERE. Это вернет соглашения, в которых первичный член имеет фамилию типа «Фрейд», но игнорирует условие вторичного члена, потому что псевдоним не течет через слияние.

Любые идеи?

ответ

0

После борьбы, чтобы понять это, я в конечном итоге заменить Member.by_any области с Squeel sifter:

class Member < ActiveRecord::Base 
    # contains surname, given_names, member_number 
    ... 

    def self.by_any(member_attribute_hash) 
    # returns any member where the member matches on surname OR given_names OR member_number 
    squeel do 
     [ 
     (surname =~ "#{member[:surname]}%" if member[:surname].present?), 
     (given_names =~ "#{member[:given_names]}%" if member[:given_names].present?), 
     (member_number == member[:member_number] if member[:member_number].present?) 
     ].compact.reduce(:|) 
     # compact to remove the nils, reduce to combine the cases with | 
    end 
    end 
end 

Единственным отличием (код-накрест), bewteen в sifter и scope является заменой where в области с squeel в сито.

Таким образом, вместо использования merge для доступа к области Member.by_any из модели соглашения я теперь мог ссылаться на фильтр фильтра Member :by_any из модели соглашения. Это выглядело как:

class Agreement < ActiveRecord::Base 
    ... 

    def self.by_member(member_attribute_hash) 
    Agreement.joins{primary.outer}.where{primary.sift :by_any, member_attribute_hash}.joins{secondary.outer}.where{secondary.sift :by_any, member_attribute_hash} 
    end 
end 

Это исправили проблему синонимии - начинают праздновать!:

SELECT "agreements".* 
FROM "agreements" 
    LEFT OUTER JOIN "members" 
     ON "members"."id" = "agreements"."primary_id" 
    LEFT OUTER JOIN "members" "secondarys_agreements" 
     ON "secondarys_agreements"."id" = "agreements"."secondary_id" 
WHERE "members"."surname" ILIKE 'Freud%' 
    AND "secondarys_agreements"."surname" ILIKE 'Freud%' 

, но я до сих пор не получал результаты, которые я ожидал - праздник положить на удержание. Что случилось? AND в предложении where было неправильным. После того, как немного больше копания (и ночь вдали от компьютера), обновилась ум решил попробовать это:

class Agreement < ActiveRecord::Base 
    ... 

    def self.by_member(member_attribute_hash) 
    Agreement.joins{primary.outer}.joins{secondary.outer}.where{(primary.sift :by_any, member_attribute_hash) | (secondary.sift :by_any, member_attribute_hash)} 
    end 
end 

Производство этого:

SELECT "agreements".* 
FROM "agreements" 
    LEFT OUTER JOIN "members" 
     ON "members"."id" = "agreements"."primary_id" 
    LEFT OUTER JOIN "members" "secondarys_agreements" 
     ON "secondarys_agreements"."id" = "agreements"."secondary_id" 
WHERE ((("members"."surname" ILIKE 'Freud%') 
    OR ("secondarys_agreements"."surname" ILIKE 'Freud%'))) 

Ах сладкий ... рестарта праздник. .. теперь я получаю соглашения, у которых есть первичный или вторичный член, который соответствует правилам, определенным в одном ситтере.

И для всей работы, которую он сделал на Squeel, большой крик идет к Эрни Миллеру.

Смежные вопросы