2016-10-17 9 views
1

Мой вопрос заключается в следующем: как улучшить рельсы код модели, такие, как это:Rails: улучшить, если заявления в модели

class Event < ActiveRecord::Base 
    scope :upcoming, -> { where('date >= ?', Time.now) 
         .includes(:groups, :creator) 
         .reorder(date: :asc) } 
    scope :past, -> { where('date < ?', Time.now) 
        .includes(:groups, :creator) } 

    scope :connected, -> (user) { 
    user_groups_ids = user.groups_teacher.pluck(:id).uniq 
    joins(:groups).where('groups.id': user_groups_ids).uniq 
    } 
    scope :created, -> (user) { 
    where(user_id: user.id) 
    } 

    scope :filtered, -> (args) { 
    filter = args[:filter] 
    kind = args[:kind] 
    if(filter == 'upcoming' && kind == 'connected') 
     upcoming.connected(args[:user]) 
    elsif(filter == 'upcoming' && kind == 'created') 
     upcoming.created(args[:user]) 
    elsif(filter == 'past' && kind == 'connected') 
     past.connected(args[:user]) 
    elsif(filter == 'past' && kind == 'created') 
     past.created(args[:user]) 
    elsif(filter == 'upcoming') 
     upcoming 
    elsif(filter == 'past') 
     past 
    else 
     all  
    end 
    } 

    belongs_to :creator, class_name: "User", foreign_key: "user_id" 
    has_many :groups, through: :group_events 
    has_many :group_events 
    accepts_nested_attributes_for :groups 
    self.per_page = 5 
end 

Я специально говорю о "фильтрованной области видимости. В моих событиях index index acion я всегда вызываю фильтрованную область, предоставляющую «фильтр» и «вид» из параметров для получения правильных событий, но я не могу найти способ не использовать эти уродливые операторы if. Моя главная цель - сделать его SOLID.

ответ

0

Я стараюсь переместить эти вещи в отдельный класс, назовите его чем-то вроде EventQuery и инициализируйте его с помощью фильтра, вида и пользователя.

Затем верните объект ActiveRelation на основе модели Event, которую затем можно использовать в контроллере. Весь код в вашей модели, связанный с фильтрацией, будет перемещен туда.

Ваш код контроллера будет выглядеть

@event_query = EventQuery.new(filter, kind, current_user) 

и в представлении, вы бы доступ к методу в классе Event Query

@event_query.results 

Еще одно замечание и возможное решение, вы не нужно сделать «области». Метод класса, который возвращает активное отношение, также хорош.

def self.filtered(args) 
    filter = args[:filter] 
    kind = args[:kind] 
    if(filter == 'upcoming' && kind == 'connected') 
    upcoming.connected(args[:user]) 
    elsif(filter == 'upcoming' && kind == 'created') 
    upcoming.created(args[:user]) 
    elsif(filter == 'past' && kind == 'connected') 
    past.connected(args[:user]) 
    elsif(filter == 'past' && kind == 'created') 
    past.created(args[:user]) 
    elsif(filter == 'upcoming') 
    upcoming 
    elsif(filter == 'past') 
    past 
    else 
    all  
    end 
end 
1

вы можете использовать корпус переключателя, чтобы сделать его более читаемым и переместить блок видимости в класс.

def self.filtered(args) 
    filter = args[:filter] 
    kind = args[:kind] 
    case [filter, kind] 
    when ['upcoming', 'connected'] then upcoming.connected(args[:user]) 
    when ['upcoming', 'created'] then upcoming.created(args[:user]) 
    when ['past', 'connected'] then past.connected(args[:user]) 
    when ['past', 'created'] then past.created(args[:user]) 
    when ['upcoming', nil] then upcoming 
    when ['past', nil] then past 
    else 
    all 
    end 
end 

затем называют его Event.filtered(args)

+1

Right. Прямо из официального ** интерфейса API запросов ActiveRecord **: [«Использование метода класса является предпочтительным способом принятия аргументов для областей».] (Http://guides.rubyonrails.org/active_record_querying.html#passing-in- аргументы). –

+0

@muistooshort есть причина, почему метод класса предпочтительнее аргументов принятия области? – MrYoshiji

+0

@MrYoshiji Вероятно, потому что он менее грязный, и он «просто дублирует функциональность, которая будет предоставляться вам методом класса». Вы имели обыкновение говорить 'scope: s, где (...)' (т. Е. Нет лямбда), поэтому 'scope' был удобной стенографией; теперь немного менее удобно, когда требуются лямбда, и область, которая больше, чем один вызов 'where', быстро становится нечитаемым беспорядком. Я уверен, что за «областью» больше истории, поскольку они затащили ее в ногу и кричали в будущее, но я не знаю этого с головы. –