我只是想知道是否有机会重新审视下面的代码并进行一些代码重构?
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”):
答案 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
语句,因为预加载的关联将仅包括与关系连接条件匹配的记录。
我真的希望您对这一点进行了充分的测试,或者希望有人可以验证此行为的有效性。