Skip to content

[STORE] Remove Elasticsearch::Persistence::Model (ActiveRecord persistence pattern) #812

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
[STORE] Remove Elasticsearch::Persistence::Model (ActiveRecord persis…
…tence pattern)
  • Loading branch information
estolfo committed Jul 25, 2018
commit 1bdd22d9d0e0d6a67d1e09c7c19b0e9bda85ee7e
14 changes: 0 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,20 +98,6 @@ repository.save Article.new(title: 'Test')
# => {"_index"=>"repository", "_type"=>"article", "_id"=>"Ak75E0U9Q96T5Y999_39NA", ...}
```

Example of using Elasticsearch as a persistence layer for a Ruby model:

```ruby
require 'elasticsearch/persistence/model'
class Article
include Elasticsearch::Persistence::Model
attribute :title, String, mapping: { analyzer: 'snowball' }
end

Article.create title: 'Test'
# POST http://localhost:9200/articles/article
# => #<Article {title: "Test", id: "lUOQ9lhHToWa7oYPxwjqPQ", ...}>
```

**Please refer to each library documentation for detailed information and examples.**

### Model
Expand Down
259 changes: 2 additions & 257 deletions elasticsearch-persistence/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ or install it from a source code checkout:
The library provides two different patterns for adding persistence to your Ruby objects:

* [Repository Pattern](#the-repository-pattern)
* [ActiveRecord Pattern](#the-activerecord-pattern)

### The Repository Pattern

Expand Down Expand Up @@ -445,262 +444,8 @@ and demonstrates a rich set of features:

### The ActiveRecord Pattern

The `Elasticsearch::Persistence::Model` module provides an implementation of the
active record [pattern](http://www.martinfowler.com/eaaCatalog/activeRecord.html),
with a familiar interface for using Elasticsearch as a persistence layer in
Ruby on Rails applications.

All the methods are documented with comprehensive examples in the source code,
available also online at <http://rubydoc.info/gems/elasticsearch-persistence/Elasticsearch/Persistence/Model>.

#### Installation/Usage

To use the library in a Rails application, add it to your `Gemfile` with a `require` statement:

```ruby
gem "elasticsearch-persistence", require: 'elasticsearch/persistence/model'
```

To use the library without Bundler, install it, and require the file:

```bash
gem install elasticsearch-persistence
```

```ruby
# In your code
require 'elasticsearch/persistence/model'
```

#### Model Definition

The integration is implemented by including the module in a Ruby class.
The model attribute definition support is implemented with the
[_Virtus_](https://github.com/solnic/virtus) Rubygem, and the
naming, validation, etc. features with the
[_ActiveModel_](https://github.com/rails/rails/tree/master/activemodel) Rubygem.

```ruby
class Article
include Elasticsearch::Persistence::Model

# Define a plain `title` attribute
#
attribute :title, String

# Define an `author` attribute, with multiple analyzers for this field
#
attribute :author, String, mapping: { fields: {
author: { type: 'text'},
raw: { type: 'keyword' }
} }


# Define a `views` attribute, with default value
#
attribute :views, Integer, default: 0, mapping: { type: 'integer' }

# Validate the presence of the `title` attribute
#
validates :title, presence: true

# Execute code after saving the model.
#
after_save { puts "Successfully saved: #{self}" }
end
```

Attribute validations work like for any other _ActiveModel_-compatible implementation:

```ruby
article = Article.new # => #<Article { ... }>

article.valid?
# => false

article.errors.to_a
# => ["Title can't be blank"]
```

#### Persistence

We can create a new article in the database...

```ruby
Article.create id: 1, title: 'Test', author: 'John'
# PUT http://localhost:9200/articles/article/1 [status:201, request:0.015s, query:n/a]
```

... and find it:

```ruby
article = Article.find(1)
# => #<Article { ... }>

article._index
# => "articles"

article.id
# => "1"

article.title
# => "Test"
```

To update the model, either update the attribute and save the model:

```ruby
article.title = 'Updated'

article.save
# => {"_index"=>"articles", "_type"=>"article", "_id"=>"1", "_version"=>2, "created"=>false}
```

... or use the `update_attributes` method:

```ruby
article.update_attributes title: 'Test', author: 'Mary'
# => {"_index"=>"articles", "_type"=>"article", "_id"=>"1", "_version"=>3}
```

The implementation supports the familiar interface for updating model timestamps:

```ruby
article.touch
# => => { ... "_version"=>4}
```

... and numeric attributes:

```ruby
article.views
# => 0

article.increment :views
article.views
# => 1
```

Any callbacks defined in the model will be triggered during the persistence operations:

```ruby
article.save
# Successfully saved: #<Article {...}>
```

The model also supports familiar `find_in_batches` and `find_each` methods to efficiently
retrieve big collections of model instances, using the Elasticsearch's _Scan API_:

```ruby
Article.find_each(_source_include: 'title') { |a| puts "===> #{a.title.upcase}" }
# GET http://localhost:9200/articles/article/_search?scroll=5m&size=20
# GET http://localhost:9200/_search/scroll?scroll=5m&scroll_id=c2Nhb...
# ===> TEST
# GET http://localhost:9200/_search/scroll?scroll=5m&scroll_id=c2Nhb...
# => "c2Nhb..."
```

#### Search

The model class provides a `search` method to retrieve model instances with a regular
search definition, including highlighting, aggregations, etc:

```ruby
results = Article.search query: { match: { title: 'test' } },
aggregations: { authors: { terms: { field: 'author.raw' } } },
highlight: { fields: { title: {} } }

puts results.first.title
# Test

puts results.first.hit.highlight['title']
# <em>Test</em>

puts results.response.aggregations.authors.buckets.each { |b| puts "#{b['key']} : #{b['doc_count']}" }
# John : 1
```

#### The Elasticsearch Client

The module will set up a [client](https://github.com/elastic/elasticsearch-ruby/tree/master/elasticsearch),
connected to `localhost:9200`, by default.

To use a client with different configuration:

```ruby
Elasticsearch::Persistence.client = Elasticsearch::Client.new log: true
```

To set up a specific client for a specific model:

```ruby
Article.gateway.client = Elasticsearch::Client.new host: 'api.server.org'
```

You might want to do this during you application bootstrap process, e.g. in a Rails initializer.

Please refer to the
[`elasticsearch-transport`](https://github.com/elasticsearch/elasticsearch-ruby/tree/master/elasticsearch-transport)
library documentation for all the configuration options, and to the
[`elasticsearch-api`](http://rubydoc.info/gems/elasticsearch-api) library documentation
for information about the Ruby client API.

#### Accessing the Repository Gateway and the Client

The integration with Elasticsearch is implemented by embedding the repository object in the model.
You can access it through the `gateway` method:

```ruby
Artist.gateway.client.info
# GET http://localhost:9200/ [status:200, request:0.011s, query:n/a]
# => {"status"=>200, "name"=>"Lightspeed", ...}
```

#### Rails Compatibility

The model instances are fully compatible with Rails' conventions and helpers:

```ruby
url_for article
# => "http://localhost:3000/articles/1"

div_for article
# => '<div class="article" id="article_1"></div>'
```

... as well as form values for dates and times:

```ruby
article = Article.new "title" => "Date", "published(1i)"=>"2014", "published(2i)"=>"1", "published(3i)"=>"1"

article.published.iso8601
# => "2014-01-01"
```

The library provides a Rails ORM generator to facilitate building the application scaffolding:

```bash
rails generate scaffold Person name:String email:String birthday:Date --orm=elasticsearch
```

#### Example application

A fully working Ruby on Rails application can be generated with the following command:

```bash
rails new music --force --skip --skip-bundle --skip-active-record --template https://raw.githubusercontent.com/elastic/elasticsearch-rails/master/elasticsearch-persistence/examples/music/template.rb
```

The application demonstrates:

* How to set up model attributes with custom mappings
* How to define model relationships with Elasticsearch's parent/child
* How to configure models to use a common index, and create the index with proper mappings
* How to use Elasticsearch's completion suggester to drive auto-complete functionality
* How to use Elasticsearch-persisted models in Rails' views and forms
* How to write controller tests

The source files for the application are available in the [`examples/music`](examples/music) folder.
The ActiveRecord pattern has been deprecated as of version 6.0.0 of this gem. Please use the
[Repository Pattern](#the-repository-pattern) instead.

## License

Expand Down
Loading