bento_search 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +299 -0
  3. data/Rakefile +40 -0
  4. data/app/assets/images/bento_search/large_loader.gif +0 -0
  5. data/app/assets/javascripts/bento_search.js +3 -0
  6. data/app/assets/javascripts/bento_search/ajax_load.js +22 -0
  7. data/app/assets/stylesheets/bento_search/bento.css +4 -0
  8. data/app/controllers/bento_search/bento_search_controller.rb +7 -0
  9. data/app/controllers/bento_search/search_controller.rb +72 -0
  10. data/app/helpers/bento_search_helper.rb +138 -0
  11. data/app/item_decorators/bento_search/only_premade_openurl.rb +16 -0
  12. data/app/item_decorators/bento_search/openurl_add_other_link.rb +35 -0
  13. data/app/item_decorators/bento_search/openurl_main_link.rb +30 -0
  14. data/app/models/bento_search/author.rb +25 -0
  15. data/app/models/bento_search/link.rb +30 -0
  16. data/app/models/bento_search/multi_searcher.rb +109 -0
  17. data/app/models/bento_search/openurl_creator.rb +128 -0
  18. data/app/models/bento_search/registrar.rb +70 -0
  19. data/app/models/bento_search/result_item.rb +203 -0
  20. data/app/models/bento_search/results.rb +54 -0
  21. data/app/models/bento_search/results/pagination.rb +67 -0
  22. data/app/models/bento_search/search_engine.rb +219 -0
  23. data/app/models/bento_search/search_engine/capabilities.rb +65 -0
  24. data/app/search_engines/bento_search/#Untitled-1# +11 -0
  25. data/app/search_engines/bento_search/ebsco_host_engine.rb +356 -0
  26. data/app/search_engines/bento_search/eds_engine.rb +557 -0
  27. data/app/search_engines/bento_search/google_books_engine.rb +184 -0
  28. data/app/search_engines/bento_search/primo_engine.rb +231 -0
  29. data/app/search_engines/bento_search/scopus_engine.rb +295 -0
  30. data/app/search_engines/bento_search/summon_engine.rb +398 -0
  31. data/app/search_engines/bento_search/xerxes_engine.rb +168 -0
  32. data/app/views/bento_search/_link.html.erb +4 -0
  33. data/app/views/bento_search/_search_error.html.erb +22 -0
  34. data/app/views/bento_search/_std_item.html.erb +39 -0
  35. data/app/views/bento_search/search/search.html.erb +1 -0
  36. data/config/locales/en.yml +25 -0
  37. data/lib/bento_search.rb +29 -0
  38. data/lib/bento_search/engine.rb +5 -0
  39. data/lib/bento_search/routes.rb +45 -0
  40. data/lib/bento_search/version.rb +3 -0
  41. data/lib/generators/bento_search/pull_ebsco_dbs_generator.rb +24 -0
  42. data/lib/generators/bento_search/templates/ebsco_global_var.erb +6 -0
  43. data/lib/http_client_patch/include_client.rb +86 -0
  44. data/lib/tasks/bento_search_tasks.rake +4 -0
  45. data/test/dummy/README.rdoc +261 -0
  46. data/test/dummy/Rakefile +7 -0
  47. data/test/dummy/app/assets/javascripts/application.js +15 -0
  48. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  49. data/test/dummy/app/controllers/application_controller.rb +3 -0
  50. data/test/dummy/app/helpers/application_helper.rb +2 -0
  51. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  52. data/test/dummy/config.ru +4 -0
  53. data/test/dummy/config/application.rb +56 -0
  54. data/test/dummy/config/boot.rb +10 -0
  55. data/test/dummy/config/database.yml +25 -0
  56. data/test/dummy/config/environment.rb +5 -0
  57. data/test/dummy/config/environments/development.rb +37 -0
  58. data/test/dummy/config/environments/production.rb +67 -0
  59. data/test/dummy/config/environments/test.rb +37 -0
  60. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  61. data/test/dummy/config/initializers/inflections.rb +15 -0
  62. data/test/dummy/config/initializers/mime_types.rb +5 -0
  63. data/test/dummy/config/initializers/secret_token.rb +7 -0
  64. data/test/dummy/config/initializers/session_store.rb +8 -0
  65. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  66. data/test/dummy/config/locales/en.yml +5 -0
  67. data/test/dummy/config/routes.rb +6 -0
  68. data/test/dummy/db/test.sqlite3 +0 -0
  69. data/test/dummy/log/test.log +3100 -0
  70. data/test/dummy/public/404.html +26 -0
  71. data/test/dummy/public/422.html +26 -0
  72. data/test/dummy/public/500.html +25 -0
  73. data/test/dummy/public/favicon.ico +0 -0
  74. data/test/dummy/script/rails +6 -0
  75. data/test/functional/bento_search/search_controller_test.rb +81 -0
  76. data/test/helper/bento_search_helper_test.rb +125 -0
  77. data/test/integration/navigation_test.rb +10 -0
  78. data/test/support/mock_engine.rb +23 -0
  79. data/test/support/test_with_cassette.rb +38 -0
  80. data/test/test_helper.rb +52 -0
  81. data/test/unit/#vcr_test.rb# +68 -0
  82. data/test/unit/ebsco_host_engine_test.rb +134 -0
  83. data/test/unit/eds_engine_test.rb +105 -0
  84. data/test/unit/google_books_engine_test.rb +93 -0
  85. data/test/unit/item_decorators_test.rb +66 -0
  86. data/test/unit/multi_searcher_test.rb +49 -0
  87. data/test/unit/openurl_creator_test.rb +111 -0
  88. data/test/unit/pagination_test.rb +59 -0
  89. data/test/unit/primo_engine_test.rb +37 -0
  90. data/test/unit/register_engine_test.rb +50 -0
  91. data/test/unit/result_item_display_test.rb +39 -0
  92. data/test/unit/result_item_test.rb +36 -0
  93. data/test/unit/scopus_engine_test.rb +130 -0
  94. data/test/unit/search_engine_base_test.rb +178 -0
  95. data/test/unit/search_engine_test.rb +95 -0
  96. data/test/unit/summon_engine_test.rb +161 -0
  97. data/test/unit/xerxes_engine_test.rb +70 -0
  98. data/test/vcr_cassettes/ebscohost/error_bad_db.yml +45 -0
  99. data/test/vcr_cassettes/ebscohost/error_bad_password.yml +45 -0
  100. data/test/vcr_cassettes/ebscohost/get_info.yml +3626 -0
  101. data/test/vcr_cassettes/ebscohost/live_search.yml +45 -0
  102. data/test/vcr_cassettes/ebscohost/live_search_smoke_test.yml +1311 -0
  103. data/test/vcr_cassettes/eds/basic_search_smoke_test.yml +1811 -0
  104. data/test/vcr_cassettes/eds/get_auth_token.yml +75 -0
  105. data/test/vcr_cassettes/eds/get_auth_token_failure.yml +39 -0
  106. data/test/vcr_cassettes/eds/get_with_auth.yml +243 -0
  107. data/test/vcr_cassettes/eds/get_with_auth_recovers_from_bad_auth.yml +368 -0
  108. data/test/vcr_cassettes/gbs/error_condition.yml +40 -0
  109. data/test/vcr_cassettes/gbs/pagination.yml +702 -0
  110. data/test/vcr_cassettes/gbs/search.yml +340 -0
  111. data/test/vcr_cassettes/primo/search_smoke_test.yml +1112 -0
  112. data/test/vcr_cassettes/scopus/bad_api_key_should_return_error_response.yml +60 -0
  113. data/test/vcr_cassettes/scopus/escaped_chars.yml +187 -0
  114. data/test/vcr_cassettes/scopus/fielded_search.yml +176 -0
  115. data/test/vcr_cassettes/scopus/simple_search.yml +227 -0
  116. data/test/vcr_cassettes/scopus/zero_results_search.yml +67 -0
  117. data/test/vcr_cassettes/summon/bad_auth.yml +54 -0
  118. data/test/vcr_cassettes/summon/proper_tags_for_snippets.yml +216 -0
  119. data/test/vcr_cassettes/summon/search.yml +242 -0
  120. data/test/vcr_cassettes/xerxes/live_search.yml +2580 -0
  121. data/test/view/std_item_test.rb +98 -0
  122. metadata +421 -0
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2012 Jonathan Rochkind/Johns Hopkins Universities
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,299 @@
1
+ # BentoSearch
2
+
3
+ [![Build Status](https://secure.travis-ci.org/jrochkind/bento_search.png)](http://travis-ci.org/jrochkind/bento_search)
4
+
5
+
6
+ (**in progress*, not yet ready for use, mainly because we need more
7
+ out of the box search engines supported).
8
+
9
+ bento_search provides an abstraction/normalization layer for querying and
10
+ displaying results for external search engines, in Ruby on Rails. Requires
11
+ Rails3 and tested only under ruby 1.9.3.
12
+
13
+ * It is focused on use cases for academic libraries, but may be useful in generic
14
+ cases too. Initially, engine adapters are planned to be provided for:
15
+ Google Books, Scopus, SerialSolutions Summon, Ex Libris Primo,
16
+ EBSCO Discovery Service, and EBSCO traditional 'EIT' api. Most
17
+ of these search engines require a vendor license to use.
18
+
19
+ * bento_search could be considered building blocks for a type of 'federated
20
+ search' functionality, but it does not and will never support merging results
21
+ from multiple engines into one result set. It is meant to support displaying the
22
+ first few results from multiple engines on one page, "bento box" style (as
23
+ named by Tito Sierra@NCSU), as well as more expanded single-search-on-a-page
24
+ uses.
25
+
26
+ * bento_search provides abstract functionality for pagination, sorting,
27
+ and single-field-specified queries. Faceting, limiting, and 'advanced'
28
+ multi-field searches are not yet supported, but planned. Not all
29
+ search engine adapters support all features. Search engine adapters can
30
+ declare search fields and sort options with 'semantics', so you can for
31
+ instance search or sort by 'title' across search engines without regard
32
+ to internal engine-specific field names.
33
+
34
+ bento_search is designed to allow code to be written agnostic of the search
35
+ provider, so you can switch out the search provider, minimizing dependent
36
+ code in your app that needs to be rewritten. As well as letting you get
37
+ started quick without reinventing the wheel and figuring out poorly
38
+ documented vendor API's yourself.
39
+
40
+
41
+ ## Usage
42
+
43
+ ### Instantiate an engine, and search
44
+
45
+ When you instantiate an engine, you can provide configuration keys. There
46
+ are a few standard keys (see BentoSearch::SearchEngine), and others that
47
+ may be engine-specific. Some engine-specific keys (such as api auth keys)
48
+ may be required for certain engines.
49
+
50
+ engine = BentoSearch::GoogleBooksEngine.new(:api_key => "my_gbs_api_key")
51
+ results = engine.search("a query")
52
+
53
+ `results` are a BentoSearch::Results object, which acts like an array of
54
+ BentoSearch::Item objects, along with some meta-information about the
55
+ search itself (pagination keys, etc). BentoSearch::Results and Item fields
56
+ are standardized accross engines. BentoSearch::Items provide semantic
57
+ values (title, author, etc.), as available from the particular engine.
58
+
59
+ To see which engines come bundled with BentoSearch, and any special
60
+ engine-specific instructions, look at BentoSearch source in `./app/search_engines`
61
+
62
+ ### Register engines in global configuration
63
+
64
+ It can be convenient to register an engine in global configuration, and is
65
+ required for certain functionality (like out-of-the-box AJAX loading).
66
+
67
+ In an initializer in your app, like say `./config/initializers/bento_search.rb`:
68
+
69
+ BentoSearch.register_engine("gbs") do |conf|
70
+ conf.engine = "BentoSearch::GoogleBooksEngine"
71
+ conf.api_key = "my_google_api_key"
72
+ # any other configuration
73
+ end
74
+
75
+ Then you can refer to it, for instance in a controller, by the id you registered:
76
+
77
+ @results = BentoSearch.get_engine("gbs").search("my query")
78
+
79
+ ### Display results
80
+
81
+ You can of course write your own code to display a BentoSearch::Results object
82
+ however you like. But BentoSearch comes with a helper method for displaying
83
+ a list of BentoSearch::Results in a standard way, using the bento_search
84
+ helper method.
85
+
86
+ <%= bento_search(@results) %>
87
+
88
+ ### Fielded searching.
89
+
90
+ You can search by an internal engine-specific field name:
91
+
92
+ google_books_engine.search("smith", :search_field => "inauthor")
93
+
94
+ Or, if the engine provides it, you can search by normalized semantic search
95
+ field type names:
96
+
97
+ google_books_engine.search("smith", :semantic_earch_field => :title)
98
+
99
+ This will raise if an engine doesn't support that semantic search field.
100
+ You can find out what fields a particular engine supports.
101
+
102
+ BentoSearch::GoogleBooksEngine.search_keys # => internal keys
103
+ BentoSearch::GoogleBooksEngine.semantic_search_keys
104
+
105
+ You can also provide all arguments in a single hash when it's convenient
106
+ to do so:
107
+
108
+ google_books_engine.search(:query => "smith", :search_field => "inauthor")
109
+
110
+ ### Sorting
111
+
112
+ An engine advertises what sort types it supports:
113
+
114
+ BentoSearch::GoogleBooksEngine.sort_definitions
115
+
116
+ That returns a hash, where the keys are sort identifiers, where possible
117
+ chosen from a standard list of semantics. (See list in config/i18n/en.yml,
118
+ bento_search.sort_keys).
119
+
120
+ google_books_engine.search("my query", :sort => "date_desc")
121
+
122
+ For help creating your UI, you can use built-in helper method:
123
+
124
+ bento_sort_hash_for(engine)
125
+ #=> returns a Hash suitable as first argument for rails
126
+ # options_for_select helper, with sort options and labels from I18n.
127
+
128
+
129
+ ### Pagination
130
+
131
+ You can tell the search engine how many items you want per-page, and
132
+ use _either_ `:start` (0-based item offset) or `:page` (1-based page
133
+ offset) keys to paginate into the results.
134
+
135
+ results = google_books_engine.search("my query", :per_page => 20, :start => 40)
136
+ results = google_books_engine.search("my query", :per_page => 20, :page => 2) # means same as above
137
+
138
+ An engine instance advertises it's maximum per-page values.
139
+
140
+ google_books_engine.max_per_page
141
+
142
+ bento_search fixes the default per_page at 10.
143
+
144
+ For help creating your UI, you can ask a BentoSearch::Results for
145
+ `results.pagination`, which returns a BentoSearch::Results::Pagination
146
+ object which should be suitable for passing to [kaminari](https://github.com/amatsuda/kaminari)
147
+ `paginate`, or else have convenient methods for roll your own pagination UI.
148
+ Kaminari's paginate method:
149
+
150
+ <%= paginate results.pagination %>
151
+
152
+ ### Concurrent searching
153
+
154
+ If you're going to search 2 or more search engines at once, you'll want to execute
155
+ those searches concurrently. For instance, if GoogleBooks results take 2 second
156
+ to come in, and Scopus results take 3 seconds -- you don't want to first wait
157
+ the 2 second then wait the 3 seconds for a total of 5 -- you instead want
158
+ to execute concurrently in seperate threads, so the total wait time is the slowest
159
+ engine, not the sum of the engines.
160
+
161
+ You can write your own logic using ruby threads to do this, but
162
+ BentoSearch provides a multi-searching helper using [Celluloid](https://github.com/celluloid/celluloid)
163
+ to help you do this easily. Say, in a controller:
164
+
165
+ ~~~~ruby
166
+ # constructor takes id's registered with BentoSearch.register_engine
167
+ searcher = BentoSearch::MultiSearcher.new(:gbs, :scopus, :summon)
168
+
169
+ # Call 'start' with any parameters you would give to an_engine.search
170
+ searcher.start("my query", :semantic_search_field => :author, :sort => "title")
171
+
172
+ # At this point, all searches are executing asynchronously in seperate threads.
173
+ # To get the results, blocking until all complete:
174
+ @results = searcher.results
175
+
176
+ # @results will be a hash, keyed by registered engine id, values
177
+ # are BentoSearch::Results
178
+ ~~~~
179
+
180
+ Even if you are only searching one engine, this may be useful to have the
181
+ search execute in a seperate thread, so you can continue doing other work
182
+ in the main thread (like search a local store of some kind outside of
183
+ bento_search)
184
+
185
+ You will need to add the 'celluloid' gem to your app to use this feature,
186
+ BentoSearch doesn't automatically include the celluloid dependency right now
187
+ (should it?).
188
+
189
+ For more info, see BentoSearch::MultiSearcher.
190
+
191
+ ### Delayed results loading via AJAX (actually more like AJAHtml)
192
+
193
+ BentoSearch provides some basic support for initially displaying a placeholder
194
+ progress spinner, and having Javascript call back to get the actual results.
195
+
196
+ * **Setup Pre-requisites**
197
+ * In your `./config/routes.rb`, you need `BentoSearch::Routes.new(self).draw` in order
198
+ to route to the ajax loader.
199
+ * In your asset pipeline, you must have `//= require 'bento_search/ajax_load`
200
+ to get JS for ajax loading. (or require 'bento_search' to get all bento_search JS)
201
+ * **Note** that this is not a panacea for a very slow search engine -- if the
202
+ search results take 20 seconds to come in, when the AJAX call back happens,
203
+ your Rails process _will_ be blocked from serving any other requests for that 20
204
+ seconds. In fact, that makes this feature of very limited applicability in general,
205
+ think carefully about what this will do for you.
206
+ * **Beware** that there are some authorization considerations if your search
207
+ engine is not publically configurable, see BentoSearch::SearchController
208
+ for more details.
209
+
210
+ You have have registered a configured engine globally, and given it the special
211
+ `:allow_routable_results` key.
212
+
213
+ BentoSearch.register_engine("gbs") do |conf|
214
+ conf.api_key = "x"
215
+ conf.allow_routable_results = true
216
+ end
217
+
218
+ Now you can use the `bento_search` helper method with the registered id
219
+ and query, instead of with results as before, and with an option for
220
+ ajax auto-load.
221
+
222
+ <%= bento_search("gbs", :query => "my query",
223
+ :semantic_search_field => :title,
224
+ :load => :ajax_auto) %>
225
+
226
+
227
+
228
+ ### Item Decorators, and Links
229
+
230
+ You can configure Decorators, in the form of plain old ruby modules, to be
231
+ applied to BentoSearch::Items, on an engine-by-engine basis. These can modify,
232
+ add, or remove Item data, as well as over-ride some presentational methods.
233
+
234
+ One common use for these Decorators is changing, adding, or removing links
235
+ associated with an item. For instance, to link to your local OpenURL
236
+ link resolver.
237
+
238
+ BentoSearch::Items can have a main link associated with them (generally
239
+ hyperlinked from title), as well as a list of additional links. Most engines
240
+ do not provide additional links by default, custom local Decorators would
241
+ be used to add them.
242
+
243
+ BentoSearch.register_engine("something") do |conf|
244
+ conf.engine = SomeEngine
245
+ conf.item_decorators = [ SomeModule, OtherModule]
246
+ end
247
+
248
+ See BentoSearch::Item for more information on decorators, and BentoSearch::Link
249
+ on links.
250
+
251
+ ## Planned Features
252
+
253
+ I am trying to keep BentoSearch as simple as it can be to conveniently meet
254
+ actual use cases. Trying to avoid premature over-engineering, and pave
255
+ the cowpaths as needed.
256
+
257
+ Probably:
258
+
259
+ * Support for display facets for engines that support such, as well as
260
+ search with limits from controlled vocabulary (ie, selected facet, but
261
+ also may be supported by some engines that do not support facetting).
262
+ * Support for multi-field, multi-entry-box 'advanced search' UI's, in
263
+ a normalized cross-engine way.
264
+ * More mindless support for displaying pagination UI with kaminari.
265
+
266
+ Other needs or suggestions?
267
+
268
+
269
+ ## Developing
270
+
271
+ BentoSearch is fairly well covered by automated tests. We simply use Test::Unit.
272
+ Run tests with `rake test`.
273
+
274
+ The testing environment was generated with `rails plugin new`, and includes
275
+ a dummy app used when testing at `./test/dummy`.
276
+
277
+ For integration tests against live external search API's, we use the awesome
278
+ [VCR](https://github.com/myronmarston/vcr) gem to cache responses.
279
+ To write your own Test::Unit tests using VCR, take note of the
280
+ `test_with_cassette` method provided in `./test/support/test_with_cassette.rb`.
281
+
282
+ Also note use of VCR.filter_sensitive_data to make sure your API keys
283
+ do not get saved in cached response in the repo, while still allowing
284
+ tests to be run against cached responses even for engines that require
285
+ auth.
286
+
287
+ To re-generate cached responses, delete the relevant files in
288
+ `./test/vcr_cassettes` and re-run tests. You may have to set an ENV
289
+ variable with your own API keys to re-run tests without cached response
290
+ like this.
291
+
292
+ Also note `./test/support/mock_engine.rb`, a simple mock/dummy SearchEngine
293
+ implementation that can be used in other tests.
294
+
295
+ Pull requests welcome. Pull requests with additional search engine implementations
296
+ welcome. See more info on writing a BentoSearch::SearchEngine in the inline
297
+ docs in that file.
298
+
299
+
data/Rakefile ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'BentoSearch'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
24
+ load 'rails/tasks/engine.rake'
25
+
26
+
27
+
28
+ Bundler::GemHelper.install_tasks
29
+
30
+ require 'rake/testtask'
31
+
32
+ Rake::TestTask.new(:test) do |t|
33
+ t.libs << 'lib'
34
+ t.libs << 'test'
35
+ t.pattern = 'test/**/*_test.rb'
36
+ t.verbose = false
37
+ end
38
+
39
+
40
+ task :default => :test
@@ -0,0 +1,3 @@
1
+ // require all bento_search javascript.
2
+ //
3
+ //= require_tree ./bento_search
@@ -0,0 +1,22 @@
1
+ jQuery(document).ready(function($) {
2
+ //Intentionally wait for window.load, not just onready, to
3
+ //prevent interfering with rest of page load.
4
+ $(window).bind("load", function() {
5
+ $(".bento_search_ajax_wait").each(function(i, div) {
6
+ div = $(div);
7
+ // from html5 data-bento-ajax-url
8
+ $.ajax({
9
+ url: div.data("bentoAjaxUrl"),
10
+ success: function(response, status, xhr) {
11
+ div.replaceWith(response);
12
+ },
13
+ error: function(xhr, status, errorThrown) {
14
+ var msg = "Sorry but there was an error: ";
15
+ div.html(msg + xhr.status + " " + xhr.statusText + ", " + status);
16
+ }
17
+ });
18
+
19
+ });
20
+ });
21
+
22
+ });
@@ -0,0 +1,4 @@
1
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
@@ -0,0 +1,7 @@
1
+ module BentoSearch
2
+ # Master superclass for all controllers included in
3
+ # bento_search, note it inherits from host app's
4
+ # ApplicationController
5
+ class BentoSearchController < ::ApplicationController
6
+ end
7
+ end
@@ -0,0 +1,72 @@
1
+ module BentoSearch
2
+ # This is a controller that provides stand-alone search results
3
+ # for registered engines. Right now, this is only for automatic
4
+ # AJAX delayed loading. In the future it may be used for atom results,
5
+ # or other such.
6
+ #
7
+ # You need to make sure to include routing for this controller in your
8
+ # app to use it, for instance with `BentoSearch::Routes.new(self).draw`
9
+ # in your ./config/routes.rb
10
+ #
11
+ # # Authorization Issues
12
+ #
13
+ # You may have some engines which should not be publically searchable,
14
+ # they should only be searchable by certain auth'd users. This controller
15
+ # could accidentally provide a non-protected endpoint to get results if
16
+ # nothing were done to prevent it.
17
+ #
18
+ # Only engines which have a :allow_routable_results => true key
19
+ # in their config will be served by this controller.
20
+ #
21
+ # If you need routable results on an engine which ALSO needs to
22
+ # be protected by auth, you can add your own Rails before_filter
23
+ # to provide auth. Say, in an initializer in your app:
24
+ #
25
+ # SearchController.before_filter do |controller|
26
+ # unless controller.current_user
27
+ # raise BentoSearch::SearchController::AccessDenied
28
+ # end
29
+ # end
30
+ #
31
+ #
32
+ # We may provide fancier/nicer API for this in the future, if there's
33
+ # demand.
34
+ class SearchController < BentoSearchController
35
+ class AccessDenied < Exception ; end
36
+
37
+
38
+ rescue_from AccessDenied, :with => :deny_access
39
+ rescue_from NoSuchEngine, :with => :render_404
40
+
41
+ # returns partial HTML results, suitable for
42
+ # AJAX to insert into DOM.
43
+ # arguments for engine.search are taken from URI request params.
44
+ # (TODO: Is this a security issue, do we need to whitelist em? )
45
+ def search
46
+ engine = BentoSearch.get_engine(params[:engine_id])
47
+
48
+
49
+ unless engine.configuration.allow_routable_results == true
50
+ raise AccessDenied.new("engine needs to be registered with :allow_routable_results => true")
51
+ end
52
+
53
+ @results = engine.search(params.to_hash.symbolize_keys)
54
+
55
+ render :layout => false # partial HTML results
56
+ end
57
+
58
+
59
+
60
+ protected
61
+
62
+ def deny_access(exception)
63
+ render :text => exception.message, :status => 403
64
+ end
65
+
66
+ def render_404(exception)
67
+ render :text => exception.message, :status => 404
68
+ end
69
+
70
+
71
+ end
72
+ end