Rails: 我可以同时使用 elasticsearch-model 和 active_model_serializers 吗?
Rails: can I use elasticsearch-model and active_model_serializers together?
我正在 Rails 中构建一个 JSON API,我想使用 Elasticsearch 来加快响应速度并允许搜索。
我刚刚为我的第一个模型实现了 elasticsearch-rails Gem,我可以从控制台成功查询 ES。
现在我想让 API 消费者可以使用结果,因此例如对 /articles/index.json?q="blah" 的 GET 请求将检索来自 ES 的匹配文章并根据 JSON:API 标准呈现它们。
是否可以使用 rails active_model_serializers gem 来实现?我问是因为那里(与 jbuilder 相比)JSON:API 格式已经得到处理。
编辑:这是我现在的立场:
在我的模型中,我有以下内容:
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 gem 包装到这个 Hashie::Mash 对象中的结果。
我终于设法让它很好地工作,而且不需要从数据库中获取记录。这是面向未来 google 员工的完整解决方案:
序列化器(最好为搜索结果创建一个专用序列化器):
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 提供数据的额外好处:
我正在 Rails 中构建一个 JSON API,我想使用 Elasticsearch 来加快响应速度并允许搜索。
我刚刚为我的第一个模型实现了 elasticsearch-rails Gem,我可以从控制台成功查询 ES。
现在我想让 API 消费者可以使用结果,因此例如对 /articles/index.json?q="blah" 的 GET 请求将检索来自 ES 的匹配文章并根据 JSON:API 标准呈现它们。
是否可以使用 rails active_model_serializers gem 来实现?我问是因为那里(与 jbuilder 相比)JSON:API 格式已经得到处理。
编辑:这是我现在的立场:
在我的模型中,我有以下内容:
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 gem 包装到这个 Hashie::Mash 对象中的结果。
我终于设法让它很好地工作,而且不需要从数据库中获取记录。这是面向未来 google 员工的完整解决方案:
序列化器(最好为搜索结果创建一个专用序列化器):
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 提供数据的额外好处: