【问题标题】:How do I index polymorphic (STI) models in Rails 5 with Thinking Sphinx without a circular dependency?如何在没有循环依赖的情况下使用 Thinking Sphinx 在 Rails 5 中索引多态 (STI) 模型?
【发布时间】:2018-04-29 08:40:45
【问题描述】:

我正在使用Sphinx 2.2.11-id64-release (95ae9a6)thinking_sphinx v 4.0.0rails 5.1.4 应用程序集成一个简单的索引搜索

预期行为:

当我提交新搜索时,我希望看到一个空数组 [] 或一组搜索结果。

实际行为:

当我从视图层提交一个带有空参数的新搜索并尝试通过控制器操作中的binding.pry 访问 ThinkingSphinx::Search 对象时,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)>

代码 sn-ps:

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
}

【问题讨论】:

  • 支持基弗!你怎么了?!当您使用参数搜索时,它是否有效?有什么错误吗?
  • 使用空参数在控制台中搜索会成功返回结果集,但是当从视图中搜索并检查binding.pry 中的结果时,我遇到了[#&lt;ThinkingSphinx::Search:0x3fd34aba5448&gt;,在检查Search 时对象我看到循环依赖错误 - 我的模型可能有问题,但其他一切都在 ThinkingSphinx 之外按预期工作

标签: ruby-on-rails ruby sphinx thinking-sphinx


【解决方案1】:

我认为这里的问题与 Thinking Sphinx 没有直接关系 - 它只是错误,因为由于模型中的循环依赖性而无法加载搜索结果 - 特别是 LESSON_TYPES 常量:

  • Thinking Sphinx 进行搜索调用,在其结果集中它至少有一个 StudentLesson 实例,因此它需要加载该模型。
  • 加载StudentLesson 发现它对Lesson 的依赖(作为子类)。
  • 加载Lesson 会发现它对StudentLessonProfessionalLesson 的依赖关系(作为对常量的引用)。
  • 因此,StudentLesson 被尝试再次加载,因此出现了无限循环的依赖关系。

(FWIW 我刚刚使用您提供的模型代码在一个测试 Rails 应用程序中确认了这种行为,没有涉及到 TS:我需要在控制台中运行的只是 StudentLesson.first。)

【讨论】:

    【解决方案2】:

    你有 2 个类都继承了一个常量定义,这看起来有问题。

    尝试将此常量定义移至初始化器:

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

    【讨论】:

    • 嘿兰斯!很高兴收到您的来信 - 我已经用开发配置更新了这个问题。从视图触发时会发生此错误,但在 rails 控制台中直接调用 ThinkingSphinx.search(nil) 时不会发生此错误。在控制台中发送ThinkingSphinx.search('')ThinkingSphinx.search({}) 也会返回相同的集合。但是,当在控制器操作中从 binding.pry 检查 @results 时,结果看起来像 [#&lt;ThinkingSphinx::Search:0x3fd34aba5448&gt;,这是一个损坏的数组,检查该数组中的 .first 元素会给出循环错误
    • Thinking Sphinx 可以通过传递 nil - 它只是被视为空字符串 :)
    【解决方案3】:

    解决方案实际上是在spring 的一个仍然未解决的问题的评论线程中找到的,通过初始化require_dependency 'lesson' 解决了这个问题-> 我实际上已经在初始化程序中但是将它移动到Rails.application.config.to_prepare 块解决了重新加载问题以及与狮身人面像相关的症状。

    【讨论】:

    • 不错的一个!也许您想发布解决问题的代码设置!
    猜你喜欢
    • 1970-01-01
    • 2016-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多