在 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
我正在为 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