Rails has_many условия - PullRequest
       8

Rails has_many условия

1 голос
/ 30 марта 2010
    c = "(f.profile_id = #{self.id} OR f.friend_id = #{self.id})"
    c += AND + "(CASE WHEN f.profile_id=#{self.id} THEN f.friend_id ELSE f.profile_id END = p.id)"
    c += AND + "(CASE WHEN f.profile_id=#{self.id} THEN f.profile_rejected ELSE f.friend_rejected END = 1)"
    c += AND + "(p.banned = 0)"

Мне нужно, чтобы это использовалось в таких отношениях has_many:

    has_many :removed_friends, :conditions => ???

как мне установить там self.id? Или как передать туда идентификатор? Тогда я хочу использовать плагин will_paginate:

    @profile.removed_friends.paginate(:page => 1, :per_page => 20)

Спасибо за вашу помощь

EDIT:

 class Profile < ActiveRecord::Base
    has_many :friendships
    has_many :removed_friends, :class_name => 'Profile', :through => :friendships, :conditions => 
        "(friendships.profile_id = #{self.id} OR friendships.friend_id = #{self.id})"
        "AND (CASE WHEN friendships.profile_id=#{self.id} THEN friendships.profile_rejected ELSE friendships.friend_rejected END = 1)" + 
        "AND (p.banned = 0)"
  end


class Friendship < ActiveRecord::Base
  belongs_to :profile
  belongs_to :removed_friend, :class_name => 'Profile', :foreign_key => "(CASE WHEN friendships.profile_id = #{self.id} THEN friend_id ELSE profile_id END)"
end

Ответы [ 3 ]

3 голосов
/ 30 марта 2010

Используйте одинарные кавычки, чтобы заключить условие:

class Profile < ActiveRecord::Base
  has_many :friendships
  has_many :removed_friends, :class_name => 'Profile', :through => :friendships, 
                             :conditions => '
    ( friendships.profile_id = #{self.id} OR 
      friendships.friend_id = #{self.id}
    ) AND
    (CASE WHEN friendships.profile_id=#{self.id} 
          THEN friendships.profile_rejected 
          ELSE friendships.friend_rejected 
     END = 1
    ) AND 
    (p.banned = 0)'
end
1 голос
/ 30 марта 2010

Возможно, вы захотите разбить это на серию именованных областей, которые можно применять поэтапно, а не все сразу. В качестве примера извлеките запрещенную часть:

class Friend < ActiveRecord::Base
  named_scope :banned, lambda { |*banned| {
    :conditions => { :banned => banned.empty? ? 1 : (banned.first ? 1 : 0) }
  }}
end

@profile.friends.removed.banned(false).paginate(:page => 1, :per_page => 20)

Использование тяжелых условий в отношениях обязательно вызовет проблемы. Если возможно, попробуйте денормализовать таблицу, создать производные столбцы, которые имеют «простые» версии данных, или другие вещи, чтобы упростить запросы к ним.

0 голосов
/ 31 марта 2010

У вас действительно есть два отношения здесь. У вас есть:

  • Отклоненная дружба со стороны profile_id
  • Отклоненная дружба со стороны friend_id

Я не знаю, почему обе стороны могут отклонить дружбу, и, возможно, вам нужно немного посмотреть на вашу модель (какая сторона запрашивает ее? сказать, что это было отклонено со стороны profile?

Во всяком случае, я бы смоделировал это как два отдельных отношения:

class Profile
  has_many :rejected_friendships, :conditions => 'friendships.profile_rejected = 1'
  has_many :canceled_friendships, :foreign_key => 'friend_id', :conditions => 'friendships.friend_rejected = 1'

  named_scope :banned, lambda do |*banned| 
      { :conditions => {:banned => banned.empty? ? 1 : (banned.first ? 1 : 0) } }
  end

  has_many :rejected_friends, :class_name => 'Profile', :through => :rejected_friendships
  has_many :canceled_friends, :class_name => 'Profile', :through => :canceled_friendships

  def removed_friends
    (self.rejected_friends.banned(false).all + self.canceled_friends.banned(false).all).uniq
  end
end

Это несколько нежелательно, так как remove_friends больше не является отношением, поэтому вы больше не можете делать такие вещи, как Profile.removed_friends.find(:all, :conditions => {:name => "bleh"}), но это довольно сложный случай. Это условие довольно сложное.

...