elasticsearch-rails 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +6 -0
- data/README.md +15 -13
- data/elasticsearch-rails.gemspec +1 -0
- data/lib/elasticsearch/rails/tasks/import.rb +6 -4
- data/lib/elasticsearch/rails/version.rb +1 -1
- data/lib/rails/templates/01-basic.rb +45 -27
- data/lib/rails/templates/02-pretty.rb +30 -15
- data/lib/rails/templates/03-expert.rb +240 -825
- data/lib/rails/templates/articles.yml.gz +0 -0
- data/lib/rails/templates/index.html.erb +157 -0
- data/lib/rails/templates/indexer.rb +27 -0
- data/lib/rails/templates/search.css +72 -0
- data/lib/rails/templates/searchable.rb +212 -0
- data/lib/rails/templates/seeds.rb +56 -0
- metadata +25 -2
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -78,30 +78,32 @@ You should see the duration of the request to Elasticsearch as part of each log
|
|
78
78
|
|
79
79
|
You can generate a fully working example Ruby on Rails application, with an `Article` model and a search form,
|
80
80
|
to play with (it even downloads _Elasticsearch_ itself, generates the application skeleton and leaves you with
|
81
|
-
a _Git_ repository to explore the steps and the code)
|
81
|
+
a _Git_ repository to explore the steps and the code) with the
|
82
|
+
[`01-basic.rb`](https://github.com/elasticsearch/elasticsearch-rails/blob/master/elasticsearch-rails/lib/rails/templates/01-basic.rb) template:
|
82
83
|
|
83
84
|
```bash
|
84
85
|
rails new searchapp --skip --skip-bundle --template https://raw.github.com/elasticsearch/elasticsearch-rails/master/elasticsearch-rails/lib/rails/templates/01-basic.rb
|
85
86
|
```
|
86
87
|
|
87
|
-
Run the same command again, in the same folder, with the
|
88
|
-
|
88
|
+
Run the same command again, in the same folder, with the
|
89
|
+
[`02-pretty`](https://github.com/elasticsearch/elasticsearch-rails/blob/master/elasticsearch-rails/lib/rails/templates/02-pretty.rb)
|
90
|
+
template to add features such as a custom `Article.search` method, result highlighting and
|
91
|
+
[_Bootstrap_](http://getbootstrap.com) integration:
|
89
92
|
|
90
93
|
```bash
|
91
94
|
rails new searchapp --skip --skip-bundle --template https://raw.github.com/elasticsearch/elasticsearch-rails/master/elasticsearch-rails/lib/rails/templates/02-pretty.rb
|
92
95
|
```
|
93
96
|
|
94
|
-
|
95
|
-
|
97
|
+
Run the same command with the [`03-expert.rb`](https://github.com/elasticsearch/elasticsearch-rails/blob/master/elasticsearch-rails/lib/rails/templates/03-expert.rb)
|
98
|
+
template to refactor the application into a more complex use case,
|
99
|
+
with couple of hundreds of The New York Times articles as the example content.
|
100
|
+
The template will extract the Elasticsearch integration into a `Searchable` "concern" module,
|
101
|
+
define complex mapping, custom serialization, implement faceted navigation and suggestions as a part of
|
102
|
+
a complex query, and add a _Sidekiq_-based worker for updating the index in the background.
|
96
103
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
being worked on, such as:
|
101
|
-
|
102
|
-
* Rake tasks for convenient (re)indexing your models from the command line
|
103
|
-
* Hooking into Rails' notification system to display Elasticsearch related statistics in the application log
|
104
|
-
* Instrumentation support for NewRelic integration
|
104
|
+
```bash
|
105
|
+
rails new searchapp --skip --skip-bundle --template https://raw.github.com/elasticsearch/elasticsearch-rails/master/elasticsearch-rails/lib/rails/templates/03-expert.rb
|
106
|
+
```
|
105
107
|
|
106
108
|
## License
|
107
109
|
|
data/elasticsearch-rails.gemspec
CHANGED
@@ -56,16 +56,17 @@ namespace :elasticsearch do
|
|
56
56
|
rescue NoMethodError; end
|
57
57
|
end
|
58
58
|
|
59
|
-
klass.import force: ENV.fetch('FORCE', false),
|
60
|
-
|
61
|
-
|
62
|
-
|
59
|
+
total_errors = klass.import force: ENV.fetch('FORCE', false),
|
60
|
+
batch_size: ENV.fetch('BATCH', 1000).to_i,
|
61
|
+
index: ENV.fetch('INDEX', nil),
|
62
|
+
type: ENV.fetch('TYPE', nil) do |response|
|
63
63
|
pbar.inc response['items'].size if pbar
|
64
64
|
STDERR.flush
|
65
65
|
STDOUT.flush
|
66
66
|
end
|
67
67
|
pbar.finish if pbar
|
68
68
|
|
69
|
+
puts "[IMPORT] #{total_errors} errors occurred" unless total_errors.zero?
|
69
70
|
puts '[IMPORT] Done'
|
70
71
|
end
|
71
72
|
|
@@ -96,6 +97,7 @@ namespace :elasticsearch do
|
|
96
97
|
|
97
98
|
ENV['CLASS'] = klass.to_s
|
98
99
|
Rake::Task["elasticsearch:import:model"].invoke
|
100
|
+
Rake::Task["elasticsearch:import:model"].reenable
|
99
101
|
puts
|
100
102
|
end
|
101
103
|
end
|
@@ -20,8 +20,8 @@
|
|
20
20
|
#
|
21
21
|
# =====================================================================================================
|
22
22
|
|
23
|
-
require '
|
24
|
-
|
23
|
+
require 'uri'
|
24
|
+
require 'net/http'
|
25
25
|
|
26
26
|
at_exit do
|
27
27
|
pid = File.read("#{destination_root}/tmp/pids/elasticsearch.pid") rescue nil
|
@@ -33,7 +33,7 @@ end
|
|
33
33
|
|
34
34
|
run "touch tmp/.gitignore"
|
35
35
|
|
36
|
-
append_to_file ".gitignore", "vendor/elasticsearch-0.
|
36
|
+
append_to_file ".gitignore", "vendor/elasticsearch-1.0.1/\n"
|
37
37
|
|
38
38
|
git :init
|
39
39
|
git add: "."
|
@@ -41,12 +41,12 @@ git commit: "-m 'Initial commit: Clean application'"
|
|
41
41
|
|
42
42
|
# ----- Download Elasticsearch --------------------------------------------------------------------
|
43
43
|
|
44
|
-
unless (
|
44
|
+
unless (Net::HTTP.get(URI.parse('http://localhost:9200')) rescue false)
|
45
45
|
COMMAND = <<-COMMAND.gsub(/^ /, '')
|
46
|
-
curl -# -O "http://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-0.
|
47
|
-
tar -zxf elasticsearch-0.
|
48
|
-
rm -f elasticsearch-0.
|
49
|
-
./elasticsearch-0.
|
46
|
+
curl -# -O "http://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.0.1.tar.gz"
|
47
|
+
tar -zxf elasticsearch-1.0.1.tar.gz
|
48
|
+
rm -f elasticsearch-1.0.1.tar.gz
|
49
|
+
./elasticsearch-1.0.1/bin/elasticsearch -d -p #{destination_root}/tmp/pids/elasticsearch.pid
|
50
50
|
COMMAND
|
51
51
|
|
52
52
|
puts "\n"
|
@@ -70,7 +70,7 @@ unless (client.ping rescue false)
|
|
70
70
|
run "(#{exec})" # Launch Elasticsearch in subshell
|
71
71
|
end
|
72
72
|
end
|
73
|
-
end
|
73
|
+
end unless ENV['RAILS_NO_ES_INSTALL']
|
74
74
|
|
75
75
|
# ----- Add README --------------------------------------------------------------------------------
|
76
76
|
|
@@ -123,6 +123,7 @@ gem 'mocha', group: 'test', require: 'mocha/setup'
|
|
123
123
|
comment_lines 'Gemfile', /gem 'coffee/
|
124
124
|
comment_lines 'Gemfile', /gem 'sass/
|
125
125
|
comment_lines 'Gemfile', /gem 'uglifier/
|
126
|
+
uncomment_lines 'Gemfile', /gem 'therubyracer/
|
126
127
|
|
127
128
|
# ----- Add gems into Gemfile ---------------------------------------------------------------------
|
128
129
|
|
@@ -134,6 +135,23 @@ gem 'elasticsearch', git: 'git://github.com/elasticsearch/elasticsearch-ru
|
|
134
135
|
gem 'elasticsearch-model', git: 'git://github.com/elasticsearch/elasticsearch-rails.git'
|
135
136
|
gem 'elasticsearch-rails', git: 'git://github.com/elasticsearch/elasticsearch-rails.git'
|
136
137
|
|
138
|
+
|
139
|
+
git add: "Gemfile*"
|
140
|
+
git commit: "-m 'Added libraries into Gemfile'"
|
141
|
+
|
142
|
+
# ----- Disable asset logging in development ------------------------------------------------------
|
143
|
+
|
144
|
+
puts
|
145
|
+
say_status "Application", "Disabling asset logging in development...\n", :yellow
|
146
|
+
puts '-'*80, ''; sleep 0.25
|
147
|
+
|
148
|
+
environment 'config.assets.logger = false', env: 'development'
|
149
|
+
gem 'quiet_assets', group: "development"
|
150
|
+
|
151
|
+
git add: "Gemfile*"
|
152
|
+
git add: "config/"
|
153
|
+
git commit: "-m 'Disabled asset logging in development'"
|
154
|
+
|
137
155
|
# ----- Install gems ------------------------------------------------------------------------------
|
138
156
|
|
139
157
|
puts
|
@@ -142,9 +160,6 @@ puts '-'*80, ''
|
|
142
160
|
|
143
161
|
run "bundle install"
|
144
162
|
|
145
|
-
git add: "Gemfile*"
|
146
|
-
git commit: "-m 'Added libraries into Gemfile'"
|
147
|
-
|
148
163
|
# ----- Generate Article resource -----------------------------------------------------------------
|
149
164
|
|
150
165
|
puts
|
@@ -169,6 +184,7 @@ file 'app/models/article.rb', <<-CODE
|
|
169
184
|
class Article < ActiveRecord::Base
|
170
185
|
include Elasticsearch::Model
|
171
186
|
include Elasticsearch::Model::Callbacks
|
187
|
+
#{'attr_accessible :title, :content, :published_on' if Rails::VERSION::STRING < '4'}
|
172
188
|
end
|
173
189
|
CODE
|
174
190
|
|
@@ -221,7 +237,7 @@ resources :articles do
|
|
221
237
|
end
|
222
238
|
CODE
|
223
239
|
|
224
|
-
gsub_file 'test/controllers/articles_controller_test.rb
|
240
|
+
gsub_file "#{Rails::VERSION::STRING > '4' ? 'test/controllers' : 'test/functional'}/articles_controller_test.rb", %r{setup do.*?end}m, <<-CODE
|
225
241
|
setup do
|
226
242
|
@article = articles(:one)
|
227
243
|
|
@@ -230,7 +246,7 @@ setup do
|
|
230
246
|
end
|
231
247
|
CODE
|
232
248
|
|
233
|
-
inject_into_file 'test/controllers/articles_controller_test.rb
|
249
|
+
inject_into_file "#{Rails::VERSION::STRING > '4' ? 'test/controllers' : 'test/functional'}/articles_controller_test.rb", after: %r{test "should get index" do.*?end}m do
|
234
250
|
<<-CODE
|
235
251
|
|
236
252
|
|
@@ -300,19 +316,21 @@ git log: "--reverse --oneline"
|
|
300
316
|
|
301
317
|
# ----- Start the application ---------------------------------------------------------------------
|
302
318
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
319
|
+
unless ENV['RAILS_NO_SERVER_START']
|
320
|
+
require 'net/http'
|
321
|
+
if (begin; Net::HTTP.get(URI('http://localhost:3000')); rescue Errno::ECONNREFUSED; false; rescue Exception; true; end)
|
322
|
+
puts "\n"
|
323
|
+
say_status "ERROR", "Some other application is running on port 3000!\n", :red
|
324
|
+
puts '-'*80
|
308
325
|
|
309
|
-
|
310
|
-
else
|
311
|
-
|
312
|
-
end
|
326
|
+
port = ask("Please provide free port:", :bold)
|
327
|
+
else
|
328
|
+
port = '3000'
|
329
|
+
end
|
313
330
|
|
314
|
-
puts "", "="*80
|
315
|
-
say_status "DONE", "\e[1mStarting the application.\e[0m", :yellow
|
316
|
-
puts "="*80, ""
|
331
|
+
puts "", "="*80
|
332
|
+
say_status "DONE", "\e[1mStarting the application.\e[0m", :yellow
|
333
|
+
puts "="*80, ""
|
317
334
|
|
318
|
-
run "rails server --port=#{port}"
|
335
|
+
run "rails server --port=#{port}"
|
336
|
+
end
|
@@ -22,6 +22,19 @@ README
|
|
22
22
|
git add: "README.rdoc"
|
23
23
|
git commit: "-m '[02] Updated the application README'"
|
24
24
|
|
25
|
+
# ----- Update application.rb ---------------------------------------------------------------------
|
26
|
+
|
27
|
+
puts
|
28
|
+
say_status "Rubygems", "Adding Rails logger integration...\n", :yellow
|
29
|
+
puts '-'*80, ''; sleep 0.25
|
30
|
+
|
31
|
+
insert_into_file 'config/application.rb',
|
32
|
+
"\n\nrequire 'elasticsearch/rails/instrumentation'\n",
|
33
|
+
after: 'Bundler.require(:default, Rails.env)'
|
34
|
+
|
35
|
+
git add: "config/application.rb"
|
36
|
+
git commit: "-m 'Added the Rails logger integration to application.rb'"
|
37
|
+
|
25
38
|
# ----- Add gems into Gemfile ---------------------------------------------------------------------
|
26
39
|
|
27
40
|
puts
|
@@ -73,7 +86,7 @@ insert_into_file 'app/models/article.rb', <<-CODE, after: 'include Elasticsearch
|
|
73
86
|
end
|
74
87
|
CODE
|
75
88
|
|
76
|
-
gsub_file "test/models/article_test.rb", %r{# test "the truth" do.*?# end}m, <<-CODE
|
89
|
+
gsub_file "#{Rails::VERSION::STRING > '4' ? 'test/models' : 'test/unit' }/article_test.rb", %r{# test "the truth" do.*?# end}m, <<-CODE
|
77
90
|
|
78
91
|
test "has a search method delegating to __elasticsearch__" do
|
79
92
|
Article.__elasticsearch__.expects(:search).with do |definition|
|
@@ -85,7 +98,7 @@ gsub_file "test/models/article_test.rb", %r{# test "the truth" do.*?# end}m, <<-
|
|
85
98
|
CODE
|
86
99
|
|
87
100
|
git add: "app/models/article.rb"
|
88
|
-
git add: "test
|
101
|
+
git add: "test/**/article_test.rb"
|
89
102
|
git commit: "-m 'Added an `Article.search` method'"
|
90
103
|
|
91
104
|
# ----- Add loading Bootstrap assets --------------------------------------------------------------
|
@@ -266,19 +279,21 @@ git log: "--reverse --oneline pretty...basic"
|
|
266
279
|
|
267
280
|
# ----- Start the application ---------------------------------------------------------------------
|
268
281
|
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
282
|
+
unless ENV['RAILS_NO_SERVER_START']
|
283
|
+
require 'net/http'
|
284
|
+
if (begin; Net::HTTP.get(URI('http://localhost:3000')); rescue Errno::ECONNREFUSED; false; rescue Exception; true; end)
|
285
|
+
puts "\n"
|
286
|
+
say_status "ERROR", "Some other application is running on port 3000!\n", :red
|
287
|
+
puts '-'*80
|
274
288
|
|
275
|
-
|
276
|
-
else
|
277
|
-
|
278
|
-
end
|
289
|
+
port = ask("Please provide free port:", :bold)
|
290
|
+
else
|
291
|
+
port = '3000'
|
292
|
+
end
|
279
293
|
|
280
|
-
puts "", "="*80
|
281
|
-
say_status "DONE", "\e[1mStarting the application. Open http://localhost:#{port}\e[0m", :yellow
|
282
|
-
puts "="*80, ""
|
294
|
+
puts "", "="*80
|
295
|
+
say_status "DONE", "\e[1mStarting the application. Open http://localhost:#{port}\e[0m", :yellow
|
296
|
+
puts "="*80, ""
|
283
297
|
|
284
|
-
run "rails server --port=#{port}"
|
298
|
+
run "rails server --port=#{port}"
|
299
|
+
end
|
@@ -2,113 +2,98 @@
|
|
2
2
|
|
3
3
|
# (See: 01-basic.rb, 02-pretty.rb)
|
4
4
|
|
5
|
-
|
5
|
+
append_to_file 'README.rdoc', <<-README
|
6
|
+
|
7
|
+
== [3] Expert
|
8
|
+
|
9
|
+
The `expert` template changes to a complex database schema with model relationships: article belongs
|
10
|
+
to a category, has many authors and comments.
|
11
|
+
|
12
|
+
* The Elasticsearch integration is refactored into the `Searchable` concern
|
13
|
+
* A complex mapping for the index is defined
|
14
|
+
* A custom serialization is defined in `Article#as_indexed_json`
|
15
|
+
* The `search` method is amended with facets and suggestions
|
16
|
+
* A [Sidekiq](http://sidekiq.org) worker for handling index updates in background is added
|
17
|
+
* A custom `SearchController` with associated view is added
|
18
|
+
* A Rails initializer is added to customize the Elasticsearch client configuration
|
19
|
+
* Seed script and example data from New York Times is added
|
20
|
+
|
21
|
+
README
|
22
|
+
|
23
|
+
git add: "README.rdoc"
|
24
|
+
git commit: "-m '[03] Updated the application README'"
|
25
|
+
|
26
|
+
# ----- Add gems into Gemfile ---------------------------------------------------------------------
|
6
27
|
|
7
28
|
puts
|
8
|
-
say_status "
|
9
|
-
puts '-'*80, ''; sleep 0.
|
29
|
+
say_status "Rubygems", "Adding Rubygems into Gemfile...\n", :yellow
|
30
|
+
puts '-'*80, ''; sleep 0.25
|
10
31
|
|
11
|
-
|
12
|
-
create_file "app/views/articles/_search_form.html.erb", match
|
13
|
-
"\n<%= render partial: 'search_form' %>\n"
|
14
|
-
end
|
32
|
+
gem "oj"
|
15
33
|
|
16
|
-
git :
|
17
|
-
git :
|
34
|
+
git add: "Gemfile*"
|
35
|
+
git commit: "-m 'Added Ruby gems'"
|
18
36
|
|
19
|
-
# -----
|
37
|
+
# ----- Customize the Rails console ---------------------------------------------------------------
|
20
38
|
|
21
39
|
puts
|
22
|
-
say_status "
|
23
|
-
puts '-'*80, ''; sleep 0.
|
40
|
+
say_status "Rails", "Customizing `rails console`...\n", :yellow
|
41
|
+
puts '-'*80, ''; sleep 0.25
|
24
42
|
|
25
|
-
create_file 'app/models/concerns/searchable.rb', <<-CODE
|
26
|
-
module Searchable
|
27
|
-
extend ActiveSupport::Concern
|
28
43
|
|
29
|
-
|
30
|
-
include Elasticsearch::Model
|
31
|
-
end
|
44
|
+
gem "pry", group: 'development'
|
32
45
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
fields: ['title^10', 'content']
|
41
|
-
}
|
42
|
-
},
|
43
|
-
highlight: {
|
44
|
-
pre_tags: ['<em class="label label-highlight">'],
|
45
|
-
post_tags: ['</em>'],
|
46
|
-
fields: {
|
47
|
-
title: { number_of_fragments: 0 },
|
48
|
-
content: { fragment_size: 25 }
|
49
|
-
}
|
50
|
-
}
|
51
|
-
}
|
52
|
-
)
|
53
|
-
end
|
46
|
+
environment nil, env: 'development' do
|
47
|
+
%q{
|
48
|
+
console do
|
49
|
+
config.console = Pry
|
50
|
+
Pry.config.history.file = Rails.root.join('tmp/console_history.rb').to_s
|
51
|
+
Pry.config.prompt = [ proc { |obj, nest_level, _| "(#{obj})> " },
|
52
|
+
proc { |obj, nest_level, _| ' '*obj.to_s.size + ' '*(nest_level+1) + '| ' } ]
|
54
53
|
end
|
54
|
+
}
|
55
55
|
end
|
56
|
-
CODE
|
57
56
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
include Searchable
|
62
|
-
end
|
63
|
-
CODE
|
57
|
+
git add: "Gemfile*"
|
58
|
+
git add: "config/"
|
59
|
+
git commit: "-m 'Added Pry as the console for development'"
|
64
60
|
|
65
|
-
|
66
|
-
git :commit => "-m 'Refactored the Elasticsearch integration into a concern\n\nSee:\n\n* http://37signals.com/svn/posts/3372-put-chubby-models-on-a-diet-with-concerns\n* http://joshsymonds.com/blog/2012/10/25/rails-concerns-v-searchable-with-elasticsearch/'"
|
67
|
-
|
68
|
-
# ----- Add initializer ---------------------------------------------------------------------------
|
61
|
+
# ----- Disable asset logging in development ------------------------------------------------------
|
69
62
|
|
70
63
|
puts
|
71
|
-
say_status "Application", "
|
72
|
-
puts '-'*80, ''; sleep 0.
|
64
|
+
say_status "Application", "Disabling asset logging in development...\n", :yellow
|
65
|
+
puts '-'*80, ''; sleep 0.25
|
73
66
|
|
74
|
-
|
75
|
-
|
76
|
-
ELASTICSEARCH_URL = ENV['ELASTICSEARCH_URL'] || 'http://localhost:9200'
|
67
|
+
environment 'config.assets.logger = false', env: 'development'
|
68
|
+
gem 'quiet_assets', group: "development"
|
77
69
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
tracer = ActiveSupport::Logger.new(STDERR)
|
82
|
-
tracer.level = Logger::INFO
|
83
|
-
end
|
70
|
+
git add: "Gemfile*"
|
71
|
+
git add: "config/"
|
72
|
+
git commit: "-m 'Disabled asset logging in development'"
|
84
73
|
|
85
|
-
|
86
|
-
CODE
|
74
|
+
# ----- Run bundle install ------------------------------------------------------------------------
|
87
75
|
|
88
|
-
|
89
|
-
git :commit => "-m 'Added application initializer with Elasticsearch configuration'"
|
76
|
+
run "bundle install"
|
90
77
|
|
91
|
-
# -----
|
78
|
+
# ----- Define and generate schema ----------------------------------------------------------------
|
92
79
|
|
93
80
|
puts
|
94
|
-
say_status "
|
95
|
-
puts '-'*80, ''
|
81
|
+
say_status "Models", "Adding complex schema...\n", :yellow
|
82
|
+
puts '-'*80, ''
|
96
83
|
|
97
84
|
generate :scaffold, "Category title"
|
98
|
-
generate :scaffold, "Book title:string content:text downloads:integer category:references"
|
99
85
|
generate :scaffold, "Author first_name last_name"
|
100
|
-
generate :scaffold, "Authorship
|
86
|
+
generate :scaffold, "Authorship article:references author:references"
|
101
87
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
88
|
+
generate :model, "Comment body:text user:string user_location:string stars:integer pick:boolean article:references"
|
89
|
+
generate :migration, "CreateArticlesCategories article:references category:references"
|
90
|
+
|
91
|
+
rake "db:drop"
|
92
|
+
rake "db:migrate"
|
107
93
|
|
108
|
-
insert_into_file "app/models/
|
94
|
+
insert_into_file "app/models/category.rb", :before => "end" do
|
109
95
|
<<-CODE
|
110
|
-
|
111
|
-
has_many :authors, through: :authorships
|
96
|
+
has_and_belongs_to_many :articles
|
112
97
|
CODE
|
113
98
|
end
|
114
99
|
|
@@ -122,764 +107,192 @@ insert_into_file "app/models/author.rb", :before => "end" do
|
|
122
107
|
CODE
|
123
108
|
end
|
124
109
|
|
125
|
-
|
110
|
+
gsub_file "app/models/authorship.rb", %r{belongs_to :article$}, <<-CODE
|
111
|
+
belongs_to :article, touch: true
|
112
|
+
CODE
|
113
|
+
|
114
|
+
insert_into_file "app/models/article.rb", after: "ActiveRecord::Base" do
|
115
|
+
<<-CODE
|
116
|
+
|
117
|
+
has_and_belongs_to_many :categories, after_add: [ lambda { |a,c| Indexer.perform_async(:update, a.class.to_s, a.id) } ],
|
118
|
+
after_remove: [ lambda { |a,c| Indexer.perform_async(:update, a.class.to_s, a.id) } ]
|
119
|
+
has_many :authorships
|
120
|
+
has_many :authors, through: :authorships
|
121
|
+
has_many :comments
|
122
|
+
CODE
|
123
|
+
end
|
124
|
+
|
125
|
+
gsub_file "app/models/comment.rb", %r{belongs_to :article$}, <<-CODE
|
126
|
+
belongs_to :article, touch: true
|
127
|
+
CODE
|
126
128
|
|
127
|
-
|
129
|
+
git add: "."
|
130
|
+
git commit: "-m 'Generated Category, Author and Comment resources'"
|
128
131
|
|
129
|
-
# -----
|
132
|
+
# ----- Add the `abstract` column -----------------------------------------------------------------
|
130
133
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
books = YAML.parse <<-DATA
|
138
|
-
---
|
139
|
-
- :title: Dracula
|
140
|
-
:authors:
|
141
|
-
- :last_name: Stoker
|
142
|
-
:first_name: Bram
|
143
|
-
:downloads: 12197
|
144
|
-
:category: Fiction
|
145
|
-
:content: |
|
146
|
-
_3 May. Bistritz._--Left Munich at 8:35 P. M., on 1st May, arriving at
|
147
|
-
Vienna early next morning; should have arrived at 6:46, but train was an
|
148
|
-
hour late. Buda-Pesth seems a wonderful place, from the glimpse which I
|
149
|
-
got of it from the train and the little I could walk through the
|
150
|
-
streets. I feared to go very far from the station, as we had arrived
|
151
|
-
late and would start as near the correct time as possible. The
|
152
|
-
impression I had was that we were leaving the West and entering the
|
153
|
-
East; the most western of splendid bridges over the Danube, which is
|
154
|
-
here of noble width and depth, took us among the traditions of Turkish
|
155
|
-
rule.
|
156
|
-
|
157
|
-
We left in pretty good time, and came after nightfall to Klausenburgh.
|
158
|
-
Here I stopped for the night at the Hotel Royale. I had for dinner, or
|
159
|
-
rather supper, a chicken done up some way with red pepper, which was
|
160
|
-
very good but thirsty. (_Mem._, get recipe for Mina.) I asked the
|
161
|
-
waiter, and he said it was called "paprika hendl," and that, as it was a
|
162
|
-
national dish, I should be able to get it anywhere along the
|
163
|
-
Carpathians. I found my smattering of German very useful here; indeed, I
|
164
|
-
don't know how I should be able to get on without it.
|
165
|
-
|
166
|
-
Having had some time at my disposal when in London, I had visited the
|
167
|
-
British Museum, and made search among the books and maps in the library
|
168
|
-
regarding Transylvania; it had struck me that some foreknowledge of the
|
169
|
-
country could hardly fail to have some importance in dealing with a
|
170
|
-
nobleman of that country. I find that the district he named is in the
|
171
|
-
extreme east of the country, just on the borders of three states,
|
172
|
-
Transylvania, Moldavia and Bukovina, in the midst of the Carpathian
|
173
|
-
mountains; one of the wildest and least known portions of Europe. I was
|
174
|
-
not able to light on any map or work giving the exact locality of the
|
175
|
-
Castle Dracula, as there are no maps of this country as yet to compare
|
176
|
-
with our own Ordnance Survey maps; but I found that Bistritz, the post
|
177
|
-
town named by Count Dracula, is a fairly well-known place. I shall enter
|
178
|
-
here some of my notes, as they may refresh my memory when I talk over my
|
179
|
-
travels with Mina.
|
180
|
-
|
181
|
-
In the population of Transylvania there are four distinct nationalities:
|
182
|
-
Saxons in the South, and mixed with them the Wallachs, who are the
|
183
|
-
descendants of the Dacians; Magyars in the West, and Szekelys in the
|
184
|
-
East and North. I am going among the latter, who claim to be descended
|
185
|
-
from Attila and the Huns. This may be so, for when the Magyars conquered
|
186
|
-
the country in the eleventh century they found the Huns settled in it. I
|
187
|
-
read that every known superstition in the world is gathered into the
|
188
|
-
horseshoe of the Carpathians, as if it were the centre of some sort of
|
189
|
-
imaginative whirlpool; if so my stay may be very interesting. (_Mem._, I
|
190
|
-
must ask the Count all about them.)
|
191
|
-
|
192
|
-
I did not sleep well, though my bed was comfortable enough, for I had
|
193
|
-
all sorts of queer dreams. There was a dog howling all night under my
|
194
|
-
window, which may have had something to do with it; or it may have been
|
195
|
-
the paprika, for I had to drink up all the water in my carafe, and was
|
196
|
-
still thirsty. Towards morning I slept and was wakened by the continuous
|
197
|
-
knocking at my door, so I guess I must have been sleeping soundly then.
|
198
|
-
I had for breakfast more paprika, and a sort of porridge of maize flour
|
199
|
-
which they said was "mamaliga," and egg-plant stuffed with forcemeat, a
|
200
|
-
very excellent dish, which they call "impletata." (_Mem._, get recipe
|
201
|
-
for this also.) I had to hurry breakfast, for the train started a little
|
202
|
-
before eight, or rather it ought to have done so, for after rushing to
|
203
|
-
the station at 7:30 I had to sit in the carriage for more than an hour
|
204
|
-
before we began to move. It seems to me that the further east you go the
|
205
|
-
more unpunctual are the trains. What ought they to be in China?
|
206
|
-
|
207
|
-
All day long we seemed to dawdle through a country which was full of
|
208
|
-
beauty of every kind. Sometimes we saw little towns or castles on the
|
209
|
-
top of steep hills such as we see in old missals; sometimes we ran by
|
210
|
-
rivers and streams which seemed from the wide stony margin on each side
|
211
|
-
of them to be subject to great floods. It takes a lot of water, and
|
212
|
-
running strong, to sweep the outside edge of a river clear. At every
|
213
|
-
station there were groups of people, sometimes crowds, and in all sorts
|
214
|
-
of attire. Some of them were just like the peasants at home or those I
|
215
|
-
saw coming through France and Germany, with short jackets and round hats
|
216
|
-
and home-made trousers; but others were very picturesque. The women
|
217
|
-
looked pretty, except when you got near them, but they were very clumsy
|
218
|
-
about the waist. They had all full white sleeves of some kind or other,
|
219
|
-
and most of them had big belts with a lot of strips of something
|
220
|
-
fluttering from them like the dresses in a ballet, but of course there
|
221
|
-
were petticoats under them. The strangest figures we saw were the
|
222
|
-
Slovaks, who were more barbarian than the rest, with their big cow-boy
|
223
|
-
hats, great baggy dirty-white trousers, white linen shirts, and enormous
|
224
|
-
heavy leather belts, nearly a foot wide, all studded over with brass
|
225
|
-
nails. They wore high boots, with their trousers tucked into them, and
|
226
|
-
had long black hair and heavy black moustaches. They are very
|
227
|
-
picturesque, but do not look prepossessing. On the stage they would be
|
228
|
-
set down at once as some old Oriental band of brigands. They are,
|
229
|
-
however, I am told, very harmless and rather wanting in natural
|
230
|
-
self-assertion.
|
231
|
-
|
232
|
-
It was on the dark side of twilight when we got to Bistritz, which is a
|
233
|
-
very interesting old place. Being practically on the frontier--for the
|
234
|
-
Borgo Pass leads from it into Bukovina--it has had a very stormy
|
235
|
-
existence, and it certainly shows marks of it. Fifty years ago a series
|
236
|
-
of great fires took place, which made terrible havoc on five separate
|
237
|
-
occasions. At the very beginning of the seventeenth century it underwent
|
238
|
-
a siege of three weeks and lost 13,000 people, the casualties of war
|
239
|
-
proper being assisted by famine and disease.
|
240
|
-
|
241
|
-
Count Dracula had directed me to go to the Golden Krone Hotel, which I
|
242
|
-
found, to my great delight, to be thoroughly old-fashioned, for of
|
243
|
-
course I wanted to see all I could of the ways of the country. I was
|
244
|
-
evidently expected, for when I got near the door I faced a
|
245
|
-
cheery-looking elderly woman in the usual peasant dress--white
|
246
|
-
undergarment with long double apron, front, and back, of coloured stuff
|
247
|
-
fitting almost too tight for modesty. When I came close she bowed and
|
248
|
-
said, "The Herr Englishman?" "Yes," I said, "Jonathan Harker." She
|
249
|
-
smiled, and gave some message to an elderly man in white shirt-sleeves,
|
250
|
-
who had followed her to the door. He went, but immediately returned with
|
251
|
-
a letter:--
|
252
|
-
|
253
|
-
"My Friend.--Welcome to the Carpathians. I am anxiously expecting
|
254
|
-
you. Sleep well to-night. At three to-morrow the diligence will
|
255
|
-
start for Bukovina; a place on it is kept for you. At the Borgo
|
256
|
-
Pass my carriage will await you and will bring you to me. I trust
|
257
|
-
that your journey from London has been a happy one, and that you
|
258
|
-
will enjoy your stay in my beautiful land.
|
259
|
-
|
260
|
-
"Your friend,
|
261
|
-
|
262
|
-
"DRACULA."
|
263
|
-
|
264
|
-
- :title: Beyond Good and Evil
|
265
|
-
:authors:
|
266
|
-
- :last_name: Nietzsche
|
267
|
-
:first_name: Friedrich Wilhelm
|
268
|
-
:downloads: 8222
|
269
|
-
:category: Philosophy
|
270
|
-
:content: |
|
271
|
-
SUPPOSING that Truth is a woman--what then? Is there not ground
|
272
|
-
for suspecting that all philosophers, in so far as they have been
|
273
|
-
dogmatists, have failed to understand women--that the terrible
|
274
|
-
seriousness and clumsy importunity with which they have usually paid
|
275
|
-
their addresses to Truth, have been unskilled and unseemly methods for
|
276
|
-
winning a woman? Certainly she has never allowed herself to be won; and
|
277
|
-
at present every kind of dogma stands with sad and discouraged mien--IF,
|
278
|
-
indeed, it stands at all! For there are scoffers who maintain that it
|
279
|
-
has fallen, that all dogma lies on the ground--nay more, that it is at
|
280
|
-
its last gasp. But to speak seriously, there are good grounds for hoping
|
281
|
-
that all dogmatizing in philosophy, whatever solemn, whatever conclusive
|
282
|
-
and decided airs it has assumed, may have been only a noble puerilism
|
283
|
-
and tyronism; and probably the time is at hand when it will be once
|
284
|
-
and again understood WHAT has actually sufficed for the basis of such
|
285
|
-
imposing and absolute philosophical edifices as the dogmatists have
|
286
|
-
hitherto reared: perhaps some popular superstition of immemorial time
|
287
|
-
(such as the soul-superstition, which, in the form of subject- and
|
288
|
-
ego-superstition, has not yet ceased doing mischief): perhaps some
|
289
|
-
play upon words, a deception on the part of grammar, or an
|
290
|
-
audacious generalization of very restricted, very personal, very
|
291
|
-
human--all-too-human facts. The philosophy of the dogmatists, it is to
|
292
|
-
be hoped, was only a promise for thousands of years afterwards, as was
|
293
|
-
astrology in still earlier times, in the service of which probably more
|
294
|
-
labour, gold, acuteness, and patience have been spent than on any
|
295
|
-
actual science hitherto: we owe to it, and to its "super-terrestrial"
|
296
|
-
pretensions in Asia and Egypt, the grand style of architecture. It seems
|
297
|
-
that in order to inscribe themselves upon the heart of humanity with
|
298
|
-
everlasting claims, all great things have first to wander about the
|
299
|
-
earth as enormous and awe-inspiring caricatures: dogmatic philosophy has
|
300
|
-
been a caricature of this kind--for instance, the Vedanta doctrine in
|
301
|
-
Asia, and Platonism in Europe. Let us not be ungrateful to it, although
|
302
|
-
it must certainly be confessed that the worst, the most tiresome,
|
303
|
-
and the most dangerous of errors hitherto has been a dogmatist
|
304
|
-
error--namely, Plato's invention of Pure Spirit and the Good in Itself.
|
305
|
-
But now when it has been surmounted, when Europe, rid of this nightmare,
|
306
|
-
can again draw breath freely and at least enjoy a healthier--sleep,
|
307
|
-
we, WHOSE DUTY IS WAKEFULNESS ITSELF, are the heirs of all the strength
|
308
|
-
which the struggle against this error has fostered. It amounted to
|
309
|
-
the very inversion of truth, and the denial of the PERSPECTIVE--the
|
310
|
-
fundamental condition--of life, to speak of Spirit and the Good as Plato
|
311
|
-
spoke of them; indeed one might ask, as a physician: "How did such a
|
312
|
-
malady attack that finest product of antiquity, Plato? Had the wicked
|
313
|
-
Socrates really corrupted him? Was Socrates after all a corrupter of
|
314
|
-
youths, and deserved his hemlock?" But the struggle against Plato,
|
315
|
-
or--to speak plainer, and for the "people"--the struggle against
|
316
|
-
the ecclesiastical oppression of millenniums of Christianity (FOR
|
317
|
-
CHRISTIANITY IS PLATONISM FOR THE "PEOPLE"), produced in Europe
|
318
|
-
a magnificent tension of soul, such as had not existed anywhere
|
319
|
-
previously; with such a tensely strained bow one can now aim at the
|
320
|
-
furthest goals. As a matter of fact, the European feels this tension as
|
321
|
-
a state of distress, and twice attempts have been made in grand style to
|
322
|
-
unbend the bow: once by means of Jesuitism, and the second time by means
|
323
|
-
of democratic enlightenment--which, with the aid of liberty of the press
|
324
|
-
and newspaper-reading, might, in fact, bring it about that the spirit
|
325
|
-
would not so easily find itself in "distress"! (The Germans invented
|
326
|
-
gunpowder--all credit to them! but they again made things square--they
|
327
|
-
invented printing.) But we, who are neither Jesuits, nor democrats,
|
328
|
-
nor even sufficiently Germans, we GOOD EUROPEANS, and free, VERY free
|
329
|
-
spirits--we have it still, all the distress of spirit and all the
|
330
|
-
tension of its bow! And perhaps also the arrow, the duty, and, who
|
331
|
-
knows? THE GOAL TO AIM AT....
|
332
|
-
|
333
|
-
Sils Maria Upper Engadine, JUNE, 1885.
|
334
|
-
|
335
|
-
- :title: Ulysses
|
336
|
-
:authors:
|
337
|
-
- :last_name: Joyce
|
338
|
-
:first_name: James
|
339
|
-
:downloads: 14679
|
340
|
-
:category: Fiction
|
341
|
-
:content: |
|
342
|
-
Stately, plump Buck Mulligan came from the stairhead, bearing a bowl of
|
343
|
-
lather on which a mirror and a razor lay crossed. A yellow dressinggown,
|
344
|
-
ungirdled, was sustained gently behind him on the mild morning air. He
|
345
|
-
held the bowl aloft and intoned:
|
346
|
-
|
347
|
-
--_Introibo ad altare Dei_.
|
348
|
-
|
349
|
-
Halted, he peered down the dark winding stairs and called out coarsely:
|
350
|
-
|
351
|
-
--Come up, Kinch! Come up, you fearful jesuit!
|
352
|
-
|
353
|
-
Solemnly he came forward and mounted the round gunrest. He faced about
|
354
|
-
and blessed gravely thrice the tower, the surrounding land and the
|
355
|
-
awaking mountains. Then, catching sight of Stephen Dedalus, he bent
|
356
|
-
towards him and made rapid crosses in the air, gurgling in his throat
|
357
|
-
and shaking his head. Stephen Dedalus, displeased and sleepy, leaned
|
358
|
-
his arms on the top of the staircase and looked coldly at the shaking
|
359
|
-
gurgling face that blessed him, equine in its length, and at the light
|
360
|
-
untonsured hair, grained and hued like pale oak.
|
361
|
-
|
362
|
-
Buck Mulligan peeped an instant under the mirror and then covered the
|
363
|
-
bowl smartly.
|
364
|
-
|
365
|
-
--Back to barracks! he said sternly.
|
366
|
-
|
367
|
-
He added in a preacher's tone:
|
368
|
-
|
369
|
-
--For this, O dearly beloved, is the genuine Christine: body and soul
|
370
|
-
and blood and ouns. Slow music, please. Shut your eyes, gents. One
|
371
|
-
moment. A little trouble about those white corpuscles. Silence, all.
|
372
|
-
|
373
|
-
He peered sideways up and gave a long slow whistle of call, then paused
|
374
|
-
awhile in rapt attention, his even white teeth glistening here and there
|
375
|
-
with gold points. Chrysostomos. Two strong shrill whistles answered
|
376
|
-
through the calm.
|
377
|
-
|
378
|
-
--Thanks, old chap, he cried briskly. That will do nicely. Switch off
|
379
|
-
the current, will you?
|
380
|
-
|
381
|
-
He skipped off the gunrest and looked gravely at his watcher, gathering
|
382
|
-
about his legs the loose folds of his gown. The plump shadowed face and
|
383
|
-
sullen oval jowl recalled a prelate, patron of arts in the middle ages.
|
384
|
-
A pleasant smile broke quietly over his lips.
|
385
|
-
|
386
|
-
--The mockery of it! he said gaily. Your absurd name, an ancient Greek!
|
387
|
-
|
388
|
-
He pointed his finger in friendly jest and went over to the parapet,
|
389
|
-
laughing to himself. Stephen Dedalus stepped up, followed him wearily
|
390
|
-
halfway and sat down on the edge of the gunrest, watching him still as
|
391
|
-
he propped his mirror on the parapet, dipped the brush in the bowl and
|
392
|
-
lathered cheeks and neck.
|
393
|
-
|
394
|
-
Buck Mulligan's gay voice went on.
|
395
|
-
|
396
|
-
--My name is absurd too: Malachi Mulligan, two dactyls. But it has a
|
397
|
-
Hellenic ring, hasn't it? Tripping and sunny like the buck himself.
|
398
|
-
We must go to Athens. Will you come if I can get the aunt to fork out
|
399
|
-
twenty quid?
|
400
|
-
|
401
|
-
He laid the brush aside and, laughing with delight, cried:
|
402
|
-
|
403
|
-
--Will he come? The jejune jesuit!
|
404
|
-
|
405
|
-
Ceasing, he began to shave with care.
|
406
|
-
|
407
|
-
--Tell me, Mulligan, Stephen said quietly.
|
408
|
-
|
409
|
-
--Yes, my love?
|
410
|
-
|
411
|
-
--How long is Haines going to stay in this tower?
|
412
|
-
|
413
|
-
Buck Mulligan showed a shaven cheek over his right shoulder.
|
414
|
-
|
415
|
-
- :title: Metamorphosis
|
416
|
-
:authors:
|
417
|
-
- :last_name: Kafka
|
418
|
-
:first_name: Franz
|
419
|
-
:downloads: 22697
|
420
|
-
:category: Fiction
|
421
|
-
:content: |
|
422
|
-
One morning, when Gregor Samsa woke from troubled dreams, he found
|
423
|
-
himself transformed in his bed into a horrible vermin. He lay on
|
424
|
-
his armour-like back, and if he lifted his head a little he could
|
425
|
-
see his brown belly, slightly domed and divided by arches into stiff
|
426
|
-
sections. The bedding was hardly able to cover it and seemed ready
|
427
|
-
to slide off any moment. His many legs, pitifully thin compared
|
428
|
-
with the size of the rest of him, waved about helplessly as he
|
429
|
-
looked.
|
430
|
-
|
431
|
-
"What's happened to me?" he thought. It wasn't a dream. His room,
|
432
|
-
a proper human room although a little too small, lay peacefully
|
433
|
-
between its four familiar walls. A collection of textile samples
|
434
|
-
lay spread out on the table - Samsa was a travelling salesman - and
|
435
|
-
above it there hung a picture that he had recently cut out of an
|
436
|
-
illustrated magazine and housed in a nice, gilded frame. It showed
|
437
|
-
a lady fitted out with a fur hat and fur boa who sat upright,
|
438
|
-
raising a heavy fur muff that covered the whole of her lower arm
|
439
|
-
towards the viewer.
|
440
|
-
|
441
|
-
Gregor then turned to look out the window at the dull weather.
|
442
|
-
Drops of rain could be heard hitting the pane, which made him feel
|
443
|
-
quite sad. "How about if I sleep a little bit longer and forget all
|
444
|
-
this nonsense", he thought, but that was something he was unable to
|
445
|
-
do because he was used to sleeping on his right, and in his present
|
446
|
-
state couldn't get into that position. However hard he threw
|
447
|
-
himself onto his right, he always rolled back to where he was. He
|
448
|
-
must have tried it a hundred times, shut his eyes so that he
|
449
|
-
wouldn't have to look at the floundering legs, and only stopped when
|
450
|
-
he began to feel a mild, dull pain there that he had never felt
|
451
|
-
before.
|
452
|
-
|
453
|
-
"Oh, God", he thought, "what a strenuous career it is that I've
|
454
|
-
chosen! Travelling day in and day out. Doing business like this
|
455
|
-
takes much more effort than doing your own business at home, and on
|
456
|
-
top of that there's the curse of travelling, worries about making
|
457
|
-
train connections, bad and irregular food, contact with different
|
458
|
-
people all the time so that you can never get to know anyone or
|
459
|
-
become friendly with them. It can all go to Hell!" He felt a
|
460
|
-
slight itch up on his belly; pushed himself slowly up on his back
|
461
|
-
towards the headboard so that he could lift his head better; found
|
462
|
-
where the itch was, and saw that it was covered with lots of little
|
463
|
-
white spots which he didn't know what to make of; and when he tried
|
464
|
-
to feel the place with one of his legs he drew it quickly back
|
465
|
-
because as soon as he touched it he was overcome by a cold shudder.
|
466
|
-
|
467
|
-
He slid back into his former position. "Getting up early all the
|
468
|
-
time", he thought, "it makes you stupid. You've got to get enough
|
469
|
-
sleep. Other travelling salesmen live a life of luxury. For
|
470
|
-
instance, whenever I go back to the guest house during the morning
|
471
|
-
to copy out the contract, these gentlemen are always still sitting
|
472
|
-
there eating their breakfasts. I ought to just try that with my
|
473
|
-
boss; I'd get kicked out on the spot. But who knows, maybe that
|
474
|
-
would be the best thing for me. If I didn't have my parents to
|
475
|
-
think about I'd have given in my notice a long time ago, I'd have
|
476
|
-
gone up to the boss and told him just what I think, tell him
|
477
|
-
everything I would, let him know just what I feel. He'd fall right
|
478
|
-
off his desk! And it's a funny sort of business to be sitting up
|
479
|
-
there at your desk, talking down at your subordinates from up there,
|
480
|
-
especially when you have to go right up close because the boss is
|
481
|
-
hard of hearing. Well, there's still some hope; once I've got the
|
482
|
-
money together to pay off my parents' debt to him - another five or
|
483
|
-
six years I suppose - that's definitely what I'll do. That's when
|
484
|
-
I'll make the big change. First of all though, I've got to get up,
|
485
|
-
my train leaves at five."
|
486
|
-
|
487
|
-
- :title: Crime and Punishment
|
488
|
-
:authors:
|
489
|
-
- :last_name: Dostoyevsky
|
490
|
-
:first_name: Fyodor
|
491
|
-
:downloads: 4590
|
492
|
-
:category: Fiction
|
493
|
-
:content: |
|
494
|
-
On an exceptionally hot evening early in July a young man came out of
|
495
|
-
the garret in which he lodged in S. Place and walked slowly, as though
|
496
|
-
in hesitation, towards K. bridge.
|
497
|
-
|
498
|
-
He had successfully avoided meeting his landlady on the staircase. His
|
499
|
-
garret was under the roof of a high, five-storied house and was more
|
500
|
-
like a cupboard than a room. The landlady who provided him with garret,
|
501
|
-
dinners, and attendance, lived on the floor below, and every time
|
502
|
-
he went out he was obliged to pass her kitchen, the door of which
|
503
|
-
invariably stood open. And each time he passed, the young man had a
|
504
|
-
sick, frightened feeling, which made him scowl and feel ashamed. He was
|
505
|
-
hopelessly in debt to his landlady, and was afraid of meeting her.
|
506
|
-
|
507
|
-
This was not because he was cowardly and abject, quite the contrary; but
|
508
|
-
for some time past he had been in an overstrained irritable condition,
|
509
|
-
verging on hypochondria. He had become so completely absorbed in
|
510
|
-
himself, and isolated from his fellows that he dreaded meeting, not
|
511
|
-
only his landlady, but anyone at all. He was crushed by poverty, but the
|
512
|
-
anxieties of his position had of late ceased to weigh upon him. He had
|
513
|
-
given up attending to matters of practical importance; he had lost all
|
514
|
-
desire to do so. Nothing that any landlady could do had a real terror
|
515
|
-
for him. But to be stopped on the stairs, to be forced to listen to her
|
516
|
-
trivial, irrelevant gossip, to pestering demands for payment, threats
|
517
|
-
and complaints, and to rack his brains for excuses, to prevaricate, to
|
518
|
-
lie--no, rather than that, he would creep down the stairs like a cat and
|
519
|
-
slip out unseen.
|
520
|
-
|
521
|
-
This evening, however, on coming out into the street, he became acutely
|
522
|
-
aware of his fears.
|
523
|
-
|
524
|
-
"I want to attempt a thing _like that_ and am frightened by these
|
525
|
-
trifles," he thought, with an odd smile. "Hm... yes, all is in a man's
|
526
|
-
hands and he lets it all slip from cowardice, that's an axiom. It would
|
527
|
-
be interesting to know what it is men are most afraid of. Taking a new
|
528
|
-
step, uttering a new word is what they fear most.... But I am talking
|
529
|
-
too much. It's because I chatter that I do nothing. Or perhaps it is
|
530
|
-
that I chatter because I do nothing. I've learned to chatter this
|
531
|
-
last month, lying for days together in my den thinking... of Jack the
|
532
|
-
Giant-killer. Why am I going there now? Am I capable of _that_? Is
|
533
|
-
_that_ serious? It is not serious at all. It's simply a fantasy to amuse
|
534
|
-
myself; a plaything! Yes, maybe it is a plaything."
|
535
|
-
|
536
|
-
The heat in the street was terrible: and the airlessness, the bustle
|
537
|
-
and the plaster, scaffolding, bricks, and dust all about him, and that
|
538
|
-
special Petersburg stench, so familiar to all who are unable to get out
|
539
|
-
of town in summer--all worked painfully upon the young man's already
|
540
|
-
overwrought nerves. The insufferable stench from the pot-houses, which
|
541
|
-
are particularly numerous in that part of the town, and the drunken men
|
542
|
-
whom he met continually, although it was a working day, completed
|
543
|
-
the revolting misery of the picture. An expression of the profoundest
|
544
|
-
disgust gleamed for a moment in the young man's refined face. He was,
|
545
|
-
by the way, exceptionally handsome, above the average in height, slim,
|
546
|
-
well-built, with beautiful dark eyes and dark brown hair. Soon he sank
|
547
|
-
into deep thought, or more accurately speaking into a complete blankness
|
548
|
-
of mind; he walked along not observing what was about him and not caring
|
549
|
-
to observe it. From time to time, he would mutter something, from the
|
550
|
-
habit of talking to himself, to which he had just confessed. At these
|
551
|
-
moments he would become conscious that his ideas were sometimes in a
|
552
|
-
tangle and that he was very weak; for two days he had scarcely tasted
|
553
|
-
food.
|
554
|
-
|
555
|
-
- :title: The Hound of the Baskervilles
|
556
|
-
:authors:
|
557
|
-
- :last_name: Doyle
|
558
|
-
:first_name: Arthur Conan
|
559
|
-
:downloads: 5021
|
560
|
-
:category: Fiction
|
561
|
-
:content: |
|
562
|
-
Mr. Sherlock Holmes, who was usually very late in the mornings, save
|
563
|
-
upon those not infrequent occasions when he was up all night, was seated
|
564
|
-
at the breakfast table. I stood upon the hearth-rug and picked up the
|
565
|
-
stick which our visitor had left behind him the night before. It was a
|
566
|
-
fine, thick piece of wood, bulbous-headed, of the sort which is known as
|
567
|
-
a "Penang lawyer." Just under the head was a broad silver band nearly
|
568
|
-
an inch across. "To James Mortimer, M.R.C.S., from his friends of the
|
569
|
-
C.C.H.," was engraved upon it, with the date "1884." It was just such a
|
570
|
-
stick as the old-fashioned family practitioner used to carry--dignified,
|
571
|
-
solid, and reassuring.
|
572
|
-
|
573
|
-
"Well, Watson, what do you make of it?"
|
574
|
-
|
575
|
-
Holmes was sitting with his back to me, and I had given him no sign of
|
576
|
-
my occupation.
|
577
|
-
|
578
|
-
"How did you know what I was doing? I believe you have eyes in the back
|
579
|
-
of your head."
|
580
|
-
|
581
|
-
"I have, at least, a well-polished, silver-plated coffee-pot in front of
|
582
|
-
me," said he. "But, tell me, Watson, what do you make of our visitor's
|
583
|
-
stick? Since we have been so unfortunate as to miss him and have no
|
584
|
-
notion of his errand, this accidental souvenir becomes of importance.
|
585
|
-
Let me hear you reconstruct the man by an examination of it."
|
586
|
-
|
587
|
-
"I think," said I, following as far as I could the methods of my
|
588
|
-
companion, "that Dr. Mortimer is a successful, elderly medical man,
|
589
|
-
well-esteemed since those who know him give him this mark of their
|
590
|
-
appreciation."
|
591
|
-
|
592
|
-
"Good!" said Holmes. "Excellent!"
|
593
|
-
|
594
|
-
"I think also that the probability is in favour of his being a country
|
595
|
-
practitioner who does a great deal of his visiting on foot."
|
596
|
-
|
597
|
-
"Why so?"
|
598
|
-
|
599
|
-
"Because this stick, though originally a very handsome one has been so
|
600
|
-
knocked about that I can hardly imagine a town practitioner carrying it.
|
601
|
-
The thick-iron ferrule is worn down, so it is evident that he has done a
|
602
|
-
great amount of walking with it."
|
603
|
-
|
604
|
-
"Perfectly sound!" said Holmes.
|
605
|
-
|
606
|
-
"And then again, there is the 'friends of the C.C.H.' I should guess
|
607
|
-
that to be the Something Hunt, the local hunt to whose members he has
|
608
|
-
possibly given some surgical assistance, and which has made him a small
|
609
|
-
presentation in return."
|
610
|
-
|
611
|
-
"Really, Watson, you excel yourself," said Holmes, pushing back his
|
612
|
-
chair and lighting a cigarette. "I am bound to say that in all the
|
613
|
-
accounts which you have been so good as to give of my own small
|
614
|
-
achievements you have habitually underrated your own abilities. It may
|
615
|
-
be that you are not yourself luminous, but you are a conductor of
|
616
|
-
light. Some people without possessing genius have a remarkable power of
|
617
|
-
stimulating it. I confess, my dear fellow, that I am very much in your
|
618
|
-
debt."
|
619
|
-
|
620
|
-
He had never said as much before, and I must admit that his words gave
|
621
|
-
me keen pleasure, for I had often been piqued by his indifference to my
|
622
|
-
admiration and to the attempts which I had made to give publicity to
|
623
|
-
his methods. I was proud, too, to think that I had so far mastered his
|
624
|
-
system as to apply it in a way which earned his approval. He now took
|
625
|
-
the stick from my hands and examined it for a few minutes with his naked
|
626
|
-
eyes. Then with an expression of interest he laid down his cigarette,
|
627
|
-
and carrying the cane to the window, he looked over it again with a
|
628
|
-
convex lens.
|
629
|
-
|
630
|
-
"Interesting, though elementary," said he as he returned to his
|
631
|
-
favourite corner of the settee. "There are certainly one or two
|
632
|
-
indications upon the stick. It gives us the basis for several
|
633
|
-
deductions."
|
634
|
-
|
635
|
-
- :title: Madame Bovary
|
636
|
-
:authors:
|
637
|
-
- :last_name: Flaubert
|
638
|
-
:first_name: Gustave
|
639
|
-
:downloads: 4090
|
640
|
-
:category: Fiction
|
641
|
-
:content: |
|
642
|
-
We were in class when the head-master came in, followed by a "new
|
643
|
-
fellow," not wearing the school uniform, and a school servant carrying a
|
644
|
-
large desk. Those who had been asleep woke up, and every one rose as if
|
645
|
-
just surprised at his work.
|
646
|
-
|
647
|
-
The head-master made a sign to us to sit down. Then, turning to the
|
648
|
-
class-master, he said to him in a low voice--
|
649
|
-
|
650
|
-
"Monsieur Roger, here is a pupil whom I recommend to your care; he'll be
|
651
|
-
in the second. If his work and conduct are satisfactory, he will go into
|
652
|
-
one of the upper classes, as becomes his age."
|
653
|
-
|
654
|
-
The "new fellow," standing in the corner behind the door so that he
|
655
|
-
could hardly be seen, was a country lad of about fifteen, and taller
|
656
|
-
than any of us. His hair was cut square on his forehead like a village
|
657
|
-
chorister's; he looked reliable, but very ill at ease. Although he was
|
658
|
-
not broad-shouldered, his short school jacket of green cloth with black
|
659
|
-
buttons must have been tight about the arm-holes, and showed at the
|
660
|
-
opening of the cuffs red wrists accustomed to being bare. His legs, in
|
661
|
-
blue stockings, looked out from beneath yellow trousers, drawn tight by
|
662
|
-
braces, He wore stout, ill-cleaned, hob-nailed boots.
|
663
|
-
|
664
|
-
We began repeating the lesson. He listened with all his ears, as
|
665
|
-
attentive as if at a sermon, not daring even to cross his legs or lean
|
666
|
-
on his elbow; and when at two o'clock the bell rang, the master was
|
667
|
-
obliged to tell him to fall into line with the rest of us.
|
668
|
-
|
669
|
-
When we came back to work, we were in the habit of throwing our caps on
|
670
|
-
the ground so as to have our hands more free; we used from the door to
|
671
|
-
toss them under the form, so that they hit against the wall and made a
|
672
|
-
lot of dust: it was "the thing."
|
673
|
-
|
674
|
-
But, whether he had not noticed the trick, or did not dare to attempt
|
675
|
-
it, the "new fellow," was still holding his cap on his knees even after
|
676
|
-
prayers were over. It was one of those head-gears of composite order, in
|
677
|
-
which we can find traces of the bearskin, shako, billycock hat, sealskin
|
678
|
-
cap, and cotton night-cap; one of those poor things, in fine, whose
|
679
|
-
dumb ugliness has depths of expression, like an imbecile's face. Oval,
|
680
|
-
stiffened with whalebone, it began with three round knobs; then came in
|
681
|
-
succession lozenges of velvet and rabbit-skin separated by a red band;
|
682
|
-
after that a sort of bag that ended in a cardboard polygon covered with
|
683
|
-
complicated braiding, from which hung, at the end of a long thin cord,
|
684
|
-
small twisted gold threads in the manner of a tassel. The cap was new;
|
685
|
-
its peak shone.
|
686
|
-
|
687
|
-
"Rise," said the master.
|
688
|
-
|
689
|
-
He stood up; his cap fell. The whole class began to laugh. He stooped to
|
690
|
-
pick it up. A neighbor knocked it down again with his elbow; he picked
|
691
|
-
it up once more.
|
692
|
-
|
693
|
-
- :title: Tractatus Logico-Philosophicus
|
694
|
-
:authors:
|
695
|
-
- :last_name: Wittgenstein
|
696
|
-
:first_name: Ludwig
|
697
|
-
:downloads: 4036
|
698
|
-
:category: Philosophy
|
699
|
-
:content: |
|
700
|
-
1 The world is everything that is the case.∗
|
701
|
-
1.1 The world is the totality of facts, not of things.
|
702
|
-
1.11 The world is determined by the facts, and by these being all the facts.
|
703
|
-
1.12 For the totality of facts determines both what is the case, and also all that is not the case.
|
704
|
-
1.13 The facts in logical space are the world.
|
705
|
-
1.2 The world divides into facts.
|
706
|
-
1.21 Any one can either be the case or not be the case, and everything else remain the same.
|
707
|
-
- :title: A General Introduction to Psychoanalysis
|
708
|
-
:authors:
|
709
|
-
- :last_name: Freud
|
710
|
-
:first_name: Sigmund
|
711
|
-
:downloads: 1355
|
712
|
-
:category: Psychology
|
713
|
-
:content: |
|
714
|
-
I do not know how familiar some of you may be, either from your reading
|
715
|
-
or from hearsay, with psychoanalysis. But, in keeping with the title of
|
716
|
-
these lectures--_A General Introduction to Psychoanalysis_--I am obliged
|
717
|
-
to proceed as though you knew nothing about this subject, and stood in
|
718
|
-
need of preliminary instruction.
|
719
|
-
|
720
|
-
To be sure, this much I may presume that you do know, namely, that
|
721
|
-
psychoanalysis is a method of treating nervous patients medically. And
|
722
|
-
just at this point I can give you an example to illustrate how the
|
723
|
-
procedure in this field is precisely the reverse of that which is the
|
724
|
-
rule in medicine. Usually when we introduce a patient to a medical
|
725
|
-
technique which is strange to him we minimize its difficulties and give
|
726
|
-
him confident promises concerning the result of the treatment. When,
|
727
|
-
however, we undertake psychoanalytic treatment with a neurotic patient
|
728
|
-
we proceed differently. We hold before him the difficulties of the
|
729
|
-
method, its length, the exertions and the sacrifices which it will cost
|
730
|
-
him; and, as to the result, we tell him that we make no definite
|
731
|
-
promises, that the result depends on his conduct, on his understanding,
|
732
|
-
on his adaptability, on his perseverance. We have, of course, excellent
|
733
|
-
motives for conduct which seems so perverse, and into which you will
|
734
|
-
perhaps gain insight at a later point in these lectures.
|
735
|
-
|
736
|
-
Do not be offended, therefore, if, for the present, I treat you as I
|
737
|
-
treat these neurotic patients. Frankly, I shall dissuade you from coming
|
738
|
-
to hear me a second time. With this intention I shall show what
|
739
|
-
imperfections are necessarily involved in the teaching of psychoanalysis
|
740
|
-
and what difficulties stand in the way of gaining a personal judgment. I
|
741
|
-
shall show you how the whole trend of your previous training and all
|
742
|
-
your accustomed mental habits must unavoidably have made you opponents
|
743
|
-
of psychoanalysis, and how much you must overcome in yourselves in
|
744
|
-
order to master this instinctive opposition. Of course I cannot predict
|
745
|
-
how much psychoanalytic understanding you will gain from my lectures,
|
746
|
-
but I can promise this, that by listening to them you will not learn how
|
747
|
-
to undertake a psychoanalytic treatment or how to carry one to
|
748
|
-
completion. Furthermore, should I find anyone among you who does not
|
749
|
-
feel satisfied with a cursory acquaintance with psychoanalysis, but who
|
750
|
-
would like to enter into a more enduring relationship with it, I shall
|
751
|
-
not only dissuade him, but I shall actually warn him against it. As
|
752
|
-
things now stand, a person would, by such a choice of profession, ruin
|
753
|
-
his every chance of success at a university, and if he goes out into the
|
754
|
-
world as a practicing physician, he will find himself in a society which
|
755
|
-
does not understand his aims, which regards him with suspicion and
|
756
|
-
hostility, and which turns loose upon him all the malicious spirits
|
757
|
-
which lurk within it.
|
758
|
-
- :title: Grimms' Fairy Tales
|
759
|
-
:authors:
|
760
|
-
- :last_name: Grimm
|
761
|
-
:first_name: Jacob
|
762
|
-
- :last_name: Grimm
|
763
|
-
:first_name: Wilhelm
|
764
|
-
:downloads: 25050
|
765
|
-
:content: |
|
766
|
-
A certain king had a beautiful garden, and in the garden stood a tree
|
767
|
-
which bore golden apples. These apples were always counted, and about
|
768
|
-
the time when they began to grow ripe it was found that every night one
|
769
|
-
of them was gone. The king became very angry at this, and ordered the
|
770
|
-
gardener to keep watch all night under the tree. The gardener set his
|
771
|
-
eldest son to watch; but about twelve o'clock he fell asleep, and in
|
772
|
-
the morning another of the apples was missing. Then the second son was
|
773
|
-
ordered to watch; and at midnight he too fell asleep, and in the morning
|
774
|
-
another apple was gone. Then the third son offered to keep watch; but
|
775
|
-
the gardener at first would not let him, for fear some harm should come
|
776
|
-
to him: however, at last he consented, and the young man laid himself
|
777
|
-
under the tree to watch. As the clock struck twelve he heard a rustling
|
778
|
-
noise in the air, and a bird came flying that was of pure gold; and as
|
779
|
-
it was snapping at one of the apples with its beak, the gardener's son
|
780
|
-
jumped up and shot an arrow at it. But the arrow did the bird no harm;
|
781
|
-
only it dropped a golden feather from its tail, and then flew away.
|
782
|
-
The golden feather was brought to the king in the morning, and all the
|
783
|
-
council was called together. Everyone agreed that it was worth more than
|
784
|
-
all the wealth of the kingdom: but the king said, 'One feather is of no
|
785
|
-
use to me, I must have the whole bird.'
|
786
|
-
|
787
|
-
- :title: An English Grammar
|
788
|
-
:authors:
|
789
|
-
- :last_name: Baskervill
|
790
|
-
:first_name: William Malone
|
791
|
-
- :last_name: Sewell
|
792
|
-
:first_name: James Witt
|
793
|
-
:downloads: 1211
|
794
|
-
:category: Linguistics
|
795
|
-
:content: |
|
796
|
-
Of making many English grammars there is no end; nor should there be
|
797
|
-
till theoretical scholarship and actual practice are more happily
|
798
|
-
wedded. In this field much valuable work has already been
|
799
|
-
accomplished; but it has been done largely by workers accustomed to
|
800
|
-
take the scholar's point of view, and their writings are addressed
|
801
|
-
rather to trained minds than to immature learners. To find an advanced
|
802
|
-
grammar unencumbered with hard words, abstruse thoughts, and difficult
|
803
|
-
principles, is not altogether an easy matter. These things enhance the
|
804
|
-
difficulty which an ordinary youth experiences in grasping and
|
805
|
-
assimilating the facts of grammar, and create a distaste for the
|
806
|
-
study. It is therefore the leading object of this book to be both as
|
807
|
-
scholarly and as practical as possible. In it there is an attempt to
|
808
|
-
present grammatical facts as simply, and to lead the student to
|
809
|
-
assimilate them as thoroughly, as possible, and at the same time to do
|
810
|
-
away with confusing difficulties as far as may be.
|
811
|
-
DATA
|
812
|
-
|
813
|
-
[Book, Author, Authorship, Category].each { |model| model.delete_all }
|
814
|
-
|
815
|
-
books.to_ruby.each do |b|
|
816
|
-
book = Book.create \
|
817
|
-
title: b[:title],
|
818
|
-
downloads: b[:downloads],
|
819
|
-
content: b[:content]
|
820
|
-
|
821
|
-
b[:authors].each do |a|
|
822
|
-
author = Author.where(first_name: a[:first_name], last_name: a[:last_name]).first_or_create
|
823
|
-
book.authors << author
|
824
|
-
end
|
134
|
+
puts
|
135
|
+
say_status "Model", "Adding the `abstract` column to Article...\n", :yellow
|
136
|
+
puts '-'*80, ''
|
137
|
+
|
138
|
+
generate :migration, "AddColumnsToArticle abstract:text url:string shares:integer"
|
139
|
+
rake "db:migrate"
|
825
140
|
|
826
|
-
|
827
|
-
|
141
|
+
git add: "db/"
|
142
|
+
git commit: "-m 'Added additional columns to Article'"
|
143
|
+
|
144
|
+
# ----- Move the model integration into a concern -------------------------------------------------
|
828
145
|
|
829
|
-
|
146
|
+
puts
|
147
|
+
say_status "Model", "Refactoring the model integration...\n", :yellow
|
148
|
+
puts '-'*80, ''; sleep 0.25
|
149
|
+
|
150
|
+
remove_file 'app/models/article.rb'
|
151
|
+
create_file 'app/models/article.rb', <<-CODE
|
152
|
+
class Article < ActiveRecord::Base
|
153
|
+
include Searchable
|
830
154
|
end
|
831
155
|
CODE
|
832
156
|
|
833
|
-
|
834
|
-
|
157
|
+
# copy_file File.expand_path('../searchable.rb', __FILE__), 'app/models/concerns/searchable.rb'
|
158
|
+
get 'https://raw.github.com/elasticsearch/elasticsearch-rails/templates/elasticsearch-rails/lib/rails/templates/searchable.rb',
|
159
|
+
'app/models/concerns/searchable.rb'
|
835
160
|
|
836
|
-
|
837
|
-
|
838
|
-
# * Update views (show authors, category name, bootstrap)
|
839
|
-
# <table class="table table-hover">
|
840
|
-
# class: 'btn btn-default btn-xs'
|
841
|
-
# class: 'btn btn-primary btn-xs', style: 'color: #fff'
|
842
|
-
# <td><%= book.authors.map(&:full_name).to_sentence %></td>
|
843
|
-
# <td><%= book.category.try(:title) || 'n/a' %></td>
|
844
|
-
# Update controller (fight n+1)
|
845
|
-
# @books = Book.includes(:authors, :category)
|
846
|
-
#
|
161
|
+
insert_into_file "app/models/article.rb", after: "ActiveRecord::Base" do
|
162
|
+
<<-CODE
|
847
163
|
|
848
|
-
|
164
|
+
has_and_belongs_to_many :categories, after_add: [ lambda { |a,c| Indexer.perform_async(:update, a.class.to_s, a.id) } ],
|
165
|
+
after_remove: [ lambda { |a,c| Indexer.perform_async(:update, a.class.to_s, a.id) } ]
|
166
|
+
has_many :authorships
|
167
|
+
has_many :authors, through: :authorships
|
168
|
+
has_many :comments
|
849
169
|
|
850
|
-
|
851
|
-
|
170
|
+
CODE
|
171
|
+
end
|
172
|
+
|
173
|
+
git add: "app/models/"
|
174
|
+
git commit: "-m 'Refactored the Elasticsearch integration into a concern\n\nSee:\n\n* http://37signals.com/svn/posts/3372-put-chubby-models-on-a-diet-with-concerns\n* http://joshsymonds.com/blog/2012/10/25/rails-concerns-v-searchable-with-elasticsearch/'"
|
175
|
+
|
176
|
+
# ----- Add Sidekiq indexer -----------------------------------------------------------------------
|
177
|
+
|
178
|
+
puts
|
179
|
+
say_status "Application", "Adding Sidekiq worker for updating the index...\n", :yellow
|
180
|
+
puts '-'*80, ''; sleep 0.25
|
181
|
+
|
182
|
+
gem "sidekiq"
|
183
|
+
|
184
|
+
run "bundle install"
|
185
|
+
|
186
|
+
# copy_file File.expand_path('../indexer.rb', __FILE__), 'app/workers/indexer.rb'
|
187
|
+
get 'https://raw.github.com/elasticsearch/elasticsearch-rails/templates/elasticsearch-rails/lib/rails/templates/indexer.rb',
|
188
|
+
'app/workers/indexer.rb'
|
189
|
+
|
190
|
+
git add: "Gemfile* app/workers/"
|
191
|
+
git commit: "-m 'Added a Sidekiq indexer\n\nRun:\n\n $ bundle exec sidekiq --queue elasticsearch --verbose\n\nSee http://sidekiq.org'"
|
192
|
+
|
193
|
+
# ----- Add SearchController -----------------------------------------------------------------------
|
194
|
+
|
195
|
+
puts
|
196
|
+
say_status "Controllers", "Adding SearchController...\n", :yellow
|
197
|
+
puts '-'*80, ''; sleep 0.25
|
198
|
+
|
199
|
+
create_file 'app/controllers/search_controller.rb' do
|
200
|
+
<<-CODE.gsub(/^ /, '')
|
201
|
+
class SearchController < ApplicationController
|
202
|
+
respond_to :json, :html
|
203
|
+
|
204
|
+
def index
|
205
|
+
options = {
|
206
|
+
category: params[:c],
|
207
|
+
author: params[:a],
|
208
|
+
published_week: params[:w],
|
209
|
+
published_day: params[:d],
|
210
|
+
sort: params[:s],
|
211
|
+
comments: params[:comments]
|
212
|
+
}
|
213
|
+
@articles = Article.search(params[:q], options).page(params[:page]).results
|
214
|
+
|
215
|
+
respond_with @articles
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
852
219
|
|
853
|
-
include Searchable
|
854
220
|
CODE
|
855
221
|
end
|
856
222
|
|
857
|
-
|
858
|
-
|
223
|
+
route "get '/search', to: 'search#index', as: 'search'"
|
224
|
+
gsub_file 'config/routes.rb', %r{root to: 'articles#index'$}, "root to: 'search#index'"
|
859
225
|
|
860
|
-
#
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
#
|
226
|
+
# copy_file File.expand_path('../index.html.erb', __FILE__), 'app/views/search/index.html.erb'
|
227
|
+
get 'https://raw.github.com/elasticsearch/elasticsearch-rails/templates/elasticsearch-rails/lib/rails/templates/index.html.erb',
|
228
|
+
'app/views/search/index.html.erb'
|
229
|
+
|
230
|
+
# copy_file File.expand_path('../search.css', __FILE__), 'app/assets/stylesheets/search.css'
|
231
|
+
get 'https://raw.github.com/elasticsearch/elasticsearch-rails/templates/elasticsearch-rails/lib/rails/templates/search.css',
|
232
|
+
'app/assets/stylesheets/search.css'
|
233
|
+
|
234
|
+
git add: "app/controllers/ config/routes.rb"
|
235
|
+
git add: "app/views/search/ app/assets/stylesheets/search.css"
|
236
|
+
git commit: "-m 'Added SearchController#index'"
|
237
|
+
|
238
|
+
# ----- Add initializer ---------------------------------------------------------------------------
|
239
|
+
|
240
|
+
puts
|
241
|
+
say_status "Application", "Adding Elasticsearch configuration in an initializer...\n", :yellow
|
242
|
+
puts '-'*80, ''; sleep 0.5
|
243
|
+
|
244
|
+
create_file 'config/initializers/elasticsearch.rb', <<-CODE
|
245
|
+
# Connect to specific Elasticsearch cluster
|
246
|
+
ELASTICSEARCH_URL = ENV['ELASTICSEARCH_URL'] || 'http://localhost:9200'
|
247
|
+
|
248
|
+
Elasticsearch::Model.client = Elasticsearch::Client.new host: ELASTICSEARCH_URL
|
249
|
+
|
250
|
+
# Print Curl-formatted traces in development into a file
|
865
251
|
#
|
252
|
+
if Rails.env.development?
|
253
|
+
tracer = ActiveSupport::Logger.new('log/elasticsearch.log')
|
254
|
+
tracer.level = Logger::DEBUG
|
255
|
+
end
|
866
256
|
|
867
|
-
|
257
|
+
Elasticsearch::Model.client.transport.tracer = tracer
|
258
|
+
CODE
|
259
|
+
|
260
|
+
git add: "config/initializers"
|
261
|
+
git commit: "-m 'Added Rails initializer with Elasticsearch configuration'"
|
262
|
+
|
263
|
+
# ----- Add Rake tasks ----------------------------------------------------------------------------
|
868
264
|
|
869
265
|
puts
|
870
|
-
say_status "
|
871
|
-
puts '-'*80, ''; sleep 0.
|
266
|
+
say_status "Application", "Adding Elasticsearch Rake tasks...\n", :yellow
|
267
|
+
puts '-'*80, ''; sleep 0.5
|
268
|
+
|
269
|
+
create_file 'lib/tasks/elasticsearch.rake', <<-CODE
|
270
|
+
require 'elasticsearch/rails/tasks/import'
|
271
|
+
CODE
|
872
272
|
|
873
|
-
|
273
|
+
git add: "lib/tasks"
|
274
|
+
git commit: "-m 'Added Rake tasks for Elasticsearch'"
|
874
275
|
|
875
|
-
# -----
|
276
|
+
# ----- Insert and index data ---------------------------------------------------------------------
|
876
277
|
|
877
278
|
puts
|
878
|
-
say_status "
|
279
|
+
say_status "Database", "Re-creating the database with data and importing into Elasticsearch...", :yellow
|
879
280
|
puts '-'*80, ''; sleep 0.25
|
880
281
|
|
881
|
-
#
|
882
|
-
|
282
|
+
# copy_file File.expand_path('../articles.yml.gz', __FILE__), 'db/articles.yml.gz'
|
283
|
+
get 'https://raw.github.com/elasticsearch/elasticsearch-rails/templates/elasticsearch-rails/lib/rails/templates/articles.yml.gz',
|
284
|
+
'db/articles.yml.gz'
|
285
|
+
|
286
|
+
remove_file 'db/seeds.rb'
|
287
|
+
# copy_file File.expand_path('../seeds.rb', __FILE__), 'db/seeds.rb'
|
288
|
+
get 'https://raw.github.com/elasticsearch/elasticsearch-rails/templates/elasticsearch-rails/lib/rails/templates/seeds.rb',
|
289
|
+
'db/seeds.rb'
|
290
|
+
|
291
|
+
rake "db:reset"
|
292
|
+
rake "environment elasticsearch:import:model CLASS='Article' BATCH=100 FORCE=y"
|
293
|
+
|
294
|
+
git add: "db/seeds.rb db/articles.yml.gz"
|
295
|
+
git commit: "-m 'Added a seed script and source data'"
|
883
296
|
|
884
297
|
# ----- Print Git log -----------------------------------------------------------------------------
|
885
298
|
|
@@ -887,24 +300,26 @@ puts
|
|
887
300
|
say_status "Git", "Details about the application:", :yellow
|
888
301
|
puts '-'*80, ''
|
889
302
|
|
890
|
-
git :
|
891
|
-
git :
|
303
|
+
git tag: "expert"
|
304
|
+
git log: "--reverse --oneline HEAD...pretty"
|
892
305
|
|
893
306
|
# ----- Start the application ---------------------------------------------------------------------
|
894
307
|
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
308
|
+
unless ENV['RAILS_NO_SERVER_START']
|
309
|
+
require 'net/http'
|
310
|
+
if (begin; Net::HTTP.get(URI('http://localhost:3000')); rescue Errno::ECONNREFUSED; false; rescue Exception; true; end)
|
311
|
+
puts "\n"
|
312
|
+
say_status "ERROR", "Some other application is running on port 3000!\n", :red
|
313
|
+
puts '-'*80
|
900
314
|
|
901
|
-
|
902
|
-
else
|
903
|
-
|
904
|
-
end
|
315
|
+
port = ask("Please provide free port:", :bold)
|
316
|
+
else
|
317
|
+
port = '3000'
|
318
|
+
end
|
905
319
|
|
906
|
-
puts "", "="*80
|
907
|
-
say_status "DONE", "\e[1mStarting the application. Open http://localhost:#{port}\e[0m", :yellow
|
908
|
-
puts "="*80, ""
|
320
|
+
puts "", "="*80
|
321
|
+
say_status "DONE", "\e[1mStarting the application. Open http://localhost:#{port}\e[0m", :yellow
|
322
|
+
puts "="*80, ""
|
909
323
|
|
910
|
-
run "rails server --port=#{port}"
|
324
|
+
run "rails server --port=#{port}"
|
325
|
+
end
|