Попробуйте следующие соотношения:
class Organization < ActiveRecord::Base
has_many :memberships
has_many :users, through: :memberships
has_many :books, -> { uniq }, through: :users
end
class User < ActiveRecord::Base
has_many :memberships
has_many :readings
has_many :organizations, through: :memberships
has_many :books, through: :readings
end
class Reading < ActiveRecord::Base
belongs_to :user
belongs_to :book
end
class Book < ActiveRecord::Base
has_many :readings
has_many :users, through: :readings
has_many :organizations, -> { uniq }, through: :users
end
Теперь вы можете звоните @organization.books
, чтобы получить все книги для определенной организации.
Я не знаю точно, как вы справляетесь рейтинги, но вы можете добавить область под названием rated
к вашей Book
модели, а затем вызвать @organization.books.rated
, чтобы получить все номинальные книги для конкретной организации. Вот пример того, что, что сфера может выглядеть следующим образом:
class Book < ActiveRecord::Base
has_many :readings
has_many :users, through: :readings
has_many :organizations, through: :users
scope :rated, -> { where.not(rating: nil) }
scope :rated_above, ->(rating) { where('rating >= ?', rating) }
scope :rated_below, ->(rating) { where('rating <= ?', rating) }
end
Это просто пример, если вы используете некоторое целое на основе рейтинговой системы, где nil
рейтинга означает, что она нерейтинговая. Я также выбрал области rated_above
и rated_below
, которые вы можете или не можете найти полезными. Вы можете использовать их как @organization.books.rated_above(6)
, чтобы получить книги с рейтингом, большим или равным 6. Опять же, это просто примеры, вам может потребоваться изменить их для работы с вашей реализацией рейтинга.
Update
В том случае, если ваши оценки сохраняются на Reading
модели, вы можете изменить свою Book
модель на следующее:
class Book < ActiveRecord::Base
has_many :readings
has_many :users, through: :readings
has_many :organizations, -> { uniq }, through: :users
scope :rated, -> { with_ratings.having('COUNT(readings.rating) > 0') }
scope :rated_above, ->(rating) { with_ratings.having('average_rating >= ?', rating) }
scope :rated_below, ->(rating) { with_ratings.having('average_rating <= ?', rating) }
private
def self.with_readings
includes(:readings).group('books.id')
end
def self.with_ratings
with_readings.select('*, AVG(readings.rating) AS average_rating')
end
end
Я не уверен, если есть это более простой подход, но он выполняет свою работу. Теперь области действия должны работать должным образом. Кроме того, вы можете отсортировать по рейтингу: @organization.books.rated.order('average_rating DESC')
Не следует отношение в организации быть 'has_many: пользователи, через:: memberships' (или' has_many: члены, через:: членство, источник:: user')? –
Да, обновил вопрос. – parker