ransack 4.1.1 → 4.4.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.
- checksums.yaml +4 -4
- data/README.md +6 -4
- data/lib/polyamorous/activerecord/join_association_7_2.rb +55 -0
- data/lib/polyamorous/polyamorous.rb +5 -1
- data/lib/ransack/adapters/active_record/context.rb +32 -5
- data/lib/ransack/constants.rb +1 -1
- data/lib/ransack/context.rb +7 -4
- data/lib/ransack/helpers/form_builder.rb +6 -7
- data/lib/ransack/helpers/form_helper.rb +86 -20
- data/lib/ransack/invalid_search_error.rb +3 -0
- data/lib/ransack/locale/ja.yml +51 -51
- data/lib/ransack/locale/ko.yml +70 -0
- data/lib/ransack/locale/uk.yml +72 -0
- data/lib/ransack/nodes/condition.rb +38 -6
- data/lib/ransack/nodes/grouping.rb +1 -1
- data/lib/ransack/nodes/sort.rb +1 -1
- data/lib/ransack/nodes/value.rb +1 -1
- data/lib/ransack/search.rb +4 -3
- data/lib/ransack/version.rb +1 -1
- data/lib/ransack.rb +5 -0
- data/spec/console.rb +3 -15
- data/spec/factories/articles.rb +7 -0
- data/spec/factories/comments.rb +7 -0
- data/spec/factories/notes.rb +13 -0
- data/spec/factories/people.rb +10 -0
- data/spec/factories/tags.rb +5 -0
- data/spec/polyamorous/join_association_spec.rb +0 -1
- data/spec/polyamorous/join_dependency_spec.rb +0 -1
- data/spec/ransack/adapters/active_record/base_spec.rb +144 -3
- data/spec/ransack/adapters/active_record/context_spec.rb +72 -0
- data/spec/ransack/helpers/form_builder_spec.rb +0 -2
- data/spec/ransack/helpers/form_helper_spec.rb +219 -5
- data/spec/ransack/invalid_search_error_spec.rb +27 -0
- data/spec/ransack/nodes/condition_spec.rb +230 -0
- data/spec/ransack/nodes/grouping_spec.rb +2 -2
- data/spec/ransack/nodes/value_spec.rb +12 -1
- data/spec/ransack/predicate_spec.rb +16 -9
- data/spec/ransack/ransacker_spec.rb +69 -0
- data/spec/ransack/search_spec.rb +129 -2
- data/spec/ransack/translate_spec.rb +0 -1
- data/spec/spec_helper.rb +7 -21
- data/spec/support/schema.rb +48 -9
- metadata +32 -97
- data/.github/FUNDING.yml +0 -3
- data/.github/SECURITY.md +0 -12
- data/.github/workflows/codeql.yml +0 -72
- data/.github/workflows/cronjob.yml +0 -99
- data/.github/workflows/deploy.yml +0 -35
- data/.github/workflows/rubocop.yml +0 -20
- data/.github/workflows/test-deploy.yml +0 -29
- data/.github/workflows/test.yml +0 -131
- data/.gitignore +0 -7
- data/.nojekyll +0 -0
- data/.rubocop.yml +0 -50
- data/CHANGELOG.md +0 -1176
- data/CONTRIBUTING.md +0 -171
- data/Gemfile +0 -53
- data/Rakefile +0 -24
- data/bug_report_templates/test-ransack-scope-and-column-same-name.rb +0 -78
- data/bug_report_templates/test-ransacker-arel-present-predicate.rb +0 -75
- data/docs/.gitignore +0 -19
- data/docs/.nojekyll +0 -0
- data/docs/babel.config.js +0 -3
- data/docs/blog/2022-03-27-ransack-3.0.0.md +0 -20
- data/docs/docs/getting-started/_category_.json +0 -4
- data/docs/docs/getting-started/advanced-mode.md +0 -46
- data/docs/docs/getting-started/configuration.md +0 -47
- data/docs/docs/getting-started/search-matches.md +0 -67
- data/docs/docs/getting-started/simple-mode.md +0 -288
- data/docs/docs/getting-started/sorting.md +0 -71
- data/docs/docs/getting-started/using-predicates.md +0 -282
- data/docs/docs/going-further/_category_.json +0 -4
- data/docs/docs/going-further/acts-as-taggable-on.md +0 -114
- data/docs/docs/going-further/associations.md +0 -70
- data/docs/docs/going-further/custom-predicates.md +0 -52
- data/docs/docs/going-further/documentation.md +0 -43
- data/docs/docs/going-further/exporting-to-csv.md +0 -49
- data/docs/docs/going-further/external-guides.md +0 -57
- data/docs/docs/going-further/form-customisation.md +0 -63
- data/docs/docs/going-further/i18n.md +0 -53
- data/docs/docs/going-further/img/create_release.png +0 -0
- data/docs/docs/going-further/merging-searches.md +0 -41
- data/docs/docs/going-further/other-notes.md +0 -428
- data/docs/docs/going-further/polymorphic-search.md +0 -46
- data/docs/docs/going-further/ransackers.md +0 -331
- data/docs/docs/going-further/release_process.md +0 -36
- data/docs/docs/going-further/saving-queries.md +0 -82
- data/docs/docs/going-further/searching-postgres.md +0 -57
- data/docs/docs/going-further/wiki-contributors.md +0 -82
- data/docs/docs/intro.md +0 -99
- data/docs/docusaurus.config.js +0 -120
- data/docs/package.json +0 -42
- data/docs/sidebars.js +0 -31
- data/docs/src/components/HomepageFeatures/index.js +0 -64
- data/docs/src/components/HomepageFeatures/styles.module.css +0 -11
- data/docs/src/css/custom.css +0 -39
- data/docs/src/pages/index.module.css +0 -23
- data/docs/src/pages/markdown-page.md +0 -7
- data/docs/static/.nojekyll +0 -0
- data/docs/static/img/docusaurus.png +0 -0
- data/docs/static/img/favicon.ico +0 -0
- data/docs/static/img/logo.svg +0 -1
- data/docs/static/img/tutorial/docsVersionDropdown.png +0 -0
- data/docs/static/img/tutorial/localeDropdown.png +0 -0
- data/docs/static/img/undraw_docusaurus_mountain.svg +0 -171
- data/docs/static/img/undraw_docusaurus_react.svg +0 -170
- data/docs/static/img/undraw_docusaurus_tree.svg +0 -40
- data/docs/static/logo/ransack-h.png +0 -0
- data/docs/static/logo/ransack-h.svg +0 -34
- data/docs/static/logo/ransack-v.png +0 -0
- data/docs/static/logo/ransack-v.svg +0 -34
- data/docs/static/logo/ransack.png +0 -0
- data/docs/static/logo/ransack.svg +0 -21
- data/docs/yarn.lock +0 -8879
- data/ransack.gemspec +0 -26
- data/spec/blueprints/articles.rb +0 -5
- data/spec/blueprints/comments.rb +0 -5
- data/spec/blueprints/notes.rb +0 -5
- data/spec/blueprints/people.rb +0 -8
- data/spec/blueprints/tags.rb +0 -3
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Ransack
|
|
4
|
+
describe Ransacker do
|
|
5
|
+
let(:klass) { Person }
|
|
6
|
+
let(:name) { :test_ransacker }
|
|
7
|
+
let(:opts) { {} }
|
|
8
|
+
|
|
9
|
+
describe '#initialize' do
|
|
10
|
+
context 'with minimal options' do
|
|
11
|
+
subject { Ransacker.new(klass, name, opts) }
|
|
12
|
+
|
|
13
|
+
it 'sets the name' do
|
|
14
|
+
expect(subject.name).to eq(name)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'sets default type to string' do
|
|
18
|
+
expect(subject.type).to eq(:string)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'sets default args to [:parent]' do
|
|
22
|
+
expect(subject.args).to eq([:parent])
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
context 'with custom options' do
|
|
27
|
+
let(:opts) { { type: :integer, args: [:parent, :custom_arg], formatter: proc { |v| v.to_i } } }
|
|
28
|
+
|
|
29
|
+
subject { Ransacker.new(klass, name, opts) }
|
|
30
|
+
|
|
31
|
+
it 'sets the custom type' do
|
|
32
|
+
expect(subject.type).to eq(:integer)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'sets the custom args' do
|
|
36
|
+
expect(subject.args).to eq([:parent, :custom_arg])
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'sets the formatter' do
|
|
40
|
+
expect(subject.formatter).to eq(opts[:formatter])
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context 'with callable option' do
|
|
45
|
+
let(:callable) { proc { |parent| parent.table[:id] } }
|
|
46
|
+
let(:opts) { { callable: callable } }
|
|
47
|
+
|
|
48
|
+
subject { Ransacker.new(klass, name, opts) }
|
|
49
|
+
|
|
50
|
+
it 'initializes successfully' do
|
|
51
|
+
expect(subject).to be_a(Ransacker)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
describe 'basic functionality' do
|
|
57
|
+
subject { Ransacker.new(klass, name, opts) }
|
|
58
|
+
|
|
59
|
+
it 'responds to required methods' do
|
|
60
|
+
expect(subject).to respond_to(:name)
|
|
61
|
+
expect(subject).to respond_to(:type)
|
|
62
|
+
expect(subject).to respond_to(:args)
|
|
63
|
+
expect(subject).to respond_to(:formatter)
|
|
64
|
+
expect(subject).to respond_to(:attr_from)
|
|
65
|
+
expect(subject).to respond_to(:call)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
data/spec/ransack/search_spec.rb
CHANGED
|
@@ -178,7 +178,6 @@ module Ransack
|
|
|
178
178
|
# AND "articles"."title" = 'Test' AND "articles"."published" = 't' AND ('default_scope' = 'default_scope')
|
|
179
179
|
# ) ORDER BY "people"."id" DESC
|
|
180
180
|
|
|
181
|
-
pending("spec should pass, but I do not know how/where to fix lib code")
|
|
182
181
|
s = Search.new(Person, published_articles_title_not_eq: 'Test')
|
|
183
182
|
expect(s.result.to_sql).to include 'default_scope'
|
|
184
183
|
expect(s.result.to_sql).to include 'published'
|
|
@@ -270,6 +269,7 @@ module Ransack
|
|
|
270
269
|
end
|
|
271
270
|
|
|
272
271
|
specify { expect { subject }.to raise_error ArgumentError }
|
|
272
|
+
specify { expect { subject }.to raise_error InvalidSearchError }
|
|
273
273
|
end
|
|
274
274
|
|
|
275
275
|
context 'when ignore_unknown_conditions configuration option is true' do
|
|
@@ -300,6 +300,7 @@ module Ransack
|
|
|
300
300
|
|
|
301
301
|
context 'when ignore_unknown_conditions search parameter is false' do
|
|
302
302
|
specify { expect { with_ignore_unknown_conditions_false }.to raise_error ArgumentError }
|
|
303
|
+
specify { expect { with_ignore_unknown_conditions_false }.to raise_error InvalidSearchError }
|
|
303
304
|
end
|
|
304
305
|
|
|
305
306
|
context 'when ignore_unknown_conditions search parameter is true' do
|
|
@@ -312,6 +313,46 @@ module Ransack
|
|
|
312
313
|
expect { Search.new(Person, params) }.not_to change { params }
|
|
313
314
|
end
|
|
314
315
|
|
|
316
|
+
context 'with empty search parameters' do
|
|
317
|
+
it 'handles completely empty parameters' do
|
|
318
|
+
search = Search.new(Person, {})
|
|
319
|
+
expect(search.result.to_sql).not_to match(/WHERE/)
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
it 'handles nil parameters' do
|
|
323
|
+
search = Search.new(Person, nil)
|
|
324
|
+
expect(search.result.to_sql).not_to match(/WHERE/)
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
context 'with whitespace-only values' do
|
|
329
|
+
before do
|
|
330
|
+
Ransack.configure { |c| c.strip_whitespace = true }
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
it 'removes whitespace-only values' do
|
|
334
|
+
expect_any_instance_of(Search).to receive(:build).with({})
|
|
335
|
+
Search.new(Person, name_eq: ' ')
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
it 'keeps values with content after whitespace stripping' do
|
|
339
|
+
expect_any_instance_of(Search).to receive(:build).with({ 'name_eq' => 'test' })
|
|
340
|
+
Search.new(Person, name_eq: ' test ')
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
context 'with special characters in values' do
|
|
345
|
+
it 'handles values with special regex characters' do
|
|
346
|
+
search = Search.new(Person, name_cont: 'test[(){}^$|?*+.\\')
|
|
347
|
+
expect { search.result }.not_to raise_error
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
it 'handles values with SQL injection attempts' do
|
|
351
|
+
search = Search.new(Person, name_cont: "'; DROP TABLE people; --")
|
|
352
|
+
expect { search.result }.not_to raise_error
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
|
|
315
356
|
context "ransackable_scope" do
|
|
316
357
|
around(:each) do |example|
|
|
317
358
|
Person.define_singleton_method(:name_eq) do |name|
|
|
@@ -335,6 +376,74 @@ module Ransack
|
|
|
335
376
|
end
|
|
336
377
|
end
|
|
337
378
|
|
|
379
|
+
context "ransackable_scope with array arguments" do
|
|
380
|
+
around(:each) do |example|
|
|
381
|
+
Person.define_singleton_method(:domestic) do |countries|
|
|
382
|
+
self.where(name: countries)
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
Person.define_singleton_method(:flexible_scope) do |*args|
|
|
386
|
+
self.where(id: args)
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
Person.define_singleton_method(:two_param_scope) do |param1, param2|
|
|
390
|
+
self.where(name: param1, id: param2)
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
begin
|
|
394
|
+
example.run
|
|
395
|
+
ensure
|
|
396
|
+
Person.singleton_class.undef_method :domestic
|
|
397
|
+
Person.singleton_class.undef_method :flexible_scope
|
|
398
|
+
Person.singleton_class.undef_method :two_param_scope
|
|
399
|
+
end
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
it "handles scopes that take arrays as single arguments (arity 1)" do
|
|
403
|
+
allow(Person).to receive(:ransackable_scopes)
|
|
404
|
+
.and_return(Person.ransackable_scopes + [:domestic])
|
|
405
|
+
|
|
406
|
+
# This should not raise ArgumentError
|
|
407
|
+
expect {
|
|
408
|
+
s = Search.new(Person, domestic: ['US', 'JP'])
|
|
409
|
+
s.result # This triggers the actual scope call
|
|
410
|
+
}.not_to raise_error
|
|
411
|
+
|
|
412
|
+
s = Search.new(Person, domestic: ['US', 'JP'])
|
|
413
|
+
expect(s.instance_variable_get(:@scope_args)["domestic"]).to eq("US")
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
it "handles scopes with flexible arity (negative arity)" do
|
|
417
|
+
allow(Person).to receive(:ransackable_scopes)
|
|
418
|
+
.and_return(Person.ransackable_scopes + [:flexible_scope])
|
|
419
|
+
|
|
420
|
+
expect {
|
|
421
|
+
s = Search.new(Person, flexible_scope: ['US', 'JP'])
|
|
422
|
+
s.result
|
|
423
|
+
}.not_to raise_error
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
it "handles scopes with arity > 1" do
|
|
427
|
+
allow(Person).to receive(:ransackable_scopes)
|
|
428
|
+
.and_return(Person.ransackable_scopes + [:two_param_scope])
|
|
429
|
+
|
|
430
|
+
expect {
|
|
431
|
+
s = Search.new(Person, two_param_scope: ['param1', 'param2'])
|
|
432
|
+
s.result
|
|
433
|
+
}.not_to raise_error
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
it "still supports the workaround with nested arrays" do
|
|
437
|
+
allow(Person).to receive(:ransackable_scopes)
|
|
438
|
+
.and_return(Person.ransackable_scopes + [:domestic])
|
|
439
|
+
|
|
440
|
+
# The workaround from the issue should still work
|
|
441
|
+
expect {
|
|
442
|
+
s = Search.new(Person, domestic: [['US', 'JP']])
|
|
443
|
+
s.result
|
|
444
|
+
}.not_to raise_error
|
|
445
|
+
end
|
|
446
|
+
end
|
|
338
447
|
end
|
|
339
448
|
|
|
340
449
|
describe '#result' do
|
|
@@ -347,6 +456,7 @@ module Ransack
|
|
|
347
456
|
let(:notable_type_field) {
|
|
348
457
|
"#{quote_table_name("notes")}.#{quote_column_name("notable_type")}"
|
|
349
458
|
}
|
|
459
|
+
|
|
350
460
|
it 'evaluates conditions contextually' do
|
|
351
461
|
s = Search.new(Person, children_name_eq: 'Ernie')
|
|
352
462
|
expect(s.result).to be_an ActiveRecord::Relation
|
|
@@ -453,7 +563,7 @@ module Ransack
|
|
|
453
563
|
|
|
454
564
|
all_or_load, uniq_or_distinct = :load, :distinct
|
|
455
565
|
expect(s.result.send(all_or_load).size)
|
|
456
|
-
.to eq(
|
|
566
|
+
.to eq(8998)
|
|
457
567
|
expect(s.result(distinct: true).size)
|
|
458
568
|
.to eq(10)
|
|
459
569
|
expect(s.result.send(all_or_load).send(uniq_or_distinct))
|
|
@@ -477,6 +587,11 @@ module Ransack
|
|
|
477
587
|
@s = Search.new(Person)
|
|
478
588
|
end
|
|
479
589
|
|
|
590
|
+
it 'doesn\'t creates sorts' do
|
|
591
|
+
@s.sorts = ''
|
|
592
|
+
expect(@s.sorts.size).to eq(0)
|
|
593
|
+
end
|
|
594
|
+
|
|
480
595
|
it 'creates sorts based on a single attribute/direction' do
|
|
481
596
|
@s.sorts = 'id desc'
|
|
482
597
|
expect(@s.sorts.size).to eq(1)
|
|
@@ -614,6 +729,18 @@ module Ransack
|
|
|
614
729
|
expect(@s.result.first.id).to eq 1
|
|
615
730
|
end
|
|
616
731
|
|
|
732
|
+
it 'raises ArgumentError when an invalid argument is sent' do
|
|
733
|
+
expect do
|
|
734
|
+
@s.sorts = 1234
|
|
735
|
+
end.to raise_error(ArgumentError, "Invalid argument (Integer) supplied to sorts=")
|
|
736
|
+
end
|
|
737
|
+
|
|
738
|
+
it 'raises InvalidSearchError when an invalid argument is sent' do
|
|
739
|
+
expect do
|
|
740
|
+
@s.sorts = 1234
|
|
741
|
+
end.to raise_error(Ransack::InvalidSearchError, "Invalid argument (Integer) supplied to sorts=")
|
|
742
|
+
end
|
|
743
|
+
|
|
617
744
|
it "PG's sort option", if: ::ActiveRecord::Base.connection.adapter_name == "PostgreSQL" do
|
|
618
745
|
default = Ransack.options.clone
|
|
619
746
|
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,38 +1,27 @@
|
|
|
1
|
-
require 'machinist/active_record'
|
|
2
|
-
require 'polyamorous/polyamorous'
|
|
3
|
-
require 'sham'
|
|
4
|
-
require 'faker'
|
|
5
1
|
require 'ransack'
|
|
2
|
+
require 'factory_bot'
|
|
3
|
+
require 'faker'
|
|
6
4
|
require 'action_controller'
|
|
7
5
|
require 'ransack/helpers'
|
|
8
6
|
require 'pry'
|
|
9
7
|
require 'simplecov'
|
|
10
8
|
require 'byebug'
|
|
9
|
+
require 'rspec'
|
|
11
10
|
|
|
12
11
|
SimpleCov.start
|
|
13
12
|
I18n.enforce_available_locales = false
|
|
14
13
|
Time.zone = 'Eastern Time (US & Canada)'
|
|
15
14
|
I18n.load_path += Dir[File.join(File.dirname(__FILE__), 'support', '*.yml')]
|
|
16
15
|
|
|
17
|
-
Dir[File.expand_path('../{helpers,support,
|
|
16
|
+
Dir[File.expand_path('../{helpers,support,factories}/*.rb', __FILE__)]
|
|
18
17
|
.each { |f| require f }
|
|
19
18
|
|
|
20
19
|
Faker::Config.random = Random.new(0)
|
|
21
|
-
Sham.define do
|
|
22
|
-
name { Faker::Name.name }
|
|
23
|
-
title { Faker::Lorem.sentence }
|
|
24
|
-
body { Faker::Lorem.paragraph }
|
|
25
|
-
salary { |index| 30000 + (index * 1000) }
|
|
26
|
-
tag_name { Faker::Lorem.words(number: 3).join(' ') }
|
|
27
|
-
note { Faker::Lorem.words(number: 7).join(' ') }
|
|
28
|
-
only_admin { Faker::Lorem.words(number: 3).join(' ') }
|
|
29
|
-
only_search { Faker::Lorem.words(number: 3).join(' ') }
|
|
30
|
-
only_sort { Faker::Lorem.words(number: 3).join(' ') }
|
|
31
|
-
notable_id { |id| id }
|
|
32
|
-
end
|
|
33
20
|
|
|
34
21
|
RSpec.configure do |config|
|
|
35
22
|
config.alias_it_should_behave_like_to :it_has_behavior, 'has behavior'
|
|
23
|
+
|
|
24
|
+
config.include FactoryBot::Syntax::Methods
|
|
36
25
|
|
|
37
26
|
config.before(:suite) do
|
|
38
27
|
message = "Running Ransack specs with #{
|
|
@@ -42,12 +31,9 @@ RSpec.configure do |config|
|
|
|
42
31
|
line = '=' * message.length
|
|
43
32
|
puts line, message, line
|
|
44
33
|
Schema.create
|
|
45
|
-
SubDB::Schema.create
|
|
34
|
+
SubDB::Schema.create if defined?(SubDB)
|
|
46
35
|
end
|
|
47
36
|
|
|
48
|
-
config.before(:all) { Sham.reset(:before_all) }
|
|
49
|
-
config.before(:each) { Sham.reset(:before_each) }
|
|
50
|
-
|
|
51
37
|
config.include RansackHelper
|
|
52
38
|
config.include PolyamorousHelper
|
|
53
39
|
end
|
data/spec/support/schema.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'active_record'
|
|
2
|
+
require 'activerecord-postgis-adapter'
|
|
2
3
|
|
|
3
4
|
case ENV['DB'].try(:downcase)
|
|
4
5
|
when 'mysql', 'mysql2'
|
|
@@ -20,6 +21,17 @@ when 'pg', 'postgres', 'postgresql'
|
|
|
20
21
|
host: ENV.fetch("DATABASE_HOST") { "localhost" },
|
|
21
22
|
min_messages: 'warning'
|
|
22
23
|
)
|
|
24
|
+
when 'postgis'
|
|
25
|
+
# To test with PostGIS: `DB=postgis bundle exec rake spec`
|
|
26
|
+
ActiveRecord::Base.establish_connection(
|
|
27
|
+
adapter: 'postgis',
|
|
28
|
+
postgis_extension: 'postgis',
|
|
29
|
+
database: 'ransack',
|
|
30
|
+
username: ENV.fetch("DATABASE_USERNAME") { "postgres" },
|
|
31
|
+
password: ENV.fetch("DATABASE_PASSWORD") { "" },
|
|
32
|
+
host: ENV.fetch("DATABASE_HOST") { "localhost" },
|
|
33
|
+
min_messages: 'warning'
|
|
34
|
+
)
|
|
23
35
|
else
|
|
24
36
|
# Otherwise, assume SQLite3: `bundle exec rake spec`
|
|
25
37
|
ActiveRecord::Base.establish_connection(
|
|
@@ -104,7 +116,7 @@ class Person < ApplicationRecord
|
|
|
104
116
|
)
|
|
105
117
|
end
|
|
106
118
|
|
|
107
|
-
ransacker :sql_literal_id do
|
|
119
|
+
ransacker :sql_literal_id, type: :integer do
|
|
108
120
|
Arel.sql('people.id')
|
|
109
121
|
end
|
|
110
122
|
|
|
@@ -126,6 +138,17 @@ class Person < ApplicationRecord
|
|
|
126
138
|
Arel.sql(query)
|
|
127
139
|
end
|
|
128
140
|
|
|
141
|
+
ransacker :article_tags, formatter: proc { |id|
|
|
142
|
+
if Tag.exists?(id)
|
|
143
|
+
joins(articles: :tags)
|
|
144
|
+
.where(tags: { id: id })
|
|
145
|
+
.distinct
|
|
146
|
+
.select(:id).arel
|
|
147
|
+
end
|
|
148
|
+
} do |parent|
|
|
149
|
+
parent.table[:id]
|
|
150
|
+
end
|
|
151
|
+
|
|
129
152
|
def self.ransackable_attributes(auth_object = nil)
|
|
130
153
|
if auth_object == :admin
|
|
131
154
|
authorizable_ransackable_attributes - ['only_sort']
|
|
@@ -151,6 +174,7 @@ class Article < ApplicationRecord
|
|
|
151
174
|
has_many :comments
|
|
152
175
|
has_and_belongs_to_many :tags
|
|
153
176
|
has_many :notes, as: :notable
|
|
177
|
+
has_many :recent_notes, as: :notable
|
|
154
178
|
|
|
155
179
|
alias_attribute :content, :body
|
|
156
180
|
|
|
@@ -220,18 +244,28 @@ end
|
|
|
220
244
|
class Comment < ApplicationRecord
|
|
221
245
|
belongs_to :article
|
|
222
246
|
belongs_to :person
|
|
247
|
+
has_and_belongs_to_many :tags
|
|
223
248
|
|
|
224
249
|
default_scope { where(disabled: false) }
|
|
225
250
|
end
|
|
226
251
|
|
|
227
252
|
class Tag < ApplicationRecord
|
|
228
253
|
has_and_belongs_to_many :articles
|
|
254
|
+
has_and_belongs_to_many :comments
|
|
229
255
|
end
|
|
230
256
|
|
|
231
257
|
class Note < ApplicationRecord
|
|
232
258
|
belongs_to :notable, polymorphic: true
|
|
233
259
|
end
|
|
234
260
|
|
|
261
|
+
class RecentNote < ApplicationRecord
|
|
262
|
+
DEFAULT_NOTABLE_ID = 1
|
|
263
|
+
self.table_name = "notes"
|
|
264
|
+
default_scope { where(notable_id: DEFAULT_NOTABLE_ID) }
|
|
265
|
+
|
|
266
|
+
belongs_to :notable, polymorphic: true
|
|
267
|
+
end
|
|
268
|
+
|
|
235
269
|
class Account < ApplicationRecord
|
|
236
270
|
belongs_to :agent_account, class_name: "Account"
|
|
237
271
|
belongs_to :trade_account, class_name: "Account"
|
|
@@ -298,6 +332,11 @@ module Schema
|
|
|
298
332
|
t.integer :tag_id
|
|
299
333
|
end
|
|
300
334
|
|
|
335
|
+
create_table :comments_tags, force: true, id: false do |t|
|
|
336
|
+
t.integer :comment_id
|
|
337
|
+
t.integer :tag_id
|
|
338
|
+
end
|
|
339
|
+
|
|
301
340
|
create_table :notes, force: true do |t|
|
|
302
341
|
t.integer :notable_id
|
|
303
342
|
t.string :notable_type
|
|
@@ -331,23 +370,23 @@ module Schema
|
|
|
331
370
|
end
|
|
332
371
|
|
|
333
372
|
10.times do
|
|
334
|
-
person =
|
|
335
|
-
|
|
373
|
+
person = FactoryBot.create(:person)
|
|
374
|
+
FactoryBot.create(:note, :for_person, notable: person)
|
|
336
375
|
3.times do
|
|
337
|
-
article =
|
|
376
|
+
article = FactoryBot.create(:article, person: person)
|
|
338
377
|
3.times do
|
|
339
|
-
article.tags = [
|
|
378
|
+
article.tags = [FactoryBot.create(:tag), FactoryBot.create(:tag), FactoryBot.create(:tag)]
|
|
340
379
|
end
|
|
341
|
-
|
|
380
|
+
FactoryBot.create(:note, :for_article, notable: article)
|
|
342
381
|
10.times do
|
|
343
|
-
|
|
382
|
+
FactoryBot.create(:comment, article: article, person: person)
|
|
344
383
|
end
|
|
345
384
|
end
|
|
346
385
|
end
|
|
347
386
|
|
|
348
|
-
|
|
387
|
+
FactoryBot.create(:comment,
|
|
349
388
|
body: 'First post!',
|
|
350
|
-
article:
|
|
389
|
+
article: FactoryBot.create(:article, title: 'Hello, world!')
|
|
351
390
|
)
|
|
352
391
|
end
|
|
353
392
|
end
|