Как индексировать полиморфные (STI) модели в Rails 5 с Thinking Sphinx без круговой зависимости? - PullRequest
0 голосов
/ 29 апреля 2018

Я интегрирую простой индексированный поиск для приложения rails 5.1.4, используя Sphinx 2.2.11-id64-release (95ae9a6) и thinking_sphinx v 4.0.0

Ожидаемое поведение:

Когда я отправляю новый поиск, я ожидаю увидеть либо пустой массив [], либо набор результатов поиска.

Фактическое поведение:

Когда я отправляю новый поиск с пустыми параметрами из слоя представления и пытаюсь получить доступ к объекту ThinkingSphinx :: Search через binding.pry в действии контроллера, rails выдает ActionView::Template::Error (Circular dependency detected while autoloading constant StudentLesson)

[1] pry(main)> ThinkingSphinx.search ''
=> [#<ThinkingSphinx::Search:0x2b0925399e10>
[2] pry(main)> _.inspect
RuntimeError: Circular dependency detected while autoloading constant StudentLesson
from /home/kf/.rvm/gems/ruby-2.4.3@crm/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:509:in `load_missing_constant'
[3] pry(main)>

Фрагменты кода:

class Lesson < ApplicationRecord
  LESSON_TYPES = {
    'StudentLesson': StudentLesson,
    'ProfessionalLesson': ProfessionalLesson
  }.freeze
end

class StudentLesson < Lesson
  after_save ThinkingSphinx::RealTime.callback_for(:student_lesson)
end

class ProfessionalLesson < Lesson
  after_save ThinkingSphinx::RealTime.callback_for(:professional_lesson)
end
# app/indices/student_lesson_index.rb
ThinkingSphinx::Index.define :student_lesson, with: :real_time do
  indexes name, sortable: true
end

# app/indices/professional_lesson_index.rb
ThinkingSphinx::Index.define :professional_lesson, with: :real_time do
  indexes name, sortable: true
end
class SearchesController < ApplicationController
  def index
    @results = []
  end

  def create
    @results = ThinkingSphinx.search(params[:search])
    render :index
  end
end
<div class="collapse navbar-collapse" id="header-navbar">
   <%= render 'layouts/nav_links' %>
   <%= form_for searches_path do %>
     <%= search_field_tag :search, params[:search] %>
     <%= submit_tag 'Search', name: nil, method: :get %>
   <% end %>
 </div>

Вот dev.sphinx.conf

indexer
{
}

searchd
{
  listen = 127.0.0.1:9306:mysql41
  log = /home/myapp/log/development.searchd.log
  query_log = /home/myapp/log/development.searchd.query.log
  pid_file = /home/myapp/log/development.sphinx.pid
  workers = threads
  binlog_path = /home/myapp/tmp/binlog/development
}

index game_core
{
  type = rt
  path = /home/myapp/db/sphinx/development/game_core
  docinfo = extern
  rt_field = sphinx_internal_class_name
  rt_field = name
  rt_field = summary
  rt_attr_uint = sphinx_deleted
  rt_attr_bigint = sphinx_internal_id
  rt_attr_timestamp = created_at
  rt_attr_timestamp = updated_at
  rt_attr_string = sphinx_internal_class
  rt_attr_string = name_sort
}

index lesson_core
{
  type = rt
  path = /home/myapp/db/sphinx/development/lesson_core
  docinfo = extern
  rt_field = sphinx_internal_class_name
  rt_field = name
  rt_field = purpose
  rt_field = meta
  rt_field = supplies
  rt_field = activity
  rt_attr_uint = sphinx_deleted
  rt_attr_bigint = sphinx_internal_id
  rt_attr_timestamp = created_at
  rt_attr_timestamp = updated_at
  rt_attr_string = sphinx_internal_class
  rt_attr_string = name_sort
}

index protocol_core
{
  type = rt
  path = /home/myapp/db/sphinx/development/protocol_core
  docinfo = extern
  rt_field = sphinx_internal_class_name
  rt_field = name
  rt_field = description
  rt_attr_uint = sphinx_deleted
  rt_attr_bigint = sphinx_internal_id
  rt_attr_timestamp = created_at
  rt_attr_timestamp = updated_at
  rt_attr_string = sphinx_internal_class
  rt_attr_string = name_sort
}

index resource_page_core
{
  type = rt
  path = /home/myapp/db/sphinx/development/resource_page_core
  docinfo = extern
  rt_field = sphinx_internal_class_name
  rt_field = header
  rt_field = content
  rt_attr_uint = sphinx_deleted
  rt_attr_bigint = sphinx_internal_id
  rt_attr_timestamp = created_at
  rt_attr_timestamp = updated_at
  rt_attr_string = sphinx_internal_class
  rt_attr_string = header_sort
}

index game
{
  type = distributed
  local = game_core
}

index lesson
{
  type = distributed
  local = lesson_core
}

index protocol
{
  type = distributed
  local = protocol_core
}

index resource_page
{
  type = distributed
  local = resource_page_core
}

Ответы [ 3 ]

0 голосов
/ 30 апреля 2018

Я думаю, что проблема здесь не связана напрямую с Thinking Sphinx - это просто ошибки, потому что он не может загрузить результаты поиска из-за циклической зависимости в ваших моделях - в частности, константа LESSON_TYPES:

  • Мышление Сфинкс выполняет поисковый вызов, и в его наборе результатов он содержит как минимум один экземпляр StudentLesson, поэтому ему необходимо загрузить эту модель.
  • Загрузка StudentLesson находит свою зависимость (как подкласс) от Lesson.
  • Загрузка Lesson находит свою зависимость (в виде ссылок на константы) как StudentLesson, так и ProfessionalLesson.
  • Итак, StudentLesson пытается снова загрузиться, и, следовательно, бесконечный цикл зависимостей.

(FWIW Я только что подтвердил это поведение в тестовом приложении Rails, используя предоставленный вами код модели, без участия TS: все, что мне нужно для запуска в консоли, было StudentLesson.first.)

0 голосов
/ 30 апреля 2018

Решение фактически найдено в ветке комментариев для еще открытой проблемы с spring , которая решается путем инициализации require_dependency 'lesson' ->, которую я фактически уже имел в инициализаторе, но перемещая ее в * Блок 1004 * решил проблемы с перезагрузкой и симптомы, связанные с Сфинксом.

0 голосов
/ 29 апреля 2018

У вас есть 2 класса, которые оба наследуют определение константы, это выглядит проблематично.

Попробуйте переместить это определение константы в инициализатор:

LESSON_TYPES = {
    'StudentLesson': StudentLesson,
    'ProfessionalLesson': ProfessionalLesson
  }.freeze
...