Рефакторинг кода Rails в методе вызова для обработки карты - PullRequest
2 голосов
/ 30 октября 2019

Мне просто интересно, есть ли шанс по-новому взглянуть на приведенный ниже код и сделать какой-то рефакторинг кода?

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 (неопределенный метод `select_company_name 'для ActiveRecord :: Associations :: CollectionProxy []>):

1 Ответ

1 голос
/ 30 октября 2019

Код, который вы опубликовали, не только труден для отслеживания, но я помню, что у нас была большая утечка памяти, связанная с кэшированием 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 это не массив идентификаторов, а область 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, так как предварительно загруженная ассоциация будет включать только записи, соответствующие условиям соединения отношения.

Я очень надеюсь, что этот бит достаточно хорошо протестирован, или у вас есть кто-то, кто может проверить правильность поведения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...