调用方法中的Rails代码重构以处理地图

时间:2019-10-30 12:31:12

标签: ruby-on-rails ruby

我只是想知道是否有机会重新审视下面的代码并进行一些代码重构?

def call
  inq_proc_ids = InquiryProcess.all.includes(inquiry_field_responses: :inquiry_field).select do |process|
    process.inquiry_field_responses.select do |inquiry_field_responses|
      inquiry_field_responses.inquiry_field.name == 'company_name'
    end.last&.value&.start_with?(company_filter)
  end.map(&:id)
  InquiryProcess.where(id: inq_proc_ids)
end

我认为我应该只在自己的调用方法中保留InquiryProcess.where(id:inq_proc_ids),但我不知道如何处理所有这些.last&.value&.start_with?(company_filter).map(&:id)东西。

编辑:

我试图将其拆分为新方法

def call
  InquiryProcess.where(id: inquiry_process_id)
end

private

attr_reader :company_filter, :inquiry_field_response

def inquiry_process_id
  InquiryProcess.all.includes(inquiry_field_responses: :inquiry_field).select do |process|
    process.inquiry_field_responses.select_company_name
  end.map(&:id)
end

def select_company_name
  select do |inquiry_field_responses|
    inquiry_field_responses.inquiry_field.name == 'company_name'
  end.last&.value&.start_with?(company_filter)
end

但我遇到了错误:

  

NoMethodError(ActiveRecord :: Associations :: CollectionProxy []>的未定义方法“ select_company_name”):

1 个答案:

答案 0 :(得分:1)

您发布的代码不仅难以遵循,而且我记得在查询中使用预先计算的ID时,ActiveReocrd缓存存在大量内存泄漏。

也就是说,我会尝试在单个sql查询中利用以上内容:

def call
  id_select = InquiryProcess
    .joins(inquiry_field_responses: :inquiry_field)
    .where(inquire_fields: { name: 'company_name' })
    .where(InquiryField.arel_table[:value].matches("#{company_filter}%"))
    .select(:id)

  InquiryProcess.where(id: id_select)
end

请注意,id_select不是ID数组,而是ActiveRecord范围,上面的内容将转换为以下SQL:

SELECT "inquiry_processes".* 
  FROM "inquiry_processes" 
  WHERE "inquiry_processes"."id" IN (
    SELECT "inquiry_processes"."id"
      FROM "inquiry_processes"
      INNER JOIN ...
      WHERE ...
  ) 

并回答另一个问题-为什么我们通过将id与同一表上另一个子查询的结果匹配来查询表?这是为了避免在处理具有联接的活动记录关系时遇到的各种痛苦问题-例如这会影响所有其他includes语句,因为预加载的关联将仅包括与关系连接条件匹配的记录。

我真的希望您对这一点进行了充分的测试,或者希望有人可以验证此行为的有效性。