重构复杂仪表板的最佳方法

时间:2013-06-09 19:44:05

标签: ruby-on-rails ruby-on-rails-3 design-patterns refactoring

TL; DR

我需要一种方法来重构具有多个对象和一些复杂数据的复杂用户仪表板,以显示会计图表。我的模型和控制器非常混乱,所以如果有人有一些提示或建议,我真的很感激它:))!

长版:

我目前正致力于帮助用户协调晚宴俱乐部和所有相关会计的应用程序。 (晚餐俱乐部是团体中的人,轮流做饭休息,然后你支付少量参与。这在宿舍和大学里很正常)。当您登录时,您会看到一个仪表板,其中包含所有重要信息,分为三个区块:下一个晚餐和注册选项,下一个必须烹饪的晚餐,以及会计概览,如当前的债务,支出等。

这变得非常混乱:我的控制器中有很多实例变量,还有很多方法可以在我的模型中显示这个视图。

现在谈到真正的问题:有人能告诉我任何好的提示,设计模式或一般建议来帮助我重构这段代码吗?我已经阅读过有关演示者,服务对象,装饰器等的内容,但我不确定使用哪种以及如何使用?

以下是一些现在看起来有多糟糕的例子(厨房是一群共进晚餐的人):

# app/controllers/dashboard_controller.rb
def index
  @user = current_user
  @kitchen = @user.kitchen

  @upcoming_dinner_clubs = @user.upcoming_dinner_clubs # The next dinner clubs where the current user have to cook
  @users_next_dinner_club = @user.next_dinner_club # The first of upcoming_dinner_clubs
  @unpriced_dinner_clubs = @user.unpriced_dinner_clubs # Old dinner clubs where the user haven't specified a price yet

  # The next dinner club in the kitchen
  @next_dinner_club = @kitchen.next_dinner_club if @kitchen.next_dinner_club
  @todays_dinner_club = @next_dinner_club if @next_dinner_club && @next_dinner_club.date.today?
end

下面的视图显示了通过javascript呈现的用户费用和支出的一些图表。我的观点是haml。

# app/views/dashboard/_expenses.html.haml
%h2 Dit forbrug
  %p
    = t '.usage_html', expenses: number_to_currency(@user.last_month_expenses), spendings: number_to_currency(@user.last_month_spendings), results: number_to_currency(@user.last_month_results)
    = content_tag :div, "", id: "revenue_chart", class: "chart dashboard-chart", data: { chart: @user.usage_chart_data }
    = t '.results_html', results: number_to_currency(@user.total_results)
    = content_tag :div, "", id: "result_chart", class: "chart dashboard-chart", data: { chart: @user.result_chart_data }

不要让你厌烦所有细节,以及方法如何运作,但这是我的方法,仅用于在视图中显示费用和支出数据:

# app/models/user.rb
def last_month_expenses
  expenses_for((1.month + 1.day).ago, 1.day.ago)
end

def last_month_spendings
  spendings_for((1.month + 1.day).ago, 1.day.ago)
end

def last_month_results
  results_for((1.month + 1.day).ago, 1.day.ago)
end

def spendings_for(start_date, end_date, kitchen)
end

def expenses_for(start_date, end_date, kitchen)
end

def fee_for(start_date, end_date, kitchen)
end

def accounting_query_conditions(start_date, end_date, kitchen)
  {date: start_date..end_date, kitchen_id: kitchen.id}
end

def results_for(start_date, end_date)
  spendings_for(start_date, end_date) - expenses_for(start_date, end_date)
end

def total_fee(date = Date.today, kitchen = primary_kitchen)
end

def total_spendings(date = Date.today, kitchen = primary_kitchen)
end

def total_used_on_dinner_clubs(date = Date.today, kitchen = primary_kitchen)
end

def total_expenses(date = Date.today, kitchen = primary_kitchen)
end

def total_results(date = Date.today, kitchen = primary_kitchen)
  total_expenses(date, kitchen) - total_spendings(date, kitchen)
end

1 个答案:

答案 0 :(得分:3)

让我们从规则开始,看看它需要多远:

控制器中只有1个实例变量

为了遵循这条规则,我认为你可能想要创建一个UserDashboard对象

class UserDashboard

  attr_reader :user
  def initialize(user)
    @user = user
  end

  def kitchen
    user.kitchen
  end

  def todays_club
    next_dinner_club if next_dinner_club && next_dinner_club.date.today?
  end

end

所以,在你的控制器中:

def index
  @dashboard = UserDashboard.new current_user
end

通过这种方式,您将关于球杆和其他任何内容的逻辑放在仪表板对象上,而不是放在控制器或用户对象中。这是一种类似主持人的模式。