2012-10-22 3 views
1

사용자와 : books간에 has_and_belongs_to_many 관계가 있습니다. 그들은 다음과 같이 합류했습니다 : owned_books 모델. 내 응용 프로그램의 한 기능은 동일한 책을 읽은 사용자를 연결하는 것입니다. 지금이 순간, 나는 비효율적으로 내 모델이 처리 :레일 3 : HABTM 관계를위한 조인 문 작성

users_hash = Hash.new 
    users = User.all 
    users.each do |user| 
    if user != current_user 
     users_hash[user.id] = 0 
     user.books.each do |book| 
     if current_user.books.include?(book) 
      users_hash[user.id]+=1 
     end 
     end 
    end 
    end 
    users_hash = users_hash.sort {|a,b| b[1]<=>a[1]} 
    @users = Array.new 
    users_hash[0..max].each do |id| 
    user = User.find(id[0]) 
    @users << user 
    end 
end 

내가이 일을 할 수있는 데이터베이스를 얻을 수있는 방법이 생각합니다. 나는이처럼 보이는 MySQL의 쿼리를 놀겠다는 거 봤는데 : 내 의도는 그 책의 얼마나 많은을보기 위해 다른 모든 사용자를위한 수를 얻을 후 CURRENT_USER가 읽은 책에 가입하는 것입니다

@users = User.select("users.*, COUNT(books) AS shared_books").joins("LEFT JOIN books ON ???").order("shared_books DESC").limit(100) 

그들은 읽었습니다. 그러면이 수를 기준으로 결과를 주문하고 상위 100 개의 결과로 제한합니다.

불행히도 내 MySQL 기술은 스너프가 아닙니다. 특히 조인 된 모델의 조건을 작성하는 방법을 잘 모르겠습니다. 또한 select 문이 제대로 작동하는지 의심 스럽지만 일단 솔리드 조인 문이 있으면 알아낼 수 있습니다.

+1

주목할 것은 일반적으로'Hash.new' 대신'{}'이 사용되고'Array.new'보다'[]'가 더 선호됩니다. 생성자를 호출하는 것은 해시 또는 배열이 작동하는 방식을 사용자 정의하는 데 필요합니다. – tadman

답변

0

데이터를 올바르게 구성하면 일반적으로 한 번의 작업으로 원하는 것을 가져올 수 있습니다. 귀하의 경우에는,이 구조에 약간을 조정해야 할 수도 있습니다 : 구현이 날짜까지 더 대부분 때문에, has_many :through 새로운는 has_and_belongs_to_many 방법을 통해 장점을 가지고 사용

class User < ActiveRecord::Base 
    has_many :owned_books 
    has_many :books, 
    :through => :owned_books 
end 

class OwnedBook 
    belongs_to :user 
    belongs_to :book 
end 

class Book 
    has_many :owned_books, 
    :as => :owned_by 
    has_many :users, 
    :through => :owned_by 
end 

뿐만 아니라 방법 때문에 해당 연관이 g 용되면 조인 모델에있는 데이터와 조인되는 모델을 구별합니다. OwnedBook은 실제로 id을 사용하여 변경, 업데이트 또는 폐기 할 수있는 일류 모델이므로 연관을 관리하는 것이 훨씬 쉽습니다.

이 경우 일반 도서와 사용자를 가져 오기하려면 다음을 수행하십시오이 중복 사용자를 방지 할 수 있기 때문에

User.where('id IN (SELECT DISTINCT user_id FROM owned_books WHERE book_id IN (SELECT book_id FROM owned_books WHERE user_id=?))', @user.id)).all 

이 좀 장황한이다. 일반 서적으로 사용자를 가져온 경우 사용자 당 여러 개의 일치 항목이 표시 될 수 있습니다. 이것이 DISTINCT 조건이 쿼리에 추가 된 이유입니다.

+0

사용자를 주문하지 않아도 작동하는 것으로 보입니다. 내 의도는 사용자가 current_user와 공유하는 책의 수를 순서대로 나열하는 것입니다. User.select ('users. *, COUNT (중고 book_id에서 SELECT book_id FROM owned_books WHERE user_id =?) AS shared_books)', current_user.id) .order ("shared_books DESC "). limit (100) – nullnullnull

+0

불행하게도, 인수의 개수가 잘못되었습니다. (1 : 2) – nullnullnull

+0

'select' 메소드는 하나의 인수를 취하므로 질의에'sanitize_sql'을 실행하지 않으면 작동하지 않을 수 있습니다 . 'user_id' 인수를 받아들이고 결과를 반환하는 클래스 메소드를 만들면 해당 메소드에 쉽게 액세스 할 수 있습니다. – tadman