문제
나는 레일에 초보자이며 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 )
제한된 메시지가있는 메시지가있는 메시지가 사용자에게 연결되어 있지 않지만 사용자가 액세스 할 수 있으며 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);
가능한 한 우아하게 레일에 쓰는 방법은 무엇입니까?
smth와 같은 것입니다
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 " )
아니면 더 좋을 수 있습니까?
나는 Rails 2.3.2를 사용하고 있습니다
고마워요, 파벨
해결책
그 쿼리에서 두 가지를 가져 오려고하는 것 같습니다. 1) 모든 메시지가 제한된 = false 및 2) 모든 메시지가 제한된 = true를 가진 현재 사용자에게 묶여 있습니다.
내가 그것을 올바르게 이해하고 있다면, 당신이 그것을 단일 쿼리로 만들고 싶다면 더 좋은 방법을 보지 못합니다. 그러나 두 쿼리를 만들 겠다는 아이디어에 열려있는 경우 코드에서 약간 정리할 수 있습니다 (실행 속도를 늦출 수 있음). 대체 설정은 다음과 같습니다.
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
다른 팁
사용하지 않는 이유 : 포함?
나는 이름의 _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 협회를 통해 믿는다.