1

Я строю API JSON в Rails, и я бы хотел использовать Elasticsearch, чтобы ускорить ответы и разрешить поиск.Rails: могу ли я использовать elasticsearch-model и active_model_serializers вместе?

Я только что выполнил реализацию elasticsearch-rails Gem для моей первой модели, и я могу запросить ES с консоли успешно.

Теперь я хотел бы, чтобы результаты были доступны для пользователей API, поэтому, например, запрос GET на /articles/index.json?q="blah "будет извлекать соответствующие статьи из ES и отображать их в соответствии с JSON: Стандарты API.

Можно ли использовать рельсы active_model_serializers gem для достижения этого? Я спрашиваю, потому что там (в отличие от jbuilder) формат JSON: API уже позаботился.

EDIT: Вот где я стою на данный момент:

В моей модели я следующее:

require 'elasticsearch/rails' 
require 'elasticsearch/model' 
class Thing < ApplicationRecord 
    validates :user_id, :active, :status, presence: true 
    include Elasticsearch::Model 
    include Elasticsearch::Model::Callbacks 

    index_name Rails.application.class.parent_name.underscore 
    document_type self.name.downcase 

    settings index: { number_of_shards: 1, number_of_replicas: 1 } do 
     mapping dynamic: 'strict' do 
      indexes :id, type: :string 
      indexes :user_id, type: :string 
      indexes :active, type: :boolean 
      indexes :status, type: :string 
     end 
    end 

    def as_indexed_json(options = nil) 
     self.as_json({ 
     only: [:id, :user_id, :active, :status], 
     }) 
    end 

    def self.search(query) 
     __elasticsearch__.search({ 
      query: { 
       multi_match: { 
        query: query, 
        fields: ['id^5', 'user_id'] 
       } 
      } 
     }) 
    end 
end 

Это правильно индексирует модель в ES и позволяет искать ES индекс. В моем контроллере у меня есть:

class ThingsController < ApplicationController 
    def index 
     things = Thing.search(params[:query]).results.map{|m| m._source} 
     render json: things, each_serializer: ThingSerializer 
    end 
end 

В сериализаторе, на данный момент, является следующее:

class ThingSerializer < ActiveModel::Serializer 
    attributes :id, :user_id, :active, :status 
end 

К сожалению, это вызывает следующий JSON в представлении:

{"data":[{"id":"","type":"hashie-mashes","attributes":{"user-id":null,"active":null,"status":null}}]} 

Таким образом, сериализатор неправильно обрабатывает результат, который завернут из драгоценного камня ES в этот объект Hashie :: Mash.

+0

Вы также можете предоставить небольшой код, чтобы мы не стреляли в темноте. Однако то, что вам нравится, достигается с помощью jbuilder –

+0

У меня нет кода atm, я спрашиваю, возможно ли это вообще. У меня есть elasticsearch-rails, реализованный в модели, и я хочу отобразить JSON через active_model_serializers. Jbuilder, очевидно, является альтернативой, но, как указано в этом вопросе, мне пришлось бы сделать данные JSON: API совместимым для моей модели для каждой модели – coconup

ответ

2

Мне, наконец, удалось заставить его работать хорошо и без необходимости извлекать записи из БД. Вот полное решение для будущих Googlers:

Serializer (вероятно, лучше, чтобы создать специальный один для результатов поиска):

class SearchableThingSerializer < ActiveModel::Serializer 
    type 'things' # This needs to be overridden, otherwise it will print "hashie-mashes" 
    attributes :id # For some reason the mapping below doesn't work with :id 

    [:user_id, :active, :status].map{|a| attribute(a) {object[:_source][a]}} 

    def id 
    object[:_source].id 
    end 
end 

Контроллер:

def index 
    things = Thing.search(params[:query]) 
    render json: things, each_serializer: SearchableThingSerializer 
end 

С этим вы можете построить JSON API как описано в этом руководстве, с дополнительным преимуществом обслуживания данных прямо от Elasticsearch:

https://www.simplify.ba/articles/2016/06/18/creating-rails5-api-only-application-following-jsonapi-specification/