Rails:改进模型中的 if 语句

Rails: improve if statements in model

我的问题如下:如何改进 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

我具体说的是 'filtered' 范围。在我的事件控制器索引 acion 中,我总是从参数中调用提供 'filter' 和 'kind' 的过滤范围来获取正确的事件,但我找不到不使用那些丑陋的 if 语句的方法。我的主要目标是让它变得坚固。

我倾向于将这些东西移到一个单独的 class 中,将其称为 EventQuery 之类的东西,并使用过滤器、种类和用户对其进行初始化。

然后 return 基于事件模型的 ActiveRelation 对象,您随后可以在控制器中使用该对象。您模型中与过滤相关的所有代码都将移到那里。

您的控制器代码如下所示

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

并且在视图中,您将访问事件查询中的方法 class

@event_query.results

另外一个说明和可能的解决方法,你不需要做'scopes'。一个 class 方法 return 是一个活跃的关系也同样好。

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

您可以使用 switch case 使其更具可读性,并将范围块移动到 class 方法中。

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)