CanCanCan, Pagy и MeiliSearch, как объединить 3 драгоценных камня?

Я работаю над проектом, в котором есть модель 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, но уверены ли вы, что добавление в запрос пользовательских параметров со строковой интерполяцией не делает ваше приложение уязвимым для атак SQL-инъекций? Потому что, если бы вы сделали это с языком запросов Rails, это позволило бы внедрять SQL.

spickermann 28.04.2023 17:52

Спасибо за ваше замечание, я рассмотрю его, но я не думаю, что это вызовет какие-либо проблемы, поскольку этот фильтр будет использоваться только для запроса индекса MeiliSearch, и он не будет отправлен в саму БД приложения. Любое представление об основной проблеме, упомянутой в вопросе?

AliOsm 28.04.2023 18:01
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
114
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Другие вопросы по теме