Skip to content

Commit 2f2c0fb

Browse files
committed
[RAILS] Added the 04-dsl template
Still a work in progress...
1 parent af08c9a commit 2f2c0fb

File tree

4 files changed

+632
-0
lines changed

4 files changed

+632
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# $ rails new searchapp --skip --skip-bundle --template https://raw.github.com/elasticsearch/elasticsearch-rails/master/elasticsearch-rails/lib/rails/templates/04-dsl.rb
2+
3+
# (See: 01-basic.rb, 02-pretty.rb, 03-expert.rb)
4+
5+
append_to_file 'README.rdoc', <<-README
6+
7+
== [4] DSL
8+
9+
The `dsl` template refactors the search definition in SearchController#index
10+
to use the [`elasticsearch-dsl`](https://github.com/elastic/elasticsearch-ruby/tree/dsl/elasticsearch-dsl)
11+
Rubygem for better expresivity and readability of the code.
12+
13+
README
14+
15+
git add: "README.rdoc"
16+
git commit: "-m '[03] Updated the application README'"
17+
18+
# ----- Add gems into Gemfile ---------------------------------------------------------------------
19+
20+
puts
21+
say_status "Rubygems", "Adding Rubygems into Gemfile...\n", :yellow
22+
puts '-'*80, ''; sleep 0.25
23+
24+
gem "elasticsearch-dsl", git: "git://github.com/elasticsearch/elasticsearch-ruby.git", branch: 'dsl'
25+
26+
git add: "Gemfile*"
27+
git commit: "-m 'Added the `elasticsearch-dsl` gem'"
28+
29+
# ----- Run bundle install ------------------------------------------------------------------------
30+
31+
run "bundle install"
32+
33+
# ----- Change the search definition implementation and associated views and tests ----------------
34+
35+
copy_file File.expand_path('../searchable.dsl.rb', __FILE__), 'app/models/concerns/searchable.rb', force: true
36+
# get 'https://raw.github.com/elasticsearch/elasticsearch-rails/templates/elasticsearch-rails/lib/rails/templates/searchable.dsl.rb',
37+
# 'app/models/concerns/searchable.rb'
38+
39+
copy_file File.expand_path('../index.html.dsl.erb', __FILE__), 'app/views/search/index.html.erb', force: true
40+
# get 'https://raw.github.com/elasticsearch/elasticsearch-rails/templates/elasticsearch-rails/lib/rails/templates/index.html.dsl.erb',
41+
# 'app/views/search/index.html.erb'
42+
43+
gsub_file "test/controllers/search_controller_test.rb", %r{test "should return facets" do.*?end}m, <<-CODE
44+
test "should return aggregations" do
45+
get :index, q: 'one'
46+
assert_response :success
47+
48+
aggregations = assigns(:articles).response.response['aggregations']
49+
50+
assert_equal 2, aggregations['categories']['categories']['buckets'].size
51+
assert_equal 2, aggregations['authors']['authors']['buckets'].size
52+
assert_equal 2, aggregations['published']['published']['buckets'].size
53+
54+
assert_equal 'John Smith', aggregations['authors']['authors']['buckets'][0]['key']
55+
assert_equal 'One', aggregations['categories']['categories']['buckets'][0]['key']
56+
assert_equal '2015-03-02T00:00:00.000Z', aggregations['published']['published']['buckets'][0]['key_as_string']
57+
end
58+
CODE
59+
60+
gsub_file "test/controllers/search_controller_test.rb", %r{test "should filter search results and the author and published date facets when user selects a category" do.*?end}m, <<-CODE
61+
test "should filter search results and the author and published date facets when user selects a category" do
62+
get :index, q: 'one', c: 'One'
63+
assert_response :success
64+
65+
assert_equal 2, assigns(:articles).size
66+
67+
aggregations = assigns(:articles).response.response['aggregations']
68+
69+
assert_equal 1, aggregations['authors']['authors']['buckets'].size
70+
assert_equal 1, aggregations['published']['published']['buckets'].size
71+
72+
# Do NOT filter the category facet
73+
assert_equal 2, aggregations['categories']['categories']['buckets'].size
74+
end
75+
CODE
76+
77+
gsub_file "test/controllers/search_controller_test.rb", %r{test "should filter search results and the category and published date facets when user selects a category" do.*?end}m, <<-CODE
78+
test "should filter search results and the category and published date facets when user selects a category" do
79+
get :index, q: 'one', a: 'Mary Smith'
80+
assert_response :success
81+
82+
assert_equal 1, assigns(:articles).size
83+
84+
aggregations = assigns(:articles).response.response['aggregations']
85+
86+
assert_equal 1, aggregations['categories']['categories']['buckets'].size
87+
assert_equal 1, aggregations['published']['published']['buckets'].size
88+
89+
# Do NOT filter the authors facet
90+
assert_equal 2, aggregations['authors']['authors']['buckets'].size
91+
end
92+
CODE
93+
94+
git add: "app/models/concerns/ app/views/search/ test/controllers/search_controller_test.rb"
95+
git commit: "-m 'Updated the Article.search method to use the Ruby DSL; Updated the views and tests'"
96+
97+
# ----- Print Git log -----------------------------------------------------------------------------
98+
99+
puts
100+
say_status "Git", "Details about the application:", :yellow
101+
puts '-'*80, ''
102+
103+
git tag: "dsl"
104+
git log: "--reverse --oneline HEAD...expert"
105+
106+
# ----- Start the application ---------------------------------------------------------------------
107+
108+
unless ENV['RAILS_NO_SERVER_START']
109+
require 'net/http'
110+
if (begin; Net::HTTP.get(URI('http://localhost:3000')); rescue Errno::ECONNREFUSED; false; rescue Exception; true; end)
111+
puts "\n"
112+
say_status "ERROR", "Some other application is running on port 3000!\n", :red
113+
puts '-'*80
114+
115+
port = ask("Please provide free port:", :bold)
116+
else
117+
port = '3000'
118+
end
119+
120+
puts "", "="*80
121+
say_status "DONE", "\e[1mStarting the application. Open http://localhost:#{port}\e[0m", :yellow
122+
puts "="*80, ""
123+
124+
run "rails server --port=#{port}"
125+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
<div class="col-md-12">
2+
<h1 class="text-right"><%= link_to 'Search New York Times articles', root_path %></h1>
3+
4+
<%= form_tag search_path, method: 'get', role: 'search' do %>
5+
<div class="input-group">
6+
<%= text_field_tag :q, params[:q], class: 'form-control', placeholder: 'Search...' %>
7+
8+
<span class="input-group-btn">
9+
<button type="submit" class="btn btn-default">
10+
<span class="glyphicon glyphicon-search"></span>
11+
</button>
12+
</span>
13+
</div>
14+
15+
<div id="form-options" class="clearfix">
16+
<div class="btn-group pull-left">
17+
<label class="checkbox-inline">
18+
<%= check_box_tag 'comments', 'y', params[:comments] == 'y', onclick: "$(this).closest('form').submit()" %>
19+
Search in comments?
20+
</label>
21+
<% params.slice(:a, :c, :s).each do |name, value| %>
22+
<%= hidden_field_tag name, value %>
23+
<% end %>
24+
</div>
25+
26+
<div class="btn-group pull-right">
27+
<p style="float: left; margin: 0.1em 0 0 0"><small>Displaying <%= (params[:page] || 1).to_i.ordinalize %> page with <%= @articles.size %> articles
28+
of <strong>total <%= @articles.total %></strong></small></p>
29+
30+
<button class="btn btn-default btn-xs dropdown-toggle" type="button" data-toggle="dropdown" style="margin-left: 0.5em">
31+
<% sort = case
32+
when params[:s] then params[:s]
33+
when params[:q].blank? then 'published_on'
34+
else 'relevancy'
35+
end
36+
%>
37+
sorted by <%= sort.humanize.downcase %> <span class="caret"></span>
38+
</button>
39+
<ul class="dropdown-menu" role="menu">
40+
<li><%= link_to "Sort by published on", search_path(params.except(:controller, :action).merge(s: 'published_on')), class: 'btn-xs' %></li>
41+
<li><%= link_to "Sort by relevancy", search_path(params.except(:controller, :action).merge(s: nil)), class: 'btn-xs' %></li>
42+
</ul>
43+
</div>
44+
</div>
45+
<% end %>
46+
47+
<hr>
48+
</div>
49+
50+
<% if @articles.size < 1 && (suggestions = @articles.response.response['suggest']) && suggestions.present? %>
51+
<div class="col-md-12">
52+
<p class="alert alert-warning">
53+
No documents have been found.
54+
<% if suggestions['suggest_title'].present? || suggestions['suggest_body'].present? %>
55+
Maybe you mean
56+
<%= suggestions.map { |k,v| v.first['options'] }.flatten.map {|v| v['text']}.uniq.map do |term|
57+
link_to term, search_path(params.except(:controller, :action).merge q: term)
58+
end.to_sentence(last_word_connector: ' or ').html_safe %>?
59+
<% end %>
60+
</p>
61+
</div>
62+
<% end %>
63+
64+
<div id="facets" class="col-md-3">
65+
<% unless @articles.size < 1 %>
66+
67+
<div class="categories panel panel-default">
68+
<p class="panel-heading"><%= link_to 'All Sections &rarr;'.html_safe, search_path(params.except(:controller, :action).merge(c: nil))%></p>
69+
70+
<div class="list-group">
71+
<% @articles.response.response['aggregations']['categories']['categories']['buckets'].each do |c| %>
72+
<%=
73+
link_to search_path(params.except(:controller, :action).merge(c: c['key'])),
74+
class: "list-group-item#{' active' if params[:c] == c['key']}" do
75+
c['key'].titleize.html_safe + content_tag(:small, c['doc_count'], class: 'badge').html_safe
76+
end
77+
%>
78+
<% end %>
79+
</div>
80+
</div>
81+
82+
<div class="authors panel panel-default">
83+
<p class="panel-heading"><%= link_to 'All Authors &rarr;'.html_safe, search_path(params.except(:controller, :action).merge(a: nil))%></p>
84+
85+
<div class="list-group">
86+
<% @articles.response.response['aggregations']['authors']['authors']['buckets'].each do |a| %>
87+
<%=
88+
link_to search_path(params.except(:controller, :action).merge(a: a['key'])),
89+
class: "list-group-item#{' active' if params[:a] == a['key']}" do
90+
a['key'].titleize.html_safe + content_tag(:small, a['doc_count'], class: 'badge').html_safe
91+
end
92+
%>
93+
<% end %>
94+
</div>
95+
</div>
96+
97+
<div class="authors panel panel-default">
98+
<p class="panel-heading"><%= link_to 'Any Date &rarr;'.html_safe, search_path(params.except(:controller, :action).merge(w: nil))%></p>
99+
100+
<div class="list-group">
101+
<% @articles.response.response['aggregations']['published']['published']['buckets'].each do |w| %>
102+
<%=
103+
__start = Time.at(w['key']/1000)
104+
__end = __start.end_of_week
105+
__date = __start.to_date.to_s(:iso)
106+
107+
link_to search_path(params.except(:controller, :action).merge(w: __date)),
108+
class: "list-group-item#{' active' if params[:w] == __date}" do
109+
"#{__start.to_date.to_s(:short)} &mdash; #{__end.to_date.to_s(:short)}".html_safe + \
110+
content_tag(:small, w['doc_count'], class: 'badge').html_safe
111+
end
112+
%>
113+
<% end %>
114+
</div>
115+
</div>
116+
<% end %>
117+
</div>
118+
119+
<div class="col-md-9">
120+
<div id="results">
121+
<% @articles.each do |article| %>
122+
<div class="result">
123+
<h3 class="title">
124+
<%= (article.try(:highlight).try(:title) ? article.highlight.title.join.html_safe : article.title) %>
125+
<small class="category"><%= article.categories.to_sentence %></small>
126+
</h3>
127+
128+
<p class="body">
129+
<% if article.try(:highlight).try(:abstract) %>
130+
<%= article.highlight.abstract.join.html_safe %>
131+
<% else %>
132+
<%= article.try(:highlight).try(:content) ? article.highlight.content.join('&hellip;').html_safe : article.abstract %>
133+
<% end %>
134+
</p>
135+
136+
<% if comments = article.try(:highlight) && article.highlight['comments.body'] %>
137+
<p class="comments">
138+
Comments: <%= comments.join('&hellip;').html_safe %>
139+
</p>
140+
<% end %>
141+
142+
<p class="text-muted">
143+
<small>Authors: <%= article.authors.map(&:full_name).to_sentence %></small> |
144+
<small>Published: <%= article.published_on %></small> |
145+
<small>Score: <%= article._score %></small>
146+
</p>
147+
</div>
148+
<% end %>
149+
</div>
150+
151+
<ul class="pager">
152+
<li class="previous"><%= link_to_previous_page @articles, 'Previous Page', params: params.slice(:q, :c, :a, :comments) %></li>
153+
<li class="next"><%= link_to_next_page @articles, 'Next Page', params: params.slice(:q, :c, :a, :comments) %></li>
154+
</ul>
155+
156+
</div>
157+
158+
<div class="footer <%= @articles.size < 1 ? 'col-md-12' : 'col-md-9 col-md-offset-3' %>">
159+
<p><small>Content provided by <a href="http://nytimes.com"><em>The New York Times</em></a>.</small></p>
160+
</div>

0 commit comments

Comments
 (0)