Skip to content

Commit c2b934c

Browse files
committed
[MODEL] Added example with ActiveRecord associations ("relationships")
This example demonstrates how to set up models, search integration, callbacks, etc. in a more complex schema.
1 parent d6fe949 commit c2b934c

File tree

1 file changed

+153
-0
lines changed

1 file changed

+153
-0
lines changed
+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# ActiveRecord associations and Elasticsearch
2+
# ===========================================
3+
#
4+
# https://github.com/rails/rails/tree/master/activerecord
5+
# http://guides.rubyonrails.org/association_basics.html
6+
7+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
8+
9+
require 'pry'
10+
Pry.config.history.file = File.expand_path('../../tmp/elasticsearch_development.pry', __FILE__)
11+
12+
require 'logger'
13+
require 'ansi/core'
14+
require 'active_record'
15+
16+
require 'elasticsearch/model'
17+
18+
ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT)
19+
ActiveRecord::Base.establish_connection( adapter: 'sqlite3', database: ":memory:" )
20+
21+
# ----- Schema definition -------------------------------------------------------------------------
22+
23+
ActiveRecord::Schema.define(version: 1) do
24+
create_table :categories do |t|
25+
t.string :title
26+
t.timestamps
27+
end
28+
29+
create_table :authors do |t|
30+
t.string :first_name, :last_name
31+
t.timestamps
32+
end
33+
34+
create_table :authorships do |t|
35+
t.references :article
36+
t.references :author
37+
t.timestamps
38+
end
39+
40+
create_table :articles do |t|
41+
t.string :title
42+
t.timestamps
43+
end
44+
45+
create_table :articles_categories, id: false do |t|
46+
t.references :article, :category
47+
end
48+
49+
create_table :comments do |t|
50+
t.string :text
51+
t.references :article
52+
t.timestamps
53+
end
54+
add_index(:comments, :article_id)
55+
end
56+
57+
# ----- Model definitions -------------------------------------------------------------------------
58+
59+
class Category < ActiveRecord::Base
60+
has_and_belongs_to_many :articles
61+
end
62+
63+
class Author < ActiveRecord::Base
64+
has_many :authorships
65+
66+
def full_name
67+
[first_name, last_name].compact.join(' ')
68+
end
69+
end
70+
71+
class Authorship < ActiveRecord::Base
72+
belongs_to :author
73+
belongs_to :article, touch: true
74+
end
75+
76+
class Article < ActiveRecord::Base
77+
has_and_belongs_to_many :categories, after_add: [ lambda { |a,c| a.__elasticsearch__.index_document } ],
78+
after_remove: [ lambda { |a,c| a.__elasticsearch__.index_document } ]
79+
has_many :authorships
80+
has_many :authors, through: :authorships
81+
has_many :comments
82+
end
83+
84+
class Comment < ActiveRecord::Base
85+
belongs_to :article, touch: true
86+
end
87+
88+
# ----- Search integration ------------------------------------------------------------------------
89+
90+
module Searchable
91+
extend ActiveSupport::Concern
92+
93+
included do
94+
include Elasticsearch::Model
95+
include Elasticsearch::Model::Callbacks
96+
97+
__elasticsearch__.client Elasticsearch::Client.new log: true
98+
__elasticsearch__.client.transport.logger.formatter = proc { |s, d, p, m| "\e[32m#{m}\n\e[0m" }
99+
100+
include Indexing
101+
after_touch() { __elasticsearch__.index_document }
102+
end
103+
104+
module Indexing
105+
106+
# Customize the JSON serialization for Elasticsearch
107+
def as_indexed_json(options={})
108+
self.as_json(
109+
include: { categories: { only: :title},
110+
authors: { methods: [:full_name], only: [:full_name] },
111+
comments: { only: :text }
112+
})
113+
end
114+
end
115+
end
116+
117+
Article.__send__ :include, Searchable
118+
119+
# ----- Insert data -------------------------------------------------------------------------------
120+
121+
# Create category
122+
#
123+
category = Category.create title: 'One'
124+
125+
# Create author
126+
#
127+
author = Author.create first_name: 'John', last_name: 'Smith'
128+
129+
# Create article
130+
131+
article = Article.create title: 'First Article'
132+
133+
# Assign category
134+
#
135+
article.categories << category
136+
137+
# Assign author
138+
#
139+
article.authors << author
140+
141+
# Add comment
142+
#
143+
article.comments.create text: 'First comment'
144+
145+
# Load
146+
#
147+
article = Article.all.includes(:categories, :authors, :comments).first
148+
149+
# ----- Pry ---------------------------------------------------------------------------------------
150+
151+
Pry.start(binding, prompt: lambda { |obj, nest_level, _| '> ' },
152+
input: StringIO.new('puts "\n\narticle.as_indexed_json\n"; article.as_indexed_json'),
153+
quiet: true)

0 commit comments

Comments
 (0)