У меня есть модель WorkSpace, которую has_many Отзывы. Модель «Обзоры» имеет список атрибутов, каждый из которых рассчитывает свой средний рейтинг. Я бы хотел, чтобы пользователи могли находить WorkSpaces с атрибутом с наивысшим рейтингом по своему выбору.
Я смог добиться этого, используя области и сохраняя логику c внутри модели WorkSpace.
Это моя первая попытка сделать любой вид логики c в Rails, и мне интересно, будет ли эта логика c лучше в контроллере. Это работает хорошо, но информация, которую он генерирует, прикрепляется к каждому WorkSpace, и я думаю, что это немного избыточно, поскольку единственный раз, когда пользователю потребуется доступ к этим данным, это когда они используют систему фильтрации, а не каждый раз, когда нажимают на WorkSpace.
Модель WorkSpace (половина с логикой c Я обсуждаю)
class WorkSpace < ApplicationRecord
belongs_to :user
has_many :reviews, dependent: :delete_all
scope :max_rating, ->(rating) { joins(:reviews)
.group('work_spaces.id')
.order('AVG(reviews.rating) desc')
.having('AVG(reviews.rating) > ?', rating) if rating }
scope :max_bathroom, ->(bathroom) { joins(:reviews)
.group('work_spaces.id')
.order('AVG(reviews.bathroom) desc')
.having('AVG(reviews.bathroom) > ?', bathroom) if bathroom }
scope :max_noise, ->(noise) { joins(:reviews)
.group('work_spaces.id')
.order('AVG(reviews.noise) desc')
.having('AVG(reviews.noise) > ?', noise) if noise }
scope :max_wifi, ->(wifi) { joins(:reviews)
.group('work_spaces.id')
.order('AVG(reviews.wifi) desc')
.having('AVG(reviews.wifi) > ?', wifi) if wifi }
scope :max_seating, ->(seating) { joins(:reviews)
.group('work_spaces.id')
.order('AVG(reviews.seating) desc')
.having('AVG(reviews.seating) > ?', seating) if seating }
def top_avg_rating
WorkSpace.max_rating(2).limit(5)
end
def top_avg_bathroom
WorkSpace.max_bathroom(2).limit(5)
end
def top_avg_noise
WorkSpace.max_noise(2).limit(5)
end
def top_avg_wifi
WorkSpace.max_wifi(2).limit(5)
end
def top_avg_seating
WorkSpace.max_seating(2).limit(5)
end
Модель обзора
# frozen_string_literal: true
class Review < ApplicationRecord
belongs_to :work_space
belongs_to :user
end
Сериализатор WorkSpace
class WorkSpaceSerializer < ActiveModel::Serializer
attributes :id,
:place_id,
:lat,
:lng,
:name,
:address,
:photo,
:reviews,
:user,
:count_reviews,
:avg_rating,
:avg_noise,
:avg_wifi,
:avg_bathroom,
:avg_food,
:avg_coffee,
:avg_seating,
:avg_outlet,
:bool_outlet,
:bool_seating,
:bool_coffee,
:bool_food,
:bool_bathroom,
:bool_wifi,
:top_avg_rating,
:top_avg_bathroom,
:top_avg_noise,
:top_avg_wifi,
:top_avg_seating
has_one :user
has_many :reviews
end
Может ли это или должен быть выполнен этот тип логики c в контроллере WorkSpace? И доступен только тогда, когда сделан запрос Ax ios GET? Или ... я далеко от базы, и я должен сейчас просто сдаться?
Обновление
До сих пор я смог Dry увеличить границы с этим бит кода.
scope :by_average_for, ->(column) {
joins(:reviews)
.group('work_spaces.id')
.order("AVG(reviews.#{column}) desc")
.having("AVG(reviews.#{column}) > 4", column) if column
}
Спасибо, { ссылка }.
Далее я работаю над реализацией метода класса. Не могу заставить это работать ...