在 Ruby 中组合块

Combining blocks in Ruby

我正在为 Rails 配置 Algolia 搜索。 algoliasearch 方法接受一个包含索引配置设置的块。我们的每个可搜索模型都有一个 public 和一个私有索引。这些索引的配置与 public 索引中的数据仅在 public?方法 returns 正确。我正在尝试找到一种方法,使我无法在 public 索引中重复为安全索引指定的配置,以便代码更干。我正在考虑将配置提取到 Proc 中并在安全索引和 public 索引块中使用该 Proc。我没能完成这项工作。有没有人对如何实施这个有任何建议?

algoliasearch index_name: SECURED_INDEX_NAME do
  # Index configuration. I want to extract this so I can reuse it.
  attribute :name

  add_index PUBLIC_INDEX_NAME, if: :public? do
    # Repeat index configuration here.  
  end
end

https://github.com/algolia/algoliasearch-rails#target-multiple-indexes

这是我目前所拥有的。没用。

module Algolia::UserIndexConcern
  extend ActiveSupport::Concern

  included do
    PUBLIC_INDEX_NAME  = "User_Public_#{Rails.env}"
    PRIVATE_INDEX_NAME = "User_Private_#{Rails.env}"

    index_config = build_index_config(index_name: PRIVATE_INDEX_NAME) # Obviously can't call method here but need to?
    algoliasearch index_name: PRIVATE_INDEX_NAME, sanitize: true, force_utf8_encoding: true, &index_config

    private def build_index_config(index_name:)
      Proc.new do
        # =====================
        # Attributes
        # =====================

        # Searchable.

        attribute :name do
          full_name
        end

        attribute :primary_employer do
          primary_employer.try(:name)
        end

        attributesToIndex ['unordered(name)', 'unordered(primary_employer)']

        attributesToHighlight [:name, :primary_employer]

        if index_name == PRIVATE_INDEX_NAME
          index_config = build_index_config(index_name: PUBLIC_INDEX_NAME)
          add_index PUBLIC_INDEX_NAME, &index_config
        end
      end
    end

    private def public?
      !exclude_from_search? && !admin_exclude_from_search?
    end
  end
end

Instance_eval是解决这个问题的关键

Evaluates a string containing Ruby source code, or the given block, within the context of the receiver (obj). In order to set the context, the variable self is set to obj while the code is executing, giving the code access to obj’s instance variables.

PUBLIC_INDEX_NAME  = "User_Public_#{Rails.env}"
PRIVATE_INDEX_NAME = "User_Private_#{Rails.env}"

common_index_attributes = Proc.new do

  # Define search attributes.

end

algoliasearch index_name: PRIVATE_INDEX_NAME, sanitize: true, force_utf8_encoding: true do
  self.instance_eval &common_index_attributes

  add_index PUBLIC_INDEX_NAME, if: :public? do
    self.instance_eval &common_index_attributes
  end
end

private def public?
  # Excluded for brevity
end