Reputation: 761
I'm configuring Algolia search for Rails. The algoliasearch method accepts a block which contains index configuration settings. Each of our searchable models has a public and a private index. The configuration of these indexes is identical with the exception that data in the public index is only indexed when the public? method returns true. I'm trying to find a way where I can not repeat the configuration specified for the secured index in the public index so that the code is more DRY. I was thinking along the lines of extracting the configuration into a Proc and using that Proc in both the secured index and public index blocks. I haven't been able to make this work. Does anyone have any suggestions about how to implement this?
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
Here's what I have so far. It doesn't work.
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
Upvotes: 2
Views: 447
Reputation: 761
Instance_eval is the key to solving this.
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
Upvotes: 3