Я работаю над проектом, в котором есть модель Cue, к которой можно получить доступ и выполнить поиск несколькими ролями, такими как гость и администратор. Авторизация происходит с использованием гема CanCanCan на основе некоторой логики, написанной в классе Ability. В то время как поиск происходит с использованием комбинации Pagy/MeiliSearch для выполнения полнотекстового поиска и разбиения на страницы. Проблема, с которой я сталкиваюсь сейчас, заключается в том, что когда я ищу в качестве гостя, я вижу правильные элементы, которые должен видеть гость, а когда я ищу в качестве администратора, я вижу правильный элемент, который должен видеть администратор, НО количество драгоценных камней Pagy неправильно. Это мой код:
class SearchesController < ApplicationController
INCLUDES = %i[medium speakers].freeze
include Pagy::Backend
authorize_resource class: false
def search
filter = ''
filter = "speaker_ids IN [#{params[:speaker]}]" if params[:speaker].present?
search_results = Cue.accessible_by(current_ability).includes(INCLUDES).pagy_search(params[:query], filter:)
@pagy, @search_results = pagy_meilisearch(search_results)
end
end
Если есть какие-то подсказки, недоступные гостю, поиск не вернет их в @search_results, но объект @pagy засчитает их. Это показывает пользователю неверные подсчеты, а также показывает меньше, чем требуется Pagy::DEFAULT[:items]. Перепробовал много вариантов, но безрезультатно. Единственное, о чем я могу думать (и я не хочу идти по этому пути TBH), это добавить саму логику фильтрации в строку filter и добавить необходимые параметры в индекс. Но это будет сложно и увеличит размер индекса. У вас есть какие-нибудь мысли?
Спасибо за ваше замечание, я рассмотрю его, но я не думаю, что это вызовет какие-либо проблемы, поскольку этот фильтр будет использоваться только для запроса индекса MeiliSearch, и он не будет отправлен в саму БД приложения. Любое представление об основной проблеме, упомянутой в вопросе?





just hint
при поиске в meilisearch не читается директ какая текущая способность в CanCan, может обрабатывать в application_record чтобы получить все способности CanCan и перезаписать их https://github.com/meilisearch/meilisearch-rails/blob/5d4ac6871a8e89db06fdd1c6d765361b86c47eb6/playground/config/initializers/pagy.rb#L10
это, как вы видите, мы не звоним, можем, можем
можно в app/models/application_recored.rb
def ms_search(query, params = {})
# cancan_params should here merge cancan_params and get params
# to search with cancan params
params.merge!(cancan_params)
super(query, params)
end
Спасибо @abdelrahman-haider за подсказку, это было полезно.
По сути, мы не сможем решить эту проблему, если не реализуем логику фильтрации внутри самого индекса MeiliSearch. Итак, что я сделал, так это извлек условия фильтрации, используя способность CanCan, и вручную преобразовал их в строку фильтрации MeiliSearch.
Чтобы получить условия способности CanCan для конкретной модели при определенном действии контроллера, мы можем сделать следующее:
cue_conditions = current_ability.model_adapter(Cue, :show).conditions
Затем мы можем передать cue_conditions другому методу, чтобы преобразовать их в строку фильтрации MeiliSearch, как показано ниже:
def ability_conditions_to_meilisearch_filter(condition)
condition.map do |key, value|
case value
when Array then "#{key} IN [#{value.join(',')}]"
when NilClass then "#{key} NOT EXISTS"
when TrueClass, FalseClass then "#{key} = #{value}"
when Hash then hash_condition_to_filter(key, value)
else "#{key} = '#{value}'"
end
end.join(' AND ')
end
def hash_condition_to_filter(key, value)
case value.keys[0]
when :gt then "#{key} > #{value[:gt]}"
when :gte then "#{key} >= #{value[:gte]}"
when :lt then "#{key} < #{value[:lt]}"
when :lte then "#{key} <= #{value[:lte]}"
when :to then "#{key} #{value[:to].first} TO #{key} #{value[:to].last}"
end
end
Реализация метода ability_conditions_to_meilisearch_filter не самая лучшая реализация, но пока она удовлетворяет моим требованиям, и я постараюсь улучшить ее позже.
Обратите внимание, что вам нужно добавить необходимые атрибуты в ваш индекс MeiliSearch.
Я надеюсь, что это полезно, так как я не нашел ничего похожего в Интернете :) Если вы хотите поддержать, я отправил запрос функции в meilisearch-rails репозиторий GitHub: https://github.com/meilisearch/meilisearch-rails /выпуски/255.
Наконец, спасибо @abdelrahman-haider и poe.com за помощь :3
Я не знаком с
meilisearch, но уверены ли вы, что добавление в запрос пользовательских параметров со строковой интерполяцией не делает ваше приложение уязвимым для атак SQL-инъекций? Потому что, если бы вы сделали это с языком запросов Rails, это позволило бы внедрять SQL.