searchkick 4.4.0 → 5.3.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.
data/lib/searchkick.rb CHANGED
@@ -1,29 +1,41 @@
1
1
  # dependencies
2
2
  require "active_support"
3
3
  require "active_support/core_ext/hash/deep_merge"
4
- require "elasticsearch"
4
+ require "active_support/core_ext/module/attr_internal"
5
+ require "active_support/core_ext/module/delegation"
6
+ require "active_support/notifications"
5
7
  require "hashie"
6
8
 
9
+ # stdlib
10
+ require "forwardable"
11
+
7
12
  # modules
8
- require "searchkick/bulk_indexer"
9
- require "searchkick/index"
10
- require "searchkick/indexer"
11
- require "searchkick/hash_wrapper"
12
- require "searchkick/middleware"
13
- require "searchkick/model"
14
- require "searchkick/multi_search"
15
- require "searchkick/query"
16
- require "searchkick/reindex_queue"
17
- require "searchkick/record_data"
18
- require "searchkick/record_indexer"
19
- require "searchkick/results"
20
- require "searchkick/version"
13
+ require_relative "searchkick/controller_runtime"
14
+ require_relative "searchkick/index"
15
+ require_relative "searchkick/index_cache"
16
+ require_relative "searchkick/index_options"
17
+ require_relative "searchkick/indexer"
18
+ require_relative "searchkick/hash_wrapper"
19
+ require_relative "searchkick/log_subscriber"
20
+ require_relative "searchkick/model"
21
+ require_relative "searchkick/multi_search"
22
+ require_relative "searchkick/query"
23
+ require_relative "searchkick/reindex_queue"
24
+ require_relative "searchkick/record_data"
25
+ require_relative "searchkick/record_indexer"
26
+ require_relative "searchkick/relation"
27
+ require_relative "searchkick/relation_indexer"
28
+ require_relative "searchkick/results"
29
+ require_relative "searchkick/version"
30
+ require_relative "searchkick/where"
21
31
 
22
32
  # integrations
23
- require "searchkick/railtie" if defined?(Rails)
24
- require "searchkick/logging" if defined?(ActiveSupport::Notifications)
33
+ require_relative "searchkick/railtie" if defined?(Rails)
25
34
 
26
35
  module Searchkick
36
+ # requires faraday
37
+ autoload :Middleware, "searchkick/middleware"
38
+
27
39
  # background jobs
28
40
  autoload :BulkReindexJob, "searchkick/bulk_reindex_job"
29
41
  autoload :ProcessBatchJob, "searchkick/process_batch_job"
@@ -33,18 +45,21 @@ module Searchkick
33
45
  # errors
34
46
  class Error < StandardError; end
35
47
  class MissingIndexError < Error; end
36
- class UnsupportedVersionError < Error; end
37
- class InvalidQueryError < Elasticsearch::Transport::Transport::Errors::BadRequest; end
48
+ class UnsupportedVersionError < Error
49
+ def message
50
+ "This version of Searchkick requires Elasticsearch 7+ or OpenSearch 1+"
51
+ end
52
+ end
53
+ class InvalidQueryError < Error; end
38
54
  class DangerousOperation < Error; end
39
55
  class ImportError < Error; end
40
56
 
41
57
  class << self
42
- attr_accessor :search_method_name, :wordnet_path, :timeout, :models, :client_options, :redis, :index_prefix, :index_suffix, :queue_name, :model_options
58
+ attr_accessor :search_method_name, :timeout, :models, :client_options, :redis, :index_prefix, :index_suffix, :queue_name, :model_options, :client_type
43
59
  attr_writer :client, :env, :search_timeout
44
60
  attr_reader :aws_credentials
45
61
  end
46
62
  self.search_method_name = :search
47
- self.wordnet_path = "/var/lib/wn_s.pl"
48
63
  self.timeout = 10
49
64
  self.models = []
50
65
  self.client_options = {}
@@ -53,15 +68,45 @@ module Searchkick
53
68
 
54
69
  def self.client
55
70
  @client ||= begin
56
- require "typhoeus/adapters/faraday" if defined?(Typhoeus) && Gem::Version.new(Faraday::VERSION) < Gem::Version.new("0.14.0")
57
-
58
- Elasticsearch::Client.new({
59
- url: ENV["ELASTICSEARCH_URL"],
60
- transport_options: {request: {timeout: timeout}, headers: {content_type: "application/json"}},
61
- retry_on_failure: 2
62
- }.deep_merge(client_options)) do |f|
63
- f.use Searchkick::Middleware
64
- f.request signer_middleware_key, signer_middleware_aws_params if aws_credentials
71
+ client_type =
72
+ if self.client_type
73
+ self.client_type
74
+ elsif defined?(OpenSearch::Client) && defined?(Elasticsearch::Client)
75
+ raise Error, "Multiple clients found - set Searchkick.client_type = :elasticsearch or :opensearch"
76
+ elsif defined?(OpenSearch::Client)
77
+ :opensearch
78
+ elsif defined?(Elasticsearch::Client)
79
+ :elasticsearch
80
+ else
81
+ raise Error, "No client found - install the `elasticsearch` or `opensearch-ruby` gem"
82
+ end
83
+
84
+ # check after client to ensure faraday is installed
85
+ # TODO remove in Searchkick 6
86
+ if defined?(Typhoeus) && Gem::Version.new(Faraday::VERSION) < Gem::Version.new("0.14.0")
87
+ require "typhoeus/adapters/faraday"
88
+ end
89
+
90
+ if client_type == :opensearch
91
+ OpenSearch::Client.new({
92
+ url: ENV["OPENSEARCH_URL"],
93
+ transport_options: {request: {timeout: timeout}, headers: {content_type: "application/json"}},
94
+ retry_on_failure: 2
95
+ }.deep_merge(client_options)) do |f|
96
+ f.use Searchkick::Middleware
97
+ f.request :aws_sigv4, signer_middleware_aws_params if aws_credentials
98
+ end
99
+ else
100
+ raise Error, "The `elasticsearch` gem must be 7+" if Elasticsearch::VERSION.to_i < 7
101
+
102
+ Elasticsearch::Client.new({
103
+ url: ENV["ELASTICSEARCH_URL"],
104
+ transport_options: {request: {timeout: timeout}, headers: {content_type: "application/json"}},
105
+ retry_on_failure: 2
106
+ }.deep_merge(client_options)) do |f|
107
+ f.use Searchkick::Middleware
108
+ f.request :aws_sigv4, signer_middleware_aws_params if aws_credentials
109
+ end
65
110
  end
66
111
  end
67
112
  end
@@ -74,20 +119,26 @@ module Searchkick
74
119
  (defined?(@search_timeout) && @search_timeout) || timeout
75
120
  end
76
121
 
77
- def self.server_version
78
- @server_version ||= client.info["version"]["number"]
122
+ # private
123
+ def self.server_info
124
+ @server_info ||= client.info
79
125
  end
80
126
 
81
- def self.server_below?(version)
82
- Gem::Version.new(server_version.split("-")[0]) < Gem::Version.new(version.split("-")[0])
127
+ def self.server_version
128
+ @server_version ||= server_info["version"]["number"]
83
129
  end
84
130
 
85
- # memoize for performance
86
- def self.server_below7?
87
- unless defined?(@server_below7)
88
- @server_below7 = server_below?("7.0.0")
131
+ def self.opensearch?
132
+ unless defined?(@opensearch)
133
+ @opensearch = server_info["version"]["distribution"] == "opensearch"
89
134
  end
90
- @server_below7
135
+ @opensearch
136
+ end
137
+
138
+ # TODO always check true version in Searchkick 6
139
+ def self.server_below?(version, true_version = false)
140
+ server_version = !true_version && opensearch? ? "7.10.2" : self.server_version
141
+ Gem::Version.new(server_version.split("-")[0]) < Gem::Version.new(version.split("-")[0])
91
142
  end
92
143
 
93
144
  def self.search(term = "*", model: nil, **options, &block)
@@ -115,17 +166,27 @@ module Searchkick
115
166
  end
116
167
  end
117
168
 
118
- options = options.merge(block: block) if block
119
- query = Searchkick::Query.new(klass, term, **options)
169
+ # TODO remove in Searchkick 6
120
170
  if options[:execute] == false
121
- query
122
- else
123
- query.execute
171
+ Searchkick.warn("The execute option is no longer needed")
172
+ options.delete(:execute)
124
173
  end
174
+
175
+ options = options.merge(block: block) if block
176
+ Relation.new(klass, term, **options)
125
177
  end
126
178
 
127
179
  def self.multi_search(queries)
128
- Searchkick::MultiSearch.new(queries).perform
180
+ return if queries.empty?
181
+
182
+ queries = queries.map { |q| q.send(:query) }
183
+ event = {
184
+ name: "Multi Search",
185
+ body: queries.flat_map { |q| [q.params.except(:body).to_json, q.body.to_json] }.map { |v| "#{v}\n" }.join,
186
+ }
187
+ ActiveSupport::Notifications.instrument("multi_search.searchkick", event) do
188
+ MultiSearch.new(queries).perform
189
+ end
129
190
  end
130
191
 
131
192
  # callbacks
@@ -146,13 +207,25 @@ module Searchkick
146
207
  end
147
208
  end
148
209
 
149
- def self.callbacks(value = nil)
210
+ # message is private
211
+ def self.callbacks(value = nil, message: nil)
150
212
  if block_given?
151
213
  previous_value = callbacks_value
152
214
  begin
153
215
  self.callbacks_value = value
154
216
  result = yield
155
- indexer.perform if callbacks_value == :bulk
217
+ if callbacks_value == :bulk && indexer.queued_items.any?
218
+ event = {}
219
+ if message
220
+ message.call(event)
221
+ else
222
+ event[:name] = "Bulk"
223
+ event[:count] = indexer.queued_items.size
224
+ end
225
+ ActiveSupport::Notifications.instrument("request.searchkick", event) do
226
+ indexer.perform
227
+ end
228
+ end
156
229
  result
157
230
  ensure
158
231
  self.callbacks_value = previous_value
@@ -163,25 +236,20 @@ module Searchkick
163
236
  end
164
237
 
165
238
  def self.aws_credentials=(creds)
166
- begin
167
- require "faraday_middleware/aws_signers_v4"
168
- rescue LoadError
169
- require "faraday_middleware/aws_sigv4"
170
- end
239
+ require "faraday_middleware/aws_sigv4"
240
+
171
241
  @aws_credentials = creds
172
242
  @client = nil # reset client
173
243
  end
174
244
 
175
245
  def self.reindex_status(index_name)
176
- if redis
177
- batches_left = Searchkick::Index.new(index_name).batches_left
178
- {
179
- completed: batches_left == 0,
180
- batches_left: batches_left
181
- }
182
- else
183
- raise Searchkick::Error, "Redis not configured"
184
- end
246
+ raise Error, "Redis not configured" unless redis
247
+
248
+ batches_left = Index.new(index_name).batches_left
249
+ {
250
+ completed: batches_left == 0,
251
+ batches_left: batches_left
252
+ }
185
253
  end
186
254
 
187
255
  def self.with_redis
@@ -201,29 +269,41 @@ module Searchkick
201
269
  end
202
270
 
203
271
  # private
204
- def self.load_records(records, ids)
205
- records =
206
- if records.respond_to?(:primary_key)
207
- # ActiveRecord
208
- records.where(records.primary_key => ids) if records.primary_key
209
- elsif records.respond_to?(:queryable)
210
- # Mongoid 3+
211
- records.queryable.for_ids(ids)
212
- elsif records.respond_to?(:unscoped) && :id.respond_to?(:in)
213
- # Nobrainer
214
- records.unscoped.where(:id.in => ids)
215
- elsif records.respond_to?(:key_column_names)
216
- records.where(records.key_column_names.first => ids)
272
+ def self.load_records(relation, ids)
273
+ relation =
274
+ if relation.respond_to?(:primary_key)
275
+ primary_key = relation.primary_key
276
+ raise Error, "Need primary key to load records" if !primary_key
277
+
278
+ relation.where(primary_key => ids)
279
+ elsif relation.respond_to?(:queryable)
280
+ relation.queryable.for_ids(ids)
217
281
  end
218
282
 
219
- raise Searchkick::Error, "Not sure how to load records" if !records
283
+ raise Error, "Not sure how to load records" if !relation
220
284
 
221
- records
285
+ relation
286
+ end
287
+
288
+ # public (for reindexing conversions)
289
+ def self.load_model(class_name, allow_child: false)
290
+ model = class_name.safe_constantize
291
+ raise Error, "Could not find class: #{class_name}" unless model
292
+ if allow_child
293
+ unless model.respond_to?(:searchkick_klass)
294
+ raise Error, "#{class_name} is not a searchkick model"
295
+ end
296
+ else
297
+ unless Searchkick.models.include?(model)
298
+ raise Error, "#{class_name} is not a searchkick model"
299
+ end
300
+ end
301
+ model
222
302
  end
223
303
 
224
304
  # private
225
305
  def self.indexer
226
- Thread.current[:searchkick_indexer] ||= Searchkick::Indexer.new
306
+ Thread.current[:searchkick_indexer] ||= Indexer.new
227
307
  end
228
308
 
229
309
  # private
@@ -236,22 +316,9 @@ module Searchkick
236
316
  Thread.current[:searchkick_callbacks_enabled] = value
237
317
  end
238
318
 
239
- # private
240
- def self.signer_middleware_key
241
- defined?(FaradayMiddleware::AwsSignersV4) ? :aws_signers_v4 : :aws_sigv4
242
- end
243
-
244
319
  # private
245
320
  def self.signer_middleware_aws_params
246
- if signer_middleware_key == :aws_sigv4
247
- {service: "es", region: "us-east-1"}.merge(aws_credentials)
248
- else
249
- {
250
- credentials: aws_credentials[:credentials] || Aws::Credentials.new(aws_credentials[:access_key_id], aws_credentials[:secret_access_key]),
251
- service_name: "es",
252
- region: aws_credentials[:region] || "us-east-1"
253
- }
254
- end
321
+ {service: "es", region: "us-east-1"}.merge(aws_credentials)
255
322
  end
256
323
 
257
324
  # private
@@ -261,16 +328,55 @@ module Searchkick
261
328
  def self.relation?(klass)
262
329
  if klass.respond_to?(:current_scope)
263
330
  !klass.current_scope.nil?
264
- elsif defined?(Mongoid::Threaded)
265
- !Mongoid::Threaded.current_scope(klass).nil?
331
+ else
332
+ klass.is_a?(Mongoid::Criteria) || !Mongoid::Threaded.current_scope(klass).nil?
266
333
  end
267
334
  end
268
- end
269
335
 
270
- # TODO find better ActiveModel hook
271
- require "active_model/callbacks"
272
- ActiveModel::Callbacks.include(Searchkick::Model)
336
+ # private
337
+ def self.scope(model)
338
+ # safety check to make sure used properly in code
339
+ raise Error, "Cannot scope relation" if relation?(model)
340
+
341
+ if model.searchkick_options[:unscope]
342
+ model.unscoped
343
+ else
344
+ model
345
+ end
346
+ end
347
+
348
+ # private
349
+ def self.not_found_error?(e)
350
+ (defined?(Elastic::Transport) && e.is_a?(Elastic::Transport::Transport::Errors::NotFound)) ||
351
+ (defined?(Elasticsearch::Transport) && e.is_a?(Elasticsearch::Transport::Transport::Errors::NotFound)) ||
352
+ (defined?(OpenSearch) && e.is_a?(OpenSearch::Transport::Transport::Errors::NotFound))
353
+ end
354
+
355
+ # private
356
+ def self.transport_error?(e)
357
+ (defined?(Elastic::Transport) && e.is_a?(Elastic::Transport::Transport::Error)) ||
358
+ (defined?(Elasticsearch::Transport) && e.is_a?(Elasticsearch::Transport::Transport::Error)) ||
359
+ (defined?(OpenSearch) && e.is_a?(OpenSearch::Transport::Transport::Error))
360
+ end
361
+
362
+ # private
363
+ def self.not_allowed_error?(e)
364
+ (defined?(Elastic::Transport) && e.is_a?(Elastic::Transport::Transport::Errors::MethodNotAllowed)) ||
365
+ (defined?(Elasticsearch::Transport) && e.is_a?(Elasticsearch::Transport::Transport::Errors::MethodNotAllowed)) ||
366
+ (defined?(OpenSearch) && e.is_a?(OpenSearch::Transport::Transport::Errors::MethodNotAllowed))
367
+ end
368
+ end
273
369
 
274
370
  ActiveSupport.on_load(:active_record) do
275
371
  extend Searchkick::Model
276
372
  end
373
+
374
+ ActiveSupport.on_load(:mongoid) do
375
+ Mongoid::Document::ClassMethods.include Searchkick::Model
376
+ end
377
+
378
+ ActiveSupport.on_load(:action_controller) do
379
+ include Searchkick::ControllerRuntime
380
+ end
381
+
382
+ Searchkick::LogSubscriber.attach_to :searchkick
@@ -1,21 +1,25 @@
1
1
  namespace :searchkick do
2
- desc "reindex model"
2
+ desc "reindex a model (specify CLASS)"
3
3
  task reindex: :environment do
4
- if ENV["CLASS"]
5
- klass = ENV["CLASS"].constantize rescue nil
6
- if klass
7
- klass.reindex
8
- else
9
- abort "Could not find class: #{ENV['CLASS']}"
4
+ class_name = ENV["CLASS"]
5
+ abort "USAGE: rake searchkick:reindex CLASS=Product" unless class_name
6
+
7
+ model =
8
+ begin
9
+ Searchkick.load_model(class_name)
10
+ rescue Searchkick::Error => e
11
+ abort e.message
10
12
  end
11
- else
12
- abort "USAGE: rake searchkick:reindex CLASS=Product"
13
- end
13
+
14
+ puts "Reindexing #{model.name}..."
15
+ model.reindex
16
+ puts "Reindex successful"
14
17
  end
15
18
 
16
19
  namespace :reindex do
17
20
  desc "reindex all models"
18
21
  task all: :environment do
22
+ # eager load models to populate Searchkick.models
19
23
  if Rails.respond_to?(:autoloaders) && Rails.autoloaders.zeitwerk_enabled?
20
24
  # fix for https://github.com/rails/rails/issues/37006
21
25
  Zeitwerk::Loader.eager_load_all
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: searchkick
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.4.0
4
+ version: 5.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-18 00:00:00.000000000 Z
11
+ date: 2023-11-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -16,28 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '5'
19
+ version: '6.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '5'
27
- - !ruby/object:Gem::Dependency
28
- name: elasticsearch
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '6'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '6'
26
+ version: '6.1'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: hashie
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -52,80 +38,24 @@ dependencies:
52
38
  - - ">="
53
39
  - !ruby/object:Gem::Version
54
40
  version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: bundler
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: minitest
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: rake
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: elasticsearch-xpack
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: 7.8.0.pre
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: 7.8.0.pre
111
- description:
112
- email: andrew@chartkick.com
41
+ description:
42
+ email: andrew@ankane.org
113
43
  executables: []
114
44
  extensions: []
115
45
  extra_rdoc_files: []
116
46
  files:
117
47
  - CHANGELOG.md
118
- - CONTRIBUTING.md
119
48
  - LICENSE.txt
120
49
  - README.md
121
50
  - lib/searchkick.rb
122
- - lib/searchkick/bulk_indexer.rb
123
51
  - lib/searchkick/bulk_reindex_job.rb
52
+ - lib/searchkick/controller_runtime.rb
124
53
  - lib/searchkick/hash_wrapper.rb
125
54
  - lib/searchkick/index.rb
55
+ - lib/searchkick/index_cache.rb
126
56
  - lib/searchkick/index_options.rb
127
57
  - lib/searchkick/indexer.rb
128
- - lib/searchkick/logging.rb
58
+ - lib/searchkick/log_subscriber.rb
129
59
  - lib/searchkick/middleware.rb
130
60
  - lib/searchkick/model.rb
131
61
  - lib/searchkick/multi_search.rb
@@ -137,14 +67,17 @@ files:
137
67
  - lib/searchkick/record_indexer.rb
138
68
  - lib/searchkick/reindex_queue.rb
139
69
  - lib/searchkick/reindex_v2_job.rb
70
+ - lib/searchkick/relation.rb
71
+ - lib/searchkick/relation_indexer.rb
140
72
  - lib/searchkick/results.rb
141
73
  - lib/searchkick/version.rb
74
+ - lib/searchkick/where.rb
142
75
  - lib/tasks/searchkick.rake
143
76
  homepage: https://github.com/ankane/searchkick
144
77
  licenses:
145
78
  - MIT
146
79
  metadata: {}
147
- post_install_message:
80
+ post_install_message:
148
81
  rdoc_options: []
149
82
  require_paths:
150
83
  - lib
@@ -152,15 +85,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
152
85
  requirements:
153
86
  - - ">="
154
87
  - !ruby/object:Gem::Version
155
- version: '2.4'
88
+ version: '3'
156
89
  required_rubygems_version: !ruby/object:Gem::Requirement
157
90
  requirements:
158
91
  - - ">="
159
92
  - !ruby/object:Gem::Version
160
93
  version: '0'
161
94
  requirements: []
162
- rubygems_version: 3.1.2
163
- signing_key:
95
+ rubygems_version: 3.4.10
96
+ signing_key:
164
97
  specification_version: 4
165
- summary: Intelligent search made easy with Rails and Elasticsearch
98
+ summary: Intelligent search made easy with Rails and Elasticsearch or OpenSearch
166
99
  test_files: []
data/CONTRIBUTING.md DELETED
@@ -1,53 +0,0 @@
1
- # Contributing
2
-
3
- First, thanks for wanting to contribute. You’re awesome! :heart:
4
-
5
- ## Help
6
-
7
- We’re not able to provide support through GitHub Issues. If you’re looking for help with your code, try posting on [Stack Overflow](https://stackoverflow.com/questions/tagged/searchkick).
8
-
9
- All features should be documented. If you don’t see a feature in the docs, assume it doesn’t exist.
10
-
11
- ## Bugs
12
-
13
- Think you’ve discovered a bug?
14
-
15
- 1. Search existing issues to see if it’s been reported.
16
- 2. Try the `master` branch to make sure it hasn’t been fixed.
17
-
18
- ```rb
19
- gem "searchkick", github: "ankane/searchkick"
20
- ```
21
-
22
- 3. Try the `debug` option when searching. This can reveal useful info.
23
-
24
- ```ruby
25
- Product.search("something", debug: true)
26
- ```
27
-
28
- If the above steps don’t help, create an issue.
29
-
30
- - Recreate the problem by forking [this gist](https://gist.github.com/ankane/f80b0923d9ae2c077f41997f7b704e5c). Include a link to your gist and the output in the issue.
31
- - For exceptions, include the complete backtrace.
32
-
33
- ## New Features
34
-
35
- If you’d like to discuss a new feature, create an issue and start the title with `[Idea]`.
36
-
37
- ## Pull Requests
38
-
39
- Fork the project and create a pull request. A few tips:
40
-
41
- - Keep changes to a minimum. If you have multiple features or fixes, submit multiple pull requests.
42
- - Follow the existing style. The code should read like it’s written by a single person.
43
- - Add one or more tests if possible. Make sure existing tests pass with:
44
-
45
- ```sh
46
- bundle exec rake test
47
- ```
48
-
49
- Feel free to open an issue to get feedback on your idea before spending too much time on it.
50
-
51
- ---
52
-
53
- This contributing guide is released under [CCO](https://creativecommons.org/publicdomain/zero/1.0/) (public domain). Use it for your own project without attribution.