elasticsearch-persistence 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +8 -8
  2. data/CHANGELOG.md +4 -0
  3. data/README.md +238 -7
  4. data/elasticsearch-persistence.gemspec +4 -1
  5. data/examples/music/album.rb +34 -0
  6. data/examples/music/artist.rb +50 -0
  7. data/examples/music/artists/_form.html.erb +8 -0
  8. data/examples/music/artists/artists_controller.rb +67 -0
  9. data/examples/music/artists/artists_controller_test.rb +53 -0
  10. data/examples/music/artists/index.html.erb +57 -0
  11. data/examples/music/artists/show.html.erb +51 -0
  12. data/examples/music/assets/application.css +226 -0
  13. data/examples/music/assets/autocomplete.css +48 -0
  14. data/examples/music/assets/blank_cover.png +0 -0
  15. data/examples/music/assets/form.css +113 -0
  16. data/examples/music/index_manager.rb +60 -0
  17. data/examples/music/search/index.html.erb +93 -0
  18. data/examples/music/search/search_controller.rb +41 -0
  19. data/examples/music/search/search_controller_test.rb +9 -0
  20. data/examples/music/search/search_helper.rb +15 -0
  21. data/examples/music/suggester.rb +45 -0
  22. data/examples/music/template.rb +392 -0
  23. data/examples/music/vendor/assets/jquery-ui-1.10.4.custom.min.css +7 -0
  24. data/examples/music/vendor/assets/jquery-ui-1.10.4.custom.min.js +6 -0
  25. data/examples/{sinatra → notes}/.gitignore +0 -0
  26. data/examples/{sinatra → notes}/Gemfile +0 -0
  27. data/examples/{sinatra → notes}/README.markdown +0 -0
  28. data/examples/{sinatra → notes}/application.rb +0 -0
  29. data/examples/{sinatra → notes}/config.ru +0 -0
  30. data/examples/{sinatra → notes}/test.rb +0 -0
  31. data/lib/elasticsearch/persistence.rb +19 -0
  32. data/lib/elasticsearch/persistence/model.rb +129 -0
  33. data/lib/elasticsearch/persistence/model/base.rb +75 -0
  34. data/lib/elasticsearch/persistence/model/errors.rb +8 -0
  35. data/lib/elasticsearch/persistence/model/find.rb +171 -0
  36. data/lib/elasticsearch/persistence/model/rails.rb +39 -0
  37. data/lib/elasticsearch/persistence/model/store.rb +239 -0
  38. data/lib/elasticsearch/persistence/model/utils.rb +0 -0
  39. data/lib/elasticsearch/persistence/repository.rb +3 -1
  40. data/lib/elasticsearch/persistence/repository/search.rb +25 -0
  41. data/lib/elasticsearch/persistence/version.rb +1 -1
  42. data/lib/rails/generators/elasticsearch/model/model_generator.rb +21 -0
  43. data/lib/rails/generators/elasticsearch/model/templates/model.rb.tt +9 -0
  44. data/lib/rails/generators/elasticsearch_generator.rb +2 -0
  45. data/test/integration/model/model_basic_test.rb +157 -0
  46. data/test/integration/repository/default_class_test.rb +6 -0
  47. data/test/unit/model_base_test.rb +40 -0
  48. data/test/unit/model_find_test.rb +147 -0
  49. data/test/unit/model_gateway_test.rb +99 -0
  50. data/test/unit/model_rails_test.rb +88 -0
  51. data/test/unit/model_store_test.rb +493 -0
  52. data/test/unit/repository_search_test.rb +17 -0
  53. metadata +79 -9
@@ -0,0 +1,53 @@
1
+ require 'test_helper'
2
+
3
+ class ArtistsControllerTest < ActionController::TestCase
4
+ setup do
5
+ IndexManager.create_index force: true
6
+ @artist = Artist.create(id: 1, name: 'TEST')
7
+ Artist.gateway.refresh_index!
8
+ end
9
+
10
+ test "should get index" do
11
+ get :index
12
+ assert_response :success
13
+ assert_not_nil assigns(:artists)
14
+ end
15
+
16
+ test "should get new" do
17
+ get :new
18
+ assert_response :success
19
+ end
20
+
21
+ test "should create artist" do
22
+ assert_difference('Artist.count') do
23
+ post :create, artist: { name: @artist.name }
24
+ Artist.gateway.refresh_index!
25
+ end
26
+
27
+ assert_redirected_to artist_path(assigns(:artist))
28
+ end
29
+
30
+ test "should show artist" do
31
+ get :show, id: @artist
32
+ assert_response :success
33
+ end
34
+
35
+ test "should get edit" do
36
+ get :edit, id: @artist
37
+ assert_response :success
38
+ end
39
+
40
+ test "should update artist" do
41
+ patch :update, id: @artist, artist: { name: @artist.name }
42
+ assert_redirected_to artist_path(assigns(:artist))
43
+ end
44
+
45
+ test "should destroy artist" do
46
+ assert_difference('Artist.count', -1) do
47
+ delete :destroy, id: @artist
48
+ Artist.gateway.refresh_index!
49
+ end
50
+
51
+ assert_redirected_to artists_path
52
+ end
53
+ end
@@ -0,0 +1,57 @@
1
+ <header>
2
+ <h1>
3
+ Artists
4
+ <%= button_to 'New Artist', new_artist_path, method: 'get', tabindex: 5 %>
5
+ </h1>
6
+ </header>
7
+
8
+ <section id="searchbox">
9
+ <%= form_tag search_path, method: 'get' do %>
10
+ <input type="text" name="q" value="<%= params[:q] %>" id="q" autofocus="autofocus" placeholder="start typing to search..." tabindex="0" />
11
+ <% end %>
12
+ </section>
13
+
14
+ <section class="artists">
15
+ <% @artists.each do |artist| %>
16
+ <%= div_for artist, class: 'result clearfix' do %>
17
+ <h2>
18
+ <%= link_to artist do %>
19
+ <span class="name"><%= artist.name %></span>
20
+ <small><%= pluralize artist.album_count, 'album' %></small>
21
+ <% end %>
22
+ </h2>
23
+ <div class="actions clearfix">
24
+ <%= button_to 'Edit', edit_artist_path(artist), method: 'get' %>
25
+ <%= button_to 'Destroy', artist, method: :delete, data: { confirm: 'Are you sure?' } %>
26
+ </div>
27
+ <% end %>
28
+ <% end %>
29
+ </section>
30
+
31
+ <% if @artists.empty? %>
32
+ <section class="no-results">
33
+ <p>The search hasn't returned any results...</p>
34
+ </section>
35
+ <% end %>
36
+
37
+ <script>
38
+ $.widget( "custom.suggest", $.ui.autocomplete, {
39
+ _renderMenu: function( ul, items ) {
40
+ $.each( items, function( index, item ) {
41
+ var category = ul.append( "<li class='ui-autocomplete-category'>" + item.label + "</li>" );
42
+
43
+ $.each( item.value, function( index, item ) {
44
+ var li = $('<li class="ui-autocomplete-item"><a href="<%= Rails.application.config.relative_url_root %>'+ item.payload.url +'">'+ item.text +'</a></li>').data('ui-autocomplete-item', item )
45
+ category.append(li)
46
+ } )
47
+ });
48
+ }
49
+ });
50
+
51
+ $( "#q" ).suggest({
52
+ source: '<%= suggest_path %>',
53
+ select: function(event, ui) {
54
+ document.location.href = '<%= Rails.application.config.relative_url_root %>'+ui.item.payload.url
55
+ }
56
+ });
57
+ </script>
@@ -0,0 +1,51 @@
1
+ <header>
2
+ <h1>
3
+ <span class="back"><%= link_to "〈".html_safe, artists_path, title: "Back" %></span>
4
+ <%= @artist.name %>
5
+ <%= button_to 'Edit', edit_artist_path(@artist), method: 'get' %>
6
+ </h1>
7
+ </header>
8
+
9
+ <p id="notice"><%= notice %></p>
10
+
11
+ <section class="artist-info">
12
+ <span><%= @artist.members.to_sentence last_word_connector: ' and ' %></span> |
13
+ <span><%= pluralize @albums.size, 'album' %></span>
14
+ <p class="artist-profile"><%= @artist.profile %></p>
15
+ </section>
16
+
17
+ <section class="albums">
18
+ <% @albums.each do |album| %>
19
+ <%= div_for album, class: 'clearfix' do %>
20
+ <h3>
21
+ <span class="title"><%= album.title %></span>
22
+ <div class="info">
23
+ <small><%= album.meta.formats.join(', ') %></small>
24
+ <small><%= album.released %></small>
25
+ </div>
26
+ </h3>
27
+
28
+ <div class="cover">
29
+ <%= image_tag "http://ruby-demo-assets.s3.amazonaws.com/discogs/covers/#{album.id}.jpeg", width: '100px', class: 'cover' %>
30
+ </div>
31
+
32
+ <div class="content">
33
+ <% album.tracklist.in_groups_of(album.tracklist.size/2+1).each_with_index do |half, g| %>
34
+ <ul class=<%= cycle 'first', 'second' %> start="<%= g < 1 ? 1 : album.tracklist.size/2+2 %>">
35
+ <% half.compact.each_with_index do |track, i| %>
36
+ <li>
37
+ <i class="counter"><%= g < 1 ? i+1 : i+(g*album.tracklist.size/2+2) %></i>
38
+ <%= track['title'] %>
39
+ <small><%= track['duration'] %></small>
40
+ </li>
41
+ <% end %>
42
+ </ul>
43
+ <% end %>
44
+ </div>
45
+ <% end %>
46
+
47
+ <% end %>
48
+
49
+ <script>$('img').error(function(){ $(this).attr('src', '/images/blank_cover.png'); });</script>
50
+ <script>$(document.location.hash).effect('highlight', 1500)</script>
51
+ </section>
@@ -0,0 +1,226 @@
1
+ /*
2
+ *= require_tree .
3
+ *= require_self
4
+ *= require ui-lightness/jquery-ui-1.10.4.custom.min.css
5
+ */
6
+
7
+ .clearfix {
8
+ *zoom: 1;
9
+ }
10
+
11
+ .clearfix:before,
12
+ .clearfix:after {
13
+ display: table;
14
+ line-height: 0;
15
+ content: "";
16
+ }
17
+
18
+ .clearfix:after {
19
+ clear: both;
20
+ }
21
+
22
+ body {
23
+ font-family: 'Helvetica Neue', Helvetica, sans-serif !important;
24
+ margin: 2em 4em;
25
+ }
26
+
27
+ header {
28
+ margin: 0;
29
+ padding: 0 0 1em 0;
30
+ border-bottom: 1px solid #666;
31
+ }
32
+
33
+ header h1 {
34
+ color: #999;
35
+ font-weight: 100;
36
+ text-transform: uppercase;
37
+ margin: 0; padding: 0;
38
+ }
39
+
40
+ header a {
41
+ color: #0b6aff;
42
+ text-decoration: none;
43
+ }
44
+
45
+ header .back {
46
+ font-size: 100%;
47
+ margin: 0 0.5em 0 -0.5em;
48
+ }
49
+
50
+ h1 form {
51
+ float: right;
52
+ }
53
+
54
+ #searchbox {
55
+ border-bottom: 1px solid #666;
56
+ }
57
+
58
+ #searchbox input {
59
+ color: #444;
60
+ font-size: 100%;
61
+ font-weight: 100;
62
+ border: none;
63
+ padding: 1em 0 1em 0;
64
+ width: 100%;
65
+ }
66
+
67
+ #searchbox input:focus {
68
+ outline-width: 0;
69
+ }
70
+
71
+ .actions form {
72
+ float: right;
73
+ position: relative;
74
+ top: 0.2em;
75
+ }
76
+
77
+ .no-results {
78
+ font-weight: 200;
79
+ font-size: 200%;
80
+ }
81
+
82
+ .result,
83
+ .artist {
84
+ padding: 1em 0 1em 0;
85
+ margin: 0;
86
+ border-bottom: 1px solid #999;
87
+ }
88
+
89
+ .result:hover,
90
+ .artist:hover {
91
+ background: #f9f9f9;
92
+ }
93
+
94
+ .result h2,
95
+ .artist h2 {
96
+ color: #444;
97
+ margin: 0;
98
+ padding: 0;
99
+ }
100
+
101
+ .artist h2 {
102
+ float: left;
103
+ }
104
+
105
+ .result h2 a,
106
+ .artist h2 a {
107
+ color: #444;
108
+ }
109
+
110
+ .result h2 small,
111
+ .artist h2 small {
112
+ font-size: 70%;
113
+ font-weight: 100;
114
+ margin-left: 0.5em;
115
+ }
116
+
117
+ .result h2 a,
118
+ .artist h2 a {
119
+ text-decoration: none;
120
+ }
121
+
122
+ .result h2 a:hover name,
123
+ .artist h2 a:hover .name {
124
+ text-decoration: underline;
125
+ }
126
+
127
+ .result .small {
128
+ font-size: 90%;
129
+ font-weight: 200;
130
+ padding: 0;
131
+ margin: 0.25em 0 0.25em 0;
132
+ }
133
+
134
+ .result .small .label {
135
+ color: #999;
136
+ font-size: 80%;
137
+ min-width: 5em;
138
+ display: inline-block;
139
+ }
140
+
141
+ .artist-info {
142
+ color: #5f5f5f;
143
+ text-transform: uppercase;
144
+ font-weight: 200;
145
+ border-bottom: 1px solid #666;
146
+ padding: 0 0 1em 0;
147
+ margin: 0 0 1em 0;
148
+ }
149
+
150
+ .artist-profile {
151
+ color: #999;
152
+ font-size: 95%;
153
+ font-weight: 100;
154
+ text-transform: none;
155
+ padding: 0;
156
+ margin: 0.25em 0 0 0;
157
+ }
158
+
159
+ .album {
160
+ margin: 0 0 4em 0;
161
+ }
162
+
163
+ .album .cover {
164
+ float: left;
165
+ width: 150px;
166
+ }
167
+
168
+ .album .cover img {
169
+ border: 1px solid rgba(0,0,0,0.15);
170
+ box-shadow: 0px 0px 1px 0px rgba(0,0,0,0.05);
171
+ }
172
+
173
+ .album .content {
174
+ float: left;
175
+ margin-left: 25px;
176
+ }
177
+
178
+ .album .content ul {
179
+ float: left;
180
+ margin: 0 2em 0 0;
181
+ padding: 0;
182
+ min-width: 18em;
183
+ }
184
+
185
+ .album .content ul li {
186
+ line-height: 1.5em;
187
+ padding: 0.5em 0 0.5em 0;
188
+ border-bottom:1px solid #f8f8f8;
189
+ list-style: none;
190
+ }
191
+
192
+ .album .content ul li .counter {
193
+ color: #999;
194
+ font-style: normal;
195
+ font-size: 80%;
196
+ font-weight: 100;
197
+ margin-right: 0.5em;
198
+ }
199
+
200
+ .album h3 {
201
+ margin: 0; padding: 0;
202
+ border-bottom: 2px solid #e0e0e0;
203
+ padding: 0 0 0.5em 0;
204
+ margin: 0 0 1em 0;
205
+ }
206
+
207
+ .album h3 .title {
208
+ text-transform: uppercase;
209
+ font-weight: 200;
210
+ }
211
+
212
+ .album small {
213
+ color: #a3a3a3;
214
+ font-weight: 200;
215
+ }
216
+
217
+ .album .info {
218
+ float: right;
219
+ }
220
+
221
+ em[class^=hl] {
222
+ font-style: normal;
223
+ background: #e6efff;
224
+ padding: 0.15em 0.35em;
225
+ border-radius: 5px;
226
+ }
@@ -0,0 +1,48 @@
1
+ .ui-autocomplete {
2
+ font-family: 'Helvetica Neue', Helvetica, sans-serif !important;
3
+ border: none !important;
4
+ border-radius: 0 !important;
5
+ background-color: #fff !important;
6
+ margin: 0 !important;
7
+ padding: 0 !important;
8
+ box-shadow: 0px 3px 3px 0px rgba(0,0,0,0.75);
9
+ }
10
+
11
+ .ui-autocomplete-category {
12
+ color: #fff;
13
+ background: #222;
14
+ font-size: 90%;
15
+ font-weight: 300;
16
+ text-transform: uppercase;
17
+ margin: 0 !important;
18
+ padding: 0.25em 0.5em 0.25em 0.5em;
19
+ }
20
+
21
+ .ui-autocomplete-item {
22
+ border-bottom: 1px solid #000;
23
+ margin: 0 !important;
24
+ padding: 0 !important;
25
+ }
26
+
27
+ .ui-autocomplete-item:hover,
28
+ .ui-autocomplete-item:focus {
29
+ color: #fff !important;
30
+ background: #0b6aff !important;
31
+ }
32
+
33
+ .ui-state-focus,
34
+ .ui-state-focus a,
35
+ .ui-state-active,
36
+ .ui-state-active a,
37
+ .ui-autocomplete-item:hover a {
38
+ color: #fff !important;
39
+ background: #0b6aff !important;
40
+ outline: none !important;
41
+ border: none !important;
42
+ border-radius: 0 !important;
43
+ }
44
+
45
+ a.ui-state-focus,
46
+ a.ui-state-active {
47
+ margin: 0px !important;
48
+ }
@@ -0,0 +1,113 @@
1
+ /* Based on https://github.com/plataformatec/simple_form/wiki/CSS-for-simple_form */
2
+
3
+ body.edit h1,
4
+ body.new h1 {
5
+ color: #999;
6
+ font-size: 100%;
7
+ text-transform: uppercase;
8
+ margin: 0 0 1em 5.5em;
9
+ }
10
+
11
+ body.edit a[href^="/artists"],
12
+ body.new a[href^="/artists"],
13
+ body.edit a[href^="/music/artists"],
14
+ body.new a[href^="/music/artists"] {
15
+ color: #222;
16
+ background: #ccc;
17
+ text-decoration: none;
18
+ border-radius: 0.3em;
19
+ padding: 0.25em 0.5em;
20
+ margin: 2em 0 0 5.5em;
21
+ display: inline-block;
22
+ }
23
+
24
+ body.edit a[href^="/artists"]:hover,
25
+ body.new a[href^="/artists"]:hover,
26
+ body.edit a[href^="/music/artists"]:hover,
27
+ body.new a[href^="/music/artists"]:hover {
28
+ color: #fff;
29
+ background: #333;
30
+ }
31
+
32
+ body.edit a[href^="/artists"]:last-child,
33
+ body.new a[href^="/artists"]:last-child,
34
+ body.edit a[href^="/music/artists"]:last-child,
35
+ body.new a[href^="/music/artists"]:last-child {
36
+ margin-left: 0;
37
+ }
38
+
39
+ .simple_form div.input {
40
+ margin-bottom: 1em;
41
+ clear: both;
42
+ }
43
+
44
+ .simple_form label {
45
+ color: #878787;
46
+ font-size: 80%;
47
+ text-transform: uppercase;
48
+ font-weight: 200;
49
+ float: left;
50
+ width: 5em;
51
+ text-align: right;
52
+ margin: 0.25em 1em;
53
+ }
54
+
55
+ div.boolean, .simple_form input[type='submit'] {
56
+ margin-left: 8.5em;
57
+ }
58
+
59
+ .field_with_errors input {
60
+ border: 2px solid #c70008 !important;
61
+ }
62
+
63
+ .simple_form .error {
64
+ color: #fff !important;
65
+ background: #c70008;
66
+ font-weight: bold;
67
+ clear: left;
68
+ display: block;
69
+ padding: 0.25em 0.5em;
70
+ margin-left: 5.6em;
71
+ width: 27.45em;
72
+ }
73
+
74
+ .simple_form .hint {
75
+ color: #878787;
76
+ font-size: 80%;
77
+ font-style: italic;
78
+ display: block;
79
+ margin: 0.25em 0 0 7em;
80
+ clear: left;
81
+ }
82
+
83
+ input {
84
+ margin: 0;
85
+ }
86
+
87
+ input.radio {
88
+ margin-right: 5px;
89
+ vertical-align: -3px;
90
+ }
91
+
92
+ input.check_boxes {
93
+ margin-left: 3px;
94
+ vertical-align: -3px;
95
+ }
96
+
97
+ label.collection_check_boxes {
98
+ float: none;
99
+ margin: 0;
100
+ vertical-align: -2px;
101
+ margin-left: 2px;
102
+ }
103
+
104
+ input.string,
105
+ textarea.text {
106
+ padding: 0.5em;
107
+ min-width: 40em;
108
+ border: 1px solid #ccc;
109
+ }
110
+
111
+ textarea.text {
112
+ min-height: 5em;
113
+ }