简体   繁体   English

Rails和ActiveRecord-重构多个相同的where子句

[英]Rails & ActiveRecord - refactoring multiple identical where clauses

I'm on Rails 5. 我在Rails 5上。

I've got to deal with a pretty complex query with multiple identical where clauses : 我必须使用多个相同的where子句来处理一个非常复杂的查询:

::AllocatedBudget.joins(:account_code, :budget, account_code: [:place],
                          budget: [:fiscal_year, :budget_state])
                    .where(immeuble:            { id: place.id })
                    .where(situation_budget:    { codesituation: ['A', 'V']})
                    .where(plan_comptable:      { supprime: 'false' })
                    .where(budget:              { supprime: 'false'})
                    .where(situation_budget:    { supprime: 'false' })
                    .where(budget_previsionnel: { supprime: 'false' })
                    .where(exercice_comptable:  { supprime: 'false' })

First, you must know that my models are connected to an old database with ugly names. 首先,您必须知道我的模型以丑陋的名字连接到一个旧数据库。 I've noticed that ActiveRecord need the custom names instead the models's names to perform the queries. 我注意到ActiveRecord需要自定义名称而不是模型名称来执行查询。 I don't know why but it works only that way... If somebody could explain that it would be nice ;) 我不知道为什么,但是它只能那样工作...如果有人可以解释说那会很好;)

My real question is : can I write it in a better way ? 我真正的问题是:我可以用更好的方式编写它吗? There is so many time the same where clause "supprime = 'false' ". 相同的where子句“ supprime ='false'”有很多次。

Thanks a lot ! 非常感谢 ! :) :)

I would break the problem into two steps 我将问题分为两个步骤

  1. Create a hash of all your conditions using pure ruby code 使用纯红宝石代码创建所有条件的哈希
  2. Pass the entire hash into where . 将整个哈希传递到where

So step one is something like this. 所以第一步就是这样。

same_conditions_list = [
  :plan_comptable, 
  :budget, 
  :situation_budget, 
  :budget_previsionnel, 
  :exercice_comptable
]

same_conditions_key_values = same_conditions_list.inject({}) do |conditions, condition|
  conditions[condition] = { supprime: 'false' }
  conditions
end   

same_conditions = Hash[same_conditions_key_values]      

all_conditions = same_conditions.merge({
  immeuble: { id: "place.id" }
})       

After that all_conditions will equal this 之后all_conditions将等于

{
  :plan_comptable=>{:supprime=>"false"},
  :budget=>{:supprime=>"false"},
  :situation_budget=>{:supprime=>"false"},
  :budget_previsionnel=>{:supprime=>"false"},
  :exercice_comptable=>{:supprime=>"false"},
  :immeuble=>{:id=>"place.id"}
}

Then step two would just be 然后第二步就是

::AllocatedBudget.joins(:account_code, :budget, account_code: [:place],
                      budget: [:fiscal_year, :budget_state])
                  .where(all_conditions)

Finaly I tried the design pattern "Query Object" with a mix of the solution of AndrewSwerlick 最后,我尝试了混合使用AndrewSwerlick解决方案的设计模式“查询对象”

module QueryObject
  class AllocatedBudgetQuery

    def self.call(filters = {}, relation = ::AllocatedBudget.all)
      new(filters, relation).tap(&:call)
    end

    # filter can have the key/value as follow (key are symbols) :
    # place_id/string
    # current_fiscal_year/boolean
    # budget_state/['A', 'V', '*']
    def initialize(filters = {}, relation = ::AllocatedBudget.all)
      @relation     = relation
      @filters      = filters
    end

    def call
      conditions = {
        budget_previsionnel: { supprime: 'false' },
        budget: { supprime: 'false' }
      }

      # place filter
      conditions = conditions.merge(immeuble: { id: @filters[:place_id] }) if @filters.key?(:place_id)

      # situation budget filter
      conditions = conditions.merge(situation_budget: { codesituation: @filters[:budget_state] }) if @filters.key?(:budget_state)

      # main extract
      @relation = @relation.joins(:account_code,
                                  account_code: [:place],
                                  budget: %i[fiscal_year budget_state])
                           .where(conditions)

      # current fiscal year filter
      @relation = @relation.where("#{Date.today.to_s} between exercice_comptable.datedebutexercice and exercice_comptable.datefinexercice") if @filters.key?(:current_fiscal_year)
    end
  end
end

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM