@@ -423,10 +423,182 @@ and demonstrates a rich set of features of the repository.
423
423
424
424
### The ActiveRecord Pattern
425
425
426
- [ _ Work in progress_ ] ( https://github.com/elasticsearch/elasticsearch-rails/pull/91 ) .
427
- The ActiveRecord [ pattern] ( http://www.martinfowler.com/eaaCatalog/activeRecord.html ) will work
428
- in a very similar way as ` Tire::Model::Persistence ` , allowing a drop-in replacement of
429
- an Elasticsearch-backed model in Ruby on Rails applications.
426
+ The ` Elasticsearch::Persistence::Model ` module provides an implementation of the
427
+ active record [ pattern] ( http://www.martinfowler.com/eaaCatalog/activeRecord.html ) ,
428
+ with a familiar interface for using Elasticsearch as a persistence layer in
429
+ Ruby on Rails applications.
430
+
431
+ All the methods are documented with comprehensive examples in the source code,
432
+ available also online at < http://rubydoc.info/gems/elasticsearch-persistence/Elasticsearch/Persistence/Model > .
433
+
434
+ #### Model Definition
435
+
436
+ The integration is implemented by including the module in a Ruby class.
437
+ The model attribute definition support is implemented with the
438
+ [ _ Virtus_ ] ( https://github.com/solnic/virtus ) Rubygem, and the
439
+ naming, validation, etc. features with the
440
+ [ _ ActiveModel_ ] ( https://github.com/rails/rails/tree/master/activemodel ) Rubygem.
441
+
442
+ ``` ruby
443
+ class Article
444
+ include Elasticsearch ::Persistence ::Model
445
+
446
+ # Define a plain `title` attribute
447
+ #
448
+ attribute :title , String
449
+
450
+ # Define an `author` attribute, with multiple analyzers for this field
451
+ #
452
+ attribute :author , String , mapping: { fields: {
453
+ author: { type: ' string' },
454
+ raw: { type: ' string' , analyzer: ' keyword' }
455
+ } }
456
+
457
+
458
+ # Define a `views` attribute, with default value
459
+ #
460
+ attribute :views , Integer , default: 0 , mapping: { type: ' integer' }
461
+
462
+ # Validate the presence of the `title` attribute
463
+ #
464
+ validates :title , presence: true
465
+
466
+ # Execute code after saving the model.
467
+ #
468
+ after_save { puts " Successfuly saved: #{ self } " }
469
+ end
470
+ ```
471
+
472
+ Attribute validations works like for any other _ ActiveModel_ -compatible implementation:
473
+
474
+ ``` ruby
475
+ article = Article .new # => #<Article { ... }>
476
+
477
+ article.valid?
478
+ # => false
479
+
480
+ article.errors.to_a
481
+ # => ["Title can't be blank"]
482
+ ```
483
+
484
+ #### Persistence
485
+
486
+ We can create a new article in the database...
487
+
488
+ ``` ruby
489
+ Article .create id: 1 , title: ' Test' , author: ' John'
490
+ # PUT http://localhost:9200/articles/article/1 [status:201, request:0.015s, query:n/a]
491
+ ```
492
+
493
+ ... and find it:
494
+
495
+ ``` ruby
496
+ article = Article .find(1 )
497
+ # => #<Article { ... }>
498
+
499
+ article._index
500
+ # => "articles"
501
+
502
+ article.id
503
+ # => "1"
504
+
505
+ article.title
506
+ # => "Test"
507
+ ```
508
+
509
+ To update the model, either update the attribute and save the model:
510
+
511
+ ``` ruby
512
+ article.title = ' Updated'
513
+
514
+ article.save
515
+ => {" _index" =>" articles" , " _type" =>" article" , " _id" =>" 1" , " _version" =>2 , " created" =>false }
516
+ ```
517
+
518
+ ... or use the ` update_attributes ` method:
519
+
520
+ ``` ruby
521
+ article.update_attributes title: ' Test' , author: ' Mary'
522
+ # => {"_index"=>"articles", "_type"=>"article", "_id"=>"1", "_version"=>3}
523
+ ```
524
+
525
+ The implementation supports the familiar interface for updating model timestamps:
526
+
527
+ ``` ruby
528
+ article.touch
529
+ # => => { ... "_version"=>4}
530
+ ```
531
+
532
+ ... and numeric attributes:
533
+
534
+ ``` ruby
535
+ article.views
536
+ # => 0
537
+
538
+ article.increment :views
539
+ article.views
540
+ # => 1
541
+ ```
542
+
543
+ Any callbacks defined in the model will be triggered during the persistence operations:
544
+
545
+ ``` ruby
546
+ article.save
547
+ # Successfuly saved: #<Article {...}>
548
+ ```
549
+
550
+ The model also supports familiar ` find_in_batches ` and ` find_each ` methods to efficiently
551
+ retrieve big collections of model instance, using the Elasticsearch's _ Scan API_ :
552
+
553
+ ``` ruby
554
+ Article .find_each(_source_include: ' title' ) { |a | puts " ===> #{ a.title.upcase } " }
555
+ # GET http://localhost:9200/articles/article/_search?scroll=5m&search_type=scan&size=20
556
+ # GET http://localhost:9200/_search/scroll?scroll=5m&scroll_id=c2Nhb...
557
+ # ===> TEST
558
+ # GET http://localhost:9200/_search/scroll?scroll=5m&scroll_id=c2Nhb...
559
+ # => "c2Nhb..."
560
+ ```
561
+
562
+ #### Search
563
+
564
+ The model class provides a ` search ` method to retrieve model instances with a regular
565
+ search definition, including highlighting, aggregations, etc:
566
+
567
+ ``` ruby
568
+ results = Article .search query: { match: { title: ' test' } },
569
+ aggregations: { authors: { terms: { field: ' author.raw' } } },
570
+ highlight: { fields: { title: {} } }
571
+
572
+ puts results.first.title
573
+ # Test
574
+
575
+ puts results.first.hit.highlight[' title' ]
576
+ # <em>Test</em>
577
+
578
+ puts results.response.aggregations.authors.buckets.each { |b | puts " #{ b[' key' ] } : #{ b[' doc_count' ] } " }
579
+ # John : 1
580
+ ```
581
+
582
+ #### Rails Compatibility
583
+
584
+ The model instances are fully compatible with Rails' conventions and helpers:
585
+
586
+ ``` ruby
587
+ url_for article
588
+ # => "http://localhost:3000/articles/1"
589
+
590
+ div_for article
591
+ # => '<div class="article" id="article_1"></div>'
592
+ ```
593
+
594
+ ... as well as form values for dates and times:
595
+
596
+ ``` ruby
597
+ article = Article .new " title" => " Date" , " published(1i)" =>" 2014" , " published(2i)" =>" 1" , " published(3i)" =>" 1"
598
+
599
+ article.published.iso8601
600
+ # => "2014-01-01"
601
+ ```
430
602
431
603
## License
432
604
0 commit comments