осталось присоединиться к rails / mysql - PullRequest
2 голосов
/ 10 августа 2009

Я новичок в рельсах и пытаюсь выполнить левое соединение в MySQL.

есть два объекта - пользователь и сообщение.

пользователь has_and_belongs_to_many сообщений, сообщение has_and_belongs_to_many пользователей

В настоящее время, просто написав user.messages, я получаю следующий запрос в консоли

SELECT * FROM `messages` INNER JOIN `messages_users` ON `messages`.id = `messages_users`.message_id WHERE (`users_messages`.group_id = 1 )

Сообщение с ограниченным == false не подключено ни к одному пользователю, но доступно любому пользователю, и мне нужно добавить коллекцию Message.all (limited => false) в user.messages

запрос, который решит мою проблему:

select * from messages left join messages_users on messages_users.message_id=messages.id and messages_users.user_id=1 where (messages_users.user_id is NULL and messages.restricted=false) OR (messages_users.user_id=1 and messages.restricted=true);

как мне написать это в рельсах настолько элегантно, насколько это возможно?

было бы что-то вроде

Message.find(:all,:conditions => "(messages_users.user_id is NULL and messages.restricted=false) OR (messages_users.user_id=1 and messages.restricted=true)", :joins => "left join messages_groups on messages_users.message_id=messages.id and messages_users.user_id=1 " )

или это может быть лучше?

я использую рельсы 2.3.2

спасибо, Павел

Ответы [ 3 ]

1 голос
/ 10 августа 2009

почему бы не использовать: включить?

1 голос
/ 12 августа 2009

Мне кажется, что вы пытаетесь получить две вещи в этом запросе: 1) все сообщения, не связанные с пользователем с ограниченным = ложным, и 2) все сообщения, связанные с текущим пользователем с ограниченным = истинным.

Если я правильно понимаю, я не вижу лучшего способа сделать это, если вы хотите, чтобы это было одним запросом. Однако, если вы открыты к идее сделать два запроса, вы можете немного очистить его в коде (возможно, замедляя выполнение). Вот альтернативная установка:

class Message < ActiveRecord:Base
  has_and_belongs_to_many :users

  named_scope :restricted, :conditions => {:restricted => true}
  named_scope :unrestricted, :conditions => {:restricted => false}
  named_scope :public, :conditions => "id NOT IN (SELECT DISTINCT message_id FROM messages_users)"
end

class User < ActiveRecord:Base
  has_and_belongs_to_many :messages
end

Чтобы получить список с меньшим количеством кода, но для этого нужно выполнить два обращения к базе данных:

@current_user.messages.restricted + Message.unrestricted.public

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

Что, вероятно, сработало бы лучше с точки зрения модели, это избавиться от отношения HABTM и явно смоделировать отношение. Кроме того, у вас есть удобное место для отслеживания других данных о процессе отправки / доставки / получения сообщений (таких как отслеживание отправленного времени, считывание времени и т. Д.). Это не меняет ни одно из обсуждений выше, я просто предпочитаю, чтобы многие из них прошли через HABTM.

class Message < ActiveRecord:Base

  has_many :subscriptions
  has_many :users, :through => :subscriptions

  named_scope :restricted,   :conditions => {:restricted => true}
  named_scope :unrestricted, :conditions => {:restricted => false}
  named_scope :public, :conditions => "id NOT IN (SELECT DISTINCT message_id FROM subscriptions)"
end

class User < ActiveRecord:Base

  has_many :subscriptions
  has_many :messages, :through => :subscriptions

end

class Subscription < ActiveRecord:Base

  belongs_to :message
  belongs_to :user

end
0 голосов
/ 10 августа 2009

Я думаю, что named_scopes может быть вашим ответом. В вашей модели положить что-то вроде:

named_scope :restricted,   :conditions => {:restricted => true}
named_scope :unrestricted, :conditions => {:restricted => false}

Тогда вы можете назвать такие вещи, как:

Message.restricted
=> All restricted messages

User.first.messages.unrestricted
=> All unrestricted messages belonging to the first user.

Я считаю, что они работают через ассоциации HABTM.

...