Rails 4:复杂的搜索表单,通过各种关系过滤模型

时间:2014-02-04 18:14:45

标签: forms search ruby-on-rails-4 report analytics

我正在为网站进行一些报告/分析。目标是过滤到我从数据库查询并运行分析的一组@loans。希望使用数据库来获取已过滤的@loans,针对这些记录运行指标,然后返回要在页面上显示的指标。

这种关系并不是很复杂,但我所做的就是:

模型关系

# loan.rb
belongs_to :loan_category
belongs_to :loan_type
belongs_to :partner

# loan_category.rb
has_many :loans

# loan_type.rb
has_many :loans

# partner.rb
has_many :loans
belongs_to :company

# company.rb
has_many :partners

过滤表格

我将报告视为资源,因为用户可以将过滤器保存为saved_report。

用户按2个给定标准过滤:

  1. 他们想要什么类型的报告(合作伙伴,公司,loan_category,loan_type),只需选择四个中的一个(即按parter ID#3loan_type ID#6过滤,但绝不会超过一个) )
  2. 日期范围(从,到)
  3. 起初看起来相当微不足道,直到我开始尝试实现这一点。问题在于必须考虑各种情况:

    1. 需要一份仅按日期范围(基本上是仪表板页面)过滤的概览报告,以便如果用户未选择任何报告类型且仅提供日期,则显示概览报告
    2. 需要按提供的类型(合作伙伴,公司,loan_category,loan_type)和日期范围进行过滤
    3. 需要允许用户将过滤器保存为saved_report,以便在选择该报告时按条件快速过滤
    4. 我正试图以一种非常丑陋的方式来实现这一目标。这些例子将证明我的意思:

      • /reports =>概述报告,默认为当月。
      • /reports?from=2014-01-01 =>概述报告,从给定日期到当天
      • /reports/3 =>一个saved_report,可以按四个(partner,company,loan_category,loan_type)和日期范围中的任何一个进行过滤
      • /reports/partner?partner_id=3 =>以骇人的方式使用params[:id],我的控制器代码知道我想要由给定的合作伙伴过滤
      • /reports/loan_type?loan_type_id=7&from=2014-01-01&to=2014-01-31 =>再次使用params[:id]我知道按指定日期范围的给定loan_type进行过滤

      这会导致一些非常丑陋的控制器代码:

      报告控制器

      # always overview report; just filter by specified date range
      def index
        # Dummy code to show what I'm doing...
        @loans = Loan.where(created_at >= params[:from]).where(created_at <= params[:to])
      
        # ...use @loans to calculate metrics for report...
      end
      
      def show
        is_saved_report = false
        @saved_report = nil
      
        # feels very "hackish" to do this...
        case params[:id]
          when "partner"
            @loans = Loan.where(partner_id: params[:partner_id])
          when "company"
            @loans = Loan.includes(:partner).where(partner.company_id: params[:company_id])
          when "loan_category"
            @loans = Loan.where(loan_category_id: params[:loan_category_id])
          when "loan_type"
            @loans = Loan.where(loan_type_id: params[:loan_type_id])
          else
            # if none of the 4 "keywords" was used, assume it's a saved_report ID
            is_saved_report = true
            @saved_report = SavedReport.find(params[:id])
      
            # grab filters from @saved_report and use them to run ANOTHER case statement...
        end
      
        # add date range filters    
        if is_saved_report == true
          @loans.where(created_at >= @saved_report.from).where(created_at <= @saved_report.to)
        else
          @loans.where(created_at >= params[:from]).where(created_at <= params[:to])
        end
      
        # at this point, should have filtered list of @loans to run metrics on
        @total_loans = @loans.size
      
        # ...have to have more conditionals to display metrics for specific type of report...
      end
      

      正如您所看到的,代码非常快速地变得非常简单。必须有更好的方法来解决这个问题。我简直想不出一个更清洁的解决方案。我一直在研究这个问题,现在我没有想清楚。

      我对这种情况有任何建议或想法。一开始似乎微不足道的东西变得有点噩梦。

0 个答案:

没有答案