2012-03-23 5 views
0

Каков наилучший способ написать «(x AND y) ИЛИ (a AND b)», где запрос в Rails?Каков наилучший способ написать «(x AND y) ИЛИ (a AND b)», где запрос в Rails?

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

Это работает, но выглядит ужасно. Есть ли более простой/лучший способ написать это?

class Conversation 
    def initialize(me, them) 
    @me = me 
    @them = them 
    end 

    def messages 
    t = Message.arel_table 
    results = Message.where(
     (t[:sender_id].eq(@me.id).and(t[:recipient_id].eq(@them.id))).or(
     t[:sender_id].eq(@them.id).and(t[:recipient_id].eq(@me.id))) 
    ) 
    end 
end 

ПРИМЕЧАНИЕ Благодаря Джимми, я закончил с:

class Conversation 
    def initialize(me, them) 
    @me = me 
    @them = them 
    end 

    def messages 
    me_to_them = "sender_id = :my_id AND recipient_id = :their_id" 
    them_to_me = "sender_id = :their_id AND recipient_id = :my_id" 
    Message.where(
     "#{me_to_them} OR #{them_to_me}", 
     {:my_id => @me.id, :their_id => @them.id} 
    ) 
    end 
end 

ответ

1

Вы можете очистить его немного с помощью строки SQL и синтаксис массива для интерполяции значения:

class Conversation < ActiveRecord::Base 
    def initialize(me, them) 
    @me = me 
    @them = them 
    end 

    def messages 
    Message.where(["(sender_id = ? AND recipient_id = ?) OR (sender_id = ? AND recipient_id = ?)", @me.id, @them.id, @them.id, @me.id]) 
    end 
end 
+0

Спасибо! Я не понимал, что могу просто использовать ИЛИ. Кроме того, поскольку AND берет на себя приоритет над OR в SQL, я могу отбросить некоторые скобки и в итоге получил следующее, что, по моему мнению, намного читаемо. 'me_to_them =" sender_id = #{@me.id} И recipient_id = # {@ them.id} "' 'them_to_me =" sender_id = #{@them.id} И recipient_id = #{@me.id } "' 'Message.where (" # {me_to_them} ИЛИ # {them_to_me} "). Order (" created_at DESC ")' – Mike

+0

Это немного опасно, поскольку строковая интерполяция не защищает от SQL-инъекции. Вместо этого вы должны использовать методы массива или хэша. Взгляните на Руководство по интерфейсу запросов ActiveRecord: http://guides.rubyonrails.org/active_record_querying.html –

+0

Отмечено и обновлено выше. Лучше? :) – Mike

0

Я построил аналогичную систему это раньше. Моя база данных была построена немного по-другому, однако, чтобы сделать запросы проще и позволяют для групповой беседы (более 2-х человек)

private_message_groups 
id | subject 

private_message 
id | group_id | private_message_group_id | user_id | message 

private_message_follow 
group_id | user_id | visible 

Таким образом, вы можете просто указать пользователю на private_message контроллер. Если вы хотите, чтобы я пошел глубже, я могу, но самое большое преимущество этой системы - теперь у вас есть система форума.

+0

Большое спасибо за ваш вклад, но вопрос я действительно просят здесь то, что это самый хороший способ, чтобы написать «(х и у) или (И b) «где запрос в Rails. Я уточню вопрос соответствующим образом. – Mike

0

У меня была такая же проблема. Я несколько раз искал веб-сайт и, наконец, нашел метод с именем grouping в Arel::FactoryMethods, который просто добавляет скобки вокруг выражения.

С этим ваш метод должен выглядеть следующим образом:

def messages 
    t = Message.arel_table 
    results = Message.where(
    t.grouping(t[:sender_id].eq(@me.id).and(t[:recipient_id].eq(@them.id))).or(
    t.grouping(t[:sender_id].eq(@them.id).and(t[:recipient_id].eq(@me.id)))) 
) 
end