Rails:改进模型中的if语句

时间:2016-10-17 16:38:53

标签: ruby-on-rails ruby if-statement model solid-principles

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

我特别在谈论&#39;过滤&#39;范围。在我的事件控制器索引acion我总是调用过滤范围提供&#39;过滤&#39;并且&#39; kind&#39;从params获得适当的事件,但我找不到使用那些丑陋if语句的方法。我的主要目标是让它变得坚固。

2 个答案:

答案 0 :(得分:1)

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

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 :(得分:0)

我倾向于将这些东西移到一个单独的类中,称之为类似EventQuery,并使用filter,kind和user初始化它。

然后根据您可以在控制器中使用的事件模型返回ActiveRelation对象。模型中与过滤相关的所有代码都将移动到那里。

您的控制器代码看起来像

@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