mini-fast-sys 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 (94) hide show
  1. checksums.yaml +7 -0
  2. data/mini-fast-sys.gemspec +12 -0
  3. data/ransack-4.4.1/LICENSE +20 -0
  4. data/ransack-4.4.1/README.md +101 -0
  5. data/ransack-4.4.1/lib/polyamorous/activerecord/join_association.rb +70 -0
  6. data/ransack-4.4.1/lib/polyamorous/activerecord/join_association_7_2.rb +55 -0
  7. data/ransack-4.4.1/lib/polyamorous/activerecord/join_dependency.rb +102 -0
  8. data/ransack-4.4.1/lib/polyamorous/activerecord/reflection.rb +11 -0
  9. data/ransack-4.4.1/lib/polyamorous/join.rb +70 -0
  10. data/ransack-4.4.1/lib/polyamorous/polyamorous.rb +27 -0
  11. data/ransack-4.4.1/lib/polyamorous/swapping_reflection_class.rb +11 -0
  12. data/ransack-4.4.1/lib/polyamorous/tree_node.rb +7 -0
  13. data/ransack-4.4.1/lib/ransack/active_record.rb +14 -0
  14. data/ransack-4.4.1/lib/ransack/adapters/active_record/base.rb +152 -0
  15. data/ransack-4.4.1/lib/ransack/adapters/active_record/context.rb +373 -0
  16. data/ransack-4.4.1/lib/ransack/configuration.rb +209 -0
  17. data/ransack-4.4.1/lib/ransack/constants.rb +176 -0
  18. data/ransack-4.4.1/lib/ransack/context.rb +190 -0
  19. data/ransack-4.4.1/lib/ransack/helpers/form_builder.rb +277 -0
  20. data/ransack-4.4.1/lib/ransack/helpers/form_helper.rb +311 -0
  21. data/ransack-4.4.1/lib/ransack/helpers.rb +2 -0
  22. data/ransack-4.4.1/lib/ransack/invalid_search_error.rb +3 -0
  23. data/ransack-4.4.1/lib/ransack/locale/ar.yml +70 -0
  24. data/ransack-4.4.1/lib/ransack/locale/az.yml +70 -0
  25. data/ransack-4.4.1/lib/ransack/locale/bg.yml +70 -0
  26. data/ransack-4.4.1/lib/ransack/locale/ca.yml +70 -0
  27. data/ransack-4.4.1/lib/ransack/locale/cs.yml +70 -0
  28. data/ransack-4.4.1/lib/ransack/locale/da.yml +70 -0
  29. data/ransack-4.4.1/lib/ransack/locale/de.yml +70 -0
  30. data/ransack-4.4.1/lib/ransack/locale/el.yml +70 -0
  31. data/ransack-4.4.1/lib/ransack/locale/en.yml +70 -0
  32. data/ransack-4.4.1/lib/ransack/locale/es.yml +70 -0
  33. data/ransack-4.4.1/lib/ransack/locale/fa.yml +70 -0
  34. data/ransack-4.4.1/lib/ransack/locale/fi.yml +71 -0
  35. data/ransack-4.4.1/lib/ransack/locale/fr.yml +70 -0
  36. data/ransack-4.4.1/lib/ransack/locale/hu.yml +70 -0
  37. data/ransack-4.4.1/lib/ransack/locale/id.yml +70 -0
  38. data/ransack-4.4.1/lib/ransack/locale/it.yml +70 -0
  39. data/ransack-4.4.1/lib/ransack/locale/ja.yml +70 -0
  40. data/ransack-4.4.1/lib/ransack/locale/ko.yml +70 -0
  41. data/ransack-4.4.1/lib/ransack/locale/nl.yml +70 -0
  42. data/ransack-4.4.1/lib/ransack/locale/pt-BR.yml +70 -0
  43. data/ransack-4.4.1/lib/ransack/locale/ro.yml +70 -0
  44. data/ransack-4.4.1/lib/ransack/locale/ru.yml +70 -0
  45. data/ransack-4.4.1/lib/ransack/locale/sk.yml +70 -0
  46. data/ransack-4.4.1/lib/ransack/locale/sv.yml +70 -0
  47. data/ransack-4.4.1/lib/ransack/locale/tr.yml +70 -0
  48. data/ransack-4.4.1/lib/ransack/locale/uk.yml +72 -0
  49. data/ransack-4.4.1/lib/ransack/locale/zh-CN.yml +70 -0
  50. data/ransack-4.4.1/lib/ransack/locale/zh-TW.yml +70 -0
  51. data/ransack-4.4.1/lib/ransack/naming.rb +58 -0
  52. data/ransack-4.4.1/lib/ransack/nodes/attribute.rb +59 -0
  53. data/ransack-4.4.1/lib/ransack/nodes/bindable.rb +52 -0
  54. data/ransack-4.4.1/lib/ransack/nodes/condition.rb +399 -0
  55. data/ransack-4.4.1/lib/ransack/nodes/grouping.rb +206 -0
  56. data/ransack-4.4.1/lib/ransack/nodes/node.rb +34 -0
  57. data/ransack-4.4.1/lib/ransack/nodes/sort.rb +54 -0
  58. data/ransack-4.4.1/lib/ransack/nodes/value.rb +115 -0
  59. data/ransack-4.4.1/lib/ransack/predicate.rb +75 -0
  60. data/ransack-4.4.1/lib/ransack/ransacker.rb +24 -0
  61. data/ransack-4.4.1/lib/ransack/search.rb +195 -0
  62. data/ransack-4.4.1/lib/ransack/translate.rb +156 -0
  63. data/ransack-4.4.1/lib/ransack/version.rb +3 -0
  64. data/ransack-4.4.1/lib/ransack/visitor.rb +87 -0
  65. data/ransack-4.4.1/lib/ransack.rb +33 -0
  66. data/ransack-4.4.1/spec/console.rb +13 -0
  67. data/ransack-4.4.1/spec/factories/articles.rb +7 -0
  68. data/ransack-4.4.1/spec/factories/comments.rb +7 -0
  69. data/ransack-4.4.1/spec/factories/notes.rb +13 -0
  70. data/ransack-4.4.1/spec/factories/people.rb +10 -0
  71. data/ransack-4.4.1/spec/factories/tags.rb +5 -0
  72. data/ransack-4.4.1/spec/helpers/polyamorous_helper.rb +13 -0
  73. data/ransack-4.4.1/spec/helpers/ransack_helper.rb +9 -0
  74. data/ransack-4.4.1/spec/polyamorous/activerecord_compatibility_spec.rb +15 -0
  75. data/ransack-4.4.1/spec/polyamorous/join_association_spec.rb +29 -0
  76. data/ransack-4.4.1/spec/polyamorous/join_dependency_spec.rb +80 -0
  77. data/ransack-4.4.1/spec/polyamorous/join_spec.rb +19 -0
  78. data/ransack-4.4.1/spec/ransack/adapters/active_record/base_spec.rb +943 -0
  79. data/ransack-4.4.1/spec/ransack/adapters/active_record/context_spec.rb +219 -0
  80. data/ransack-4.4.1/spec/ransack/configuration_spec.rb +201 -0
  81. data/ransack-4.4.1/spec/ransack/helpers/form_builder_spec.rb +169 -0
  82. data/ransack-4.4.1/spec/ransack/helpers/form_helper_spec.rb +1075 -0
  83. data/ransack-4.4.1/spec/ransack/invalid_search_error_spec.rb +27 -0
  84. data/ransack-4.4.1/spec/ransack/nodes/condition_spec.rb +333 -0
  85. data/ransack-4.4.1/spec/ransack/nodes/grouping_spec.rb +111 -0
  86. data/ransack-4.4.1/spec/ransack/nodes/value_spec.rb +126 -0
  87. data/ransack-4.4.1/spec/ransack/predicate_spec.rb +504 -0
  88. data/ransack-4.4.1/spec/ransack/ransacker_spec.rb +69 -0
  89. data/ransack-4.4.1/spec/ransack/search_spec.rb +821 -0
  90. data/ransack-4.4.1/spec/ransack/translate_spec.rb +16 -0
  91. data/ransack-4.4.1/spec/spec_helper.rb +52 -0
  92. data/ransack-4.4.1/spec/support/en.yml +18 -0
  93. data/ransack-4.4.1/spec/support/schema.rb +419 -0
  94. metadata +133 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4c2167e9be76b62ce0098ca3f4f7662a41765b79365512e9cb075b58383a5260
4
+ data.tar.gz: 4f0abd952227a08b1369b6c856ee028be2eeff65ce6233bec2892cb5a36c322d
5
+ SHA512:
6
+ metadata.gz: 5d5fc22aee1fe1e969b5111b4d63fbb83d0a7518a92c8072ecc7b2f0244fb133f6eba1decb2aab174faa4cf40678e2b82c04869009f9b752ab5c8dfbd484e111
7
+ data.tar.gz: 73087d9243d7df47181cd281ed17582d2774008a6a71e425202ceec8d94a90f352e5ae6ab19ad8d674a9f347f8863bc36c0d75fbe05ed726510f403da3a03731
@@ -0,0 +1,12 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "mini-fast-sys"
3
+ s.version = "0.0.1"
4
+ s.summary = "Research test"
5
+ s.description = "University research based on ransack"
6
+ s.authors = ["Andrey78"]
7
+ s.email = ["cakoc614@gmail.com"]
8
+ s.files = Dir.glob("**/*").reject { |f| f.end_with?('.gem') }
9
+ s.homepage = "https://rubygems.org/profiles/Andrey78"
10
+ s.license = "MIT"
11
+ s.metadata = { "source_code_uri" => "https://github.com/Andrey78/mini-fast-sys" }
12
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Ernie Miller
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.
@@ -0,0 +1,101 @@
1
+ # ![Ransack](./docs/static/logo/ransack-h.png "Ransack")
2
+
3
+ [![Build Status](https://github.com/activerecord-hackery/ransack/workflows/test/badge.svg)](https://github.com/activerecord-hackery/ransack/actions)
4
+ [![Gem Version](https://badge.fury.io/rb/ransack.svg)](http://badge.fury.io/rb/ransack)
5
+ [![Code Climate](https://codeclimate.com/github/activerecord-hackery/ransack/badges/gpa.svg)](https://codeclimate.com/github/activerecord-hackery/ransack)
6
+ [![Backers on Open Collective](https://opencollective.com/ransack/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/ransack/sponsors/badge.svg)](#sponsors)
7
+
8
+ # Introduction
9
+
10
+ Ransack will help you easily add **searching to your Rails application**, without any additional dependencies.
11
+
12
+ There are advanced searching solutions around, like ElasticSearch or Algolia. **Ransack** will do the job for many Rails websites, without the need to run additional infrastructure or work in a different language. With Ransack you do it all with standard Ruby and ERB.
13
+
14
+ Ready to move beyond the basics? Use **advanced features** like i18n and extensive configuration options.
15
+
16
+ Ransack is supported for Rails 8.0, 7.2 on Ruby 3.1 and later.
17
+
18
+ ## Installation
19
+
20
+ To install `ransack` and add it to your Gemfile, run
21
+
22
+ ```ruby title='Gemfile'
23
+ gem 'ransack'
24
+ ```
25
+
26
+ ### Bleeding edge
27
+
28
+ If you would like to use the latest updates not yet published to RubyGems, use the `main` branch:
29
+
30
+ ```ruby title='Gemfile'
31
+ gem 'ransack', :github => 'activerecord-hackery/ransack', :branch => 'main'
32
+ ```
33
+
34
+ ### Documentation
35
+
36
+ There is [extensive documentation on Ransack](https://activerecord-hackery.github.io/ransack/), which is a [Docusaurus](https://docusaurus.io/) project and run as a GitHub Pages site. Alternatively there is [AI Generated documentation](https://deepwiki.com/activerecord-hackery/ransack/1-overview) produced by [devin.ai](https://devin.ai/).
37
+
38
+ This [gist](https://gist.github.com/raghubetina/d5fc3df67ddbadcac271) has a quick-start cheatsheet, created by [@raghubetina](https://gist.github.com/raghubetina)
39
+
40
+ ## Issue tracker
41
+
42
+ * Before filing an issue, please read the [Contributing Guide](CONTRIBUTING.md).
43
+ * File an issue if a bug is caused by Ransack, is new (has not already been reported), and _can be reproduced from the information you provide_.
44
+ * Please consider creating a pull request with a failing test that demonstrates the problem.
45
+ * Contributions are welcome. :smiley:
46
+ * Please do not use the issue tracker for personal support requests. Stack Overflow or [GitHub Discussions](https://github.com/activerecord-hackery/ransack/discussions) is a better place for that where a wider community can help you!
47
+
48
+
49
+ ## Contributions
50
+
51
+ To support the project:
52
+
53
+ * Consider supporting us via [Open Collective](https://opencollective.com/ransack/backers/badge.svg)
54
+ * Use Ransack in your apps, and let us know if you encounter anything that's
55
+ broken or missing. A failing spec to demonstrate the issue is awesome. A pull
56
+ request with passing tests is even better!
57
+ * Before filing an issue or pull request, be sure to read and follow the
58
+ [Contributing Guide](CONTRIBUTING.md).
59
+ * Please use Stack Overflow or [GitHub Discussions](https://github.com/activerecord-hackery/ransack/discussions) for questions or discussion not
60
+ directly related to bug reports, pull requests, or documentation improvements.
61
+ * Spread the word on social media if Ransack's been useful
62
+ to you. The more people who are using the project, the quicker we can find and
63
+ fix bugs!
64
+
65
+ ## Contributors
66
+
67
+ Ransack was created by [Ernie Miller](http://twitter.com/erniemiller) and is developed and maintained by:
68
+ * [Sean Carroll](https://github.com/scarroll32)
69
+ * [Deivid Rodriguez](https://github.com/deivid-rodriguez)
70
+ * [Greg Molnar](https://github.com/gregmolnar)
71
+ * [A great group of contributors](https://github.com/activerecord-hackery/ransack/graphs/contributors).
72
+ - Ransack's logo is designed by [Anıl Kılıç](https://github.com/anilkilic).
73
+
74
+ Alumni Maintainers
75
+ - [Jon Atack](http://twitter.com/jonatack)
76
+ - [Ryan Bigg](http://twitter.com/ryanbigg)
77
+
78
+ This project exists thanks to all the people who contribute. <img src="https://opencollective.com/ransack/contributors.svg?width=890&button=false" />
79
+
80
+
81
+ ## Backers
82
+
83
+ Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/ransack#backer)]
84
+
85
+ <a href="https://opencollective.com/ransack#backers" target="_blank"><img src="https://opencollective.com/ransack/backers.svg?width=890" /></a>
86
+
87
+
88
+ ## Sponsors
89
+
90
+ Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/ransack#sponsor)]
91
+
92
+ <a href="https://opencollective.com/ransack/sponsor/0/website" target="_blank"><img src="https://opencollective.com/ransack/sponsor/0/avatar.svg" /></a>
93
+ <a href="https://opencollective.com/ransack/sponsor/1/website" target="_blank"><img src="https://opencollective.com/ransack/sponsor/1/avatar.svg" /></a>
94
+ <a href="https://opencollective.com/ransack/sponsor/2/website" target="_blank"><img src="https://opencollective.com/ransack/sponsor/2/avatar.svg" /></a>
95
+ <a href="https://opencollective.com/ransack/sponsor/3/website" target="_blank"><img src="https://opencollective.com/ransack/sponsor/3/avatar.svg" /></a>
96
+ <a href="https://opencollective.com/ransack/sponsor/4/website" target="_blank"><img src="https://opencollective.com/ransack/sponsor/4/avatar.svg" /></a>
97
+ <a href="https://opencollective.com/ransack/sponsor/5/website" target="_blank"><img src="https://opencollective.com/ransack/sponsor/5/avatar.svg" /></a>
98
+ <a href="https://opencollective.com/ransack/sponsor/6/website" target="_blank"><img src="https://opencollective.com/ransack/sponsor/6/avatar.svg" /></a>
99
+ <a href="https://opencollective.com/ransack/sponsor/7/website" target="_blank"><img src="https://opencollective.com/ransack/sponsor/7/avatar.svg" /></a>
100
+ <a href="https://opencollective.com/ransack/sponsor/8/website" target="_blank"><img src="https://opencollective.com/ransack/sponsor/8/avatar.svg" /></a>
101
+ <a href="https://opencollective.com/ransack/sponsor/9/website" target="_blank"><img src="https://opencollective.com/ransack/sponsor/9/avatar.svg" /></a>
@@ -0,0 +1,70 @@
1
+ module Polyamorous
2
+ module JoinAssociationExtensions
3
+ include SwappingReflectionClass
4
+ def self.prepended(base)
5
+ base.class_eval { attr_reader :join_type }
6
+ end
7
+
8
+ def initialize(reflection, children, polymorphic_class = nil, join_type = Arel::Nodes::InnerJoin)
9
+ @join_type = join_type
10
+ if polymorphic_class && ::ActiveRecord::Base > polymorphic_class
11
+ swapping_reflection_klass(reflection, polymorphic_class) do |reflection|
12
+ super(reflection, children)
13
+ self.reflection.options[:polymorphic] = true
14
+ end
15
+ else
16
+ super(reflection, children)
17
+ end
18
+ end
19
+
20
+ # Same as #join_constraints, but instead of constructing tables from the
21
+ # given block, uses the ones passed
22
+ def join_constraints_with_tables(foreign_table, foreign_klass, join_type, alias_tracker, tables)
23
+ joins = []
24
+ chain = []
25
+
26
+ reflection.chain.each.with_index do |reflection, i|
27
+ table = tables[i]
28
+
29
+ @table ||= table
30
+ chain << [reflection, table]
31
+ end
32
+
33
+ # The chain starts with the target table, but we want to end with it here (makes
34
+ # more sense in this context), so we reverse
35
+ chain.reverse_each do |reflection, table|
36
+ klass = reflection.klass
37
+
38
+ join_scope = reflection.join_scope(table, foreign_table, foreign_klass)
39
+
40
+ unless join_scope.references_values.empty?
41
+ join_dependency = join_scope.construct_join_dependency(
42
+ join_scope.eager_load_values | join_scope.includes_values, Arel::Nodes::OuterJoin
43
+ )
44
+ join_scope.joins!(join_dependency)
45
+ end
46
+
47
+ arel = join_scope.arel(alias_tracker.aliases)
48
+ nodes = arel.constraints.first
49
+
50
+ if nodes.is_a?(Arel::Nodes::And)
51
+ others = nodes.children.extract! do |node|
52
+ !Arel.fetch_attribute(node) { |attr| attr.relation.name == table.name }
53
+ end
54
+ end
55
+
56
+ joins << table.create_join(table, table.create_on(nodes), join_type)
57
+
58
+ if others && !others.empty?
59
+ joins.concat arel.join_sources
60
+ append_constraints(joins.last, others)
61
+ end
62
+
63
+ # The current table in this iteration becomes the foreign table in the next
64
+ foreign_table, foreign_klass = table, klass
65
+ end
66
+
67
+ joins
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,55 @@
1
+ module Polyamorous
2
+ module JoinAssociationExtensions
3
+ # Same as #join_constraints, but instead of constructing tables from the
4
+ # given block, uses the ones passed
5
+ def join_constraints_with_tables(foreign_table, foreign_klass, join_type, alias_tracker, tables)
6
+ joins = []
7
+ chain = []
8
+
9
+ reflection.chain.each.with_index do |reflection, i|
10
+ table = tables[i]
11
+
12
+ @table ||= table
13
+ chain << [reflection, table]
14
+ end
15
+
16
+ base_klass.with_connection do |connection|
17
+ # The chain starts with the target table, but we want to end with it here (makes
18
+ # more sense in this context), so we reverse
19
+ chain.reverse_each do |reflection, table|
20
+ klass = reflection.klass
21
+
22
+ join_scope = reflection.join_scope(table, foreign_table, foreign_klass)
23
+
24
+ unless join_scope.references_values.empty?
25
+ join_dependency = join_scope.construct_join_dependency(
26
+ join_scope.eager_load_values | join_scope.includes_values, Arel::Nodes::OuterJoin
27
+ )
28
+ join_scope.joins!(join_dependency)
29
+ end
30
+
31
+ arel = join_scope.arel(alias_tracker.aliases)
32
+ nodes = arel.constraints.first
33
+
34
+ if nodes.is_a?(Arel::Nodes::And)
35
+ others = nodes.children.extract! do |node|
36
+ !Arel.fetch_attribute(node) { |attr| attr.relation.name == table.name }
37
+ end
38
+ end
39
+
40
+ joins << table.create_join(table, table.create_on(nodes), join_type)
41
+
42
+ if others && !others.empty?
43
+ joins.concat arel.join_sources
44
+ append_constraints(connection, joins.last, others)
45
+ end
46
+
47
+ # The current table in this iteration becomes the foreign table in the next
48
+ foreign_table, foreign_klass = table, klass
49
+ end
50
+
51
+ joins
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,102 @@
1
+ module Polyamorous
2
+ module JoinDependencyExtensions
3
+ # Replaces ActiveRecord::Associations::JoinDependency#build
4
+ def build(associations, base_klass)
5
+ associations.map do |name, right|
6
+ if name.is_a? Join
7
+ reflection = find_reflection base_klass, name.name
8
+ reflection.check_validity!
9
+ reflection.check_eager_loadable!
10
+
11
+ klass = if reflection.polymorphic?
12
+ name.klass || base_klass
13
+ else
14
+ reflection.klass
15
+ end
16
+ JoinAssociation.new(reflection, build(right, klass), name.klass, name.type)
17
+ else
18
+ reflection = find_reflection base_klass, name
19
+ reflection.check_validity!
20
+ reflection.check_eager_loadable!
21
+
22
+ if reflection.polymorphic?
23
+ raise ActiveRecord::EagerLoadPolymorphicError.new(reflection)
24
+ end
25
+ JoinAssociation.new(reflection, build(right, reflection.klass))
26
+ end
27
+ end
28
+ end
29
+
30
+ def join_constraints(joins_to_add, alias_tracker, references)
31
+ @alias_tracker = alias_tracker
32
+ @joined_tables = {}
33
+ @references = {}
34
+
35
+ references.each do |table_name|
36
+ @references[table_name.to_sym] = table_name if table_name.is_a?(String)
37
+ end
38
+
39
+ joins = make_join_constraints(join_root, join_type)
40
+
41
+ joins.concat joins_to_add.flat_map { |oj|
42
+ if join_root.match?(oj.join_root) && join_root.table.name == oj.join_root.table.name
43
+ walk join_root, oj.join_root, oj.join_type
44
+ else
45
+ make_join_constraints(oj.join_root, oj.join_type)
46
+ end
47
+ }
48
+ end
49
+
50
+ def construct_tables_for_association!(join_root, association)
51
+ tables = table_aliases_for(join_root, association)
52
+ association.table = tables.first
53
+ tables
54
+ end
55
+
56
+ private
57
+
58
+ def table_aliases_for(parent, node)
59
+ @joined_tables ||= {}
60
+ node.reflection.chain.map { |reflection|
61
+ table, terminated = @joined_tables[reflection]
62
+ root = reflection == node.reflection
63
+
64
+ if table && (!root || !terminated)
65
+ @joined_tables[reflection] = [table, true] if root
66
+ table
67
+ else
68
+ table = alias_tracker.aliased_table_for(reflection.klass.arel_table) do
69
+ name = reflection.alias_candidate(parent.table_name)
70
+ root ? name : "#{name}_join"
71
+ end
72
+ @joined_tables[reflection] ||= [table, root] if join_type == Arel::Nodes::OuterJoin
73
+ table
74
+ end
75
+ }
76
+ end
77
+
78
+ module ClassMethods
79
+ # Prepended before ActiveRecord::Associations::JoinDependency#walk_tree
80
+ #
81
+ def walk_tree(associations, hash)
82
+ case associations
83
+ when TreeNode
84
+ associations.add_to_tree(hash)
85
+ when Hash
86
+ associations.each do |k, v|
87
+ cache =
88
+ if TreeNode === k
89
+ k.add_to_tree(hash)
90
+ else
91
+ hash[k] ||= {}
92
+ end
93
+ walk_tree(v, cache)
94
+ end
95
+ else
96
+ super(associations, hash)
97
+ end
98
+ end
99
+ end
100
+
101
+ end
102
+ end
@@ -0,0 +1,11 @@
1
+ module Polyamorous
2
+ module ReflectionExtensions
3
+ def join_scope(table, foreign_table, foreign_klass)
4
+ if respond_to?(:polymorphic?) && polymorphic?
5
+ super.where!(foreign_table[foreign_type].eq(klass.name))
6
+ else
7
+ super
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,70 @@
1
+ module Polyamorous
2
+ class Join
3
+ include TreeNode
4
+
5
+ attr_accessor :name
6
+ attr_reader :type, :klass
7
+
8
+ def initialize(name, type = InnerJoin, klass = nil)
9
+ @name = name
10
+ @type = convert_to_arel_join_type(type)
11
+ @klass = convert_to_class(klass) if klass
12
+ end
13
+
14
+ def klass=(klass)
15
+ @klass = convert_to_class(klass) if klass
16
+ end
17
+
18
+ def type=(type)
19
+ @type = convert_to_arel_join_type(type) if type
20
+ end
21
+
22
+ def hash
23
+ [@name, @type, @klass].hash
24
+ end
25
+
26
+ def eql?(other)
27
+ self.class == other.class &&
28
+ self.name == other.name &&
29
+ self.type == other.type &&
30
+ self.klass == other.klass
31
+ end
32
+
33
+ alias :== :eql?
34
+
35
+ def add_to_tree(hash)
36
+ hash[self] ||= {}
37
+ end
38
+
39
+ private
40
+
41
+ def convert_to_arel_join_type(type)
42
+ case type
43
+ when 'inner', :inner
44
+ InnerJoin
45
+ when 'outer', :outer
46
+ OuterJoin
47
+ when Class
48
+ if [InnerJoin, OuterJoin].include? type
49
+ type
50
+ else
51
+ raise ArgumentError, "#{type} cannot be converted to an ARel join type"
52
+ end
53
+ else
54
+ raise ArgumentError, "#{type} cannot be converted to an ARel join type"
55
+ end
56
+ end
57
+
58
+ def convert_to_class(value)
59
+ case value
60
+ when String, Symbol
61
+ Kernel.const_get(value)
62
+ when Class
63
+ value
64
+ else
65
+ raise ArgumentError, "#{value} cannot be converted to a Class"
66
+ end
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,27 @@
1
+ ActiveSupport.on_load(:active_record) do
2
+ module Polyamorous
3
+ InnerJoin = Arel::Nodes::InnerJoin
4
+ OuterJoin = Arel::Nodes::OuterJoin
5
+
6
+ JoinDependency = ::ActiveRecord::Associations::JoinDependency
7
+ JoinAssociation = ::ActiveRecord::Associations::JoinDependency::JoinAssociation
8
+ end
9
+
10
+ require 'polyamorous/tree_node'
11
+ require 'polyamorous/join'
12
+ require 'polyamorous/swapping_reflection_class'
13
+
14
+ require 'polyamorous/activerecord/join_association'
15
+ require 'polyamorous/activerecord/join_dependency'
16
+ require 'polyamorous/activerecord/reflection'
17
+
18
+ if ::ActiveRecord.version >= ::Gem::Version.new("7.2") && ::ActiveRecord.version < ::Gem::Version.new("7.2.2.1")
19
+ require "polyamorous/activerecord/join_association_7_2"
20
+ end
21
+
22
+ ActiveRecord::Reflection::AbstractReflection.send(:prepend, Polyamorous::ReflectionExtensions)
23
+
24
+ Polyamorous::JoinDependency.send(:prepend, Polyamorous::JoinDependencyExtensions)
25
+ Polyamorous::JoinDependency.singleton_class.send(:prepend, Polyamorous::JoinDependencyExtensions::ClassMethods)
26
+ Polyamorous::JoinAssociation.send(:prepend, Polyamorous::JoinAssociationExtensions)
27
+ end
@@ -0,0 +1,11 @@
1
+ module Polyamorous
2
+ module SwappingReflectionClass
3
+ def swapping_reflection_klass(reflection, klass)
4
+ new_reflection = reflection.clone
5
+ new_reflection.instance_variable_set(:@options, reflection.options.clone)
6
+ new_reflection.options.delete(:polymorphic)
7
+ new_reflection.instance_variable_set(:@klass, klass)
8
+ yield new_reflection
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ module Polyamorous
2
+ module TreeNode
3
+ def add_to_tree(hash)
4
+ raise NotImplementedError
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,14 @@
1
+ require 'ransack/adapters/active_record/base'
2
+
3
+ ActiveSupport.on_load(:active_record) do
4
+ extend Ransack::Adapters::ActiveRecord::Base
5
+
6
+ Ransack::SUPPORTS_ATTRIBUTE_ALIAS =
7
+ begin
8
+ ActiveRecord::Base.respond_to?(:attribute_aliases)
9
+ rescue NameError
10
+ false
11
+ end
12
+ end
13
+
14
+ require 'ransack/adapters/active_record/context'
@@ -0,0 +1,152 @@
1
+ module Ransack
2
+ module Adapters
3
+ module ActiveRecord
4
+ module Base
5
+
6
+ def self.extended(base)
7
+ base.class_eval do
8
+ class_attribute :_ransackers
9
+ class_attribute :_ransack_aliases
10
+ self._ransackers ||= {}
11
+ self._ransack_aliases ||= {}
12
+ end
13
+ end
14
+
15
+ def ransack(params = {}, options = {})
16
+ Search.new(self, params, options)
17
+ end
18
+
19
+ def ransack!(params = {}, options = {})
20
+ ransack(params, options.merge(ignore_unknown_conditions: false))
21
+ end
22
+
23
+ def ransacker(name, opts = {}, &block)
24
+ self._ransackers = _ransackers.merge name.to_s => Ransacker
25
+ .new(self, name, opts, &block)
26
+ end
27
+
28
+ def ransack_alias(new_name, old_name)
29
+ self._ransack_aliases = _ransack_aliases.merge new_name.to_s =>
30
+ old_name.to_s
31
+ end
32
+
33
+ # Ransackable_attributes, by default, returns all column names
34
+ # and any defined ransackers as an array of strings.
35
+ # For overriding with a whitelist array of strings.
36
+ #
37
+ def ransackable_attributes(auth_object = nil)
38
+ @ransackable_attributes ||= deprecated_ransackable_list(:ransackable_attributes)
39
+ end
40
+
41
+ # Ransackable_associations, by default, returns the names
42
+ # of all associations as an array of strings.
43
+ # For overriding with a whitelist array of strings.
44
+ #
45
+ def ransackable_associations(auth_object = nil)
46
+ @ransackable_associations ||= deprecated_ransackable_list(:ransackable_associations)
47
+ end
48
+
49
+ # Ransortable_attributes, by default, returns the names
50
+ # of all attributes available for sorting as an array of strings.
51
+ # For overriding with a whitelist array of strings.
52
+ #
53
+ def ransortable_attributes(auth_object = nil)
54
+ ransackable_attributes(auth_object)
55
+ end
56
+
57
+ # Ransackable_scopes, by default, returns an empty array
58
+ # i.e. no class methods/scopes are authorized.
59
+ # For overriding with a whitelist array of *symbols*.
60
+ #
61
+ def ransackable_scopes(auth_object = nil)
62
+ []
63
+ end
64
+
65
+ # ransack_scope_skip_sanitize_args, by default, returns an empty array.
66
+ # i.e. use the sanitize_scope_args setting to determine if args should be converted.
67
+ # For overriding with a list of scopes which should be passed the args as-is.
68
+ #
69
+ def ransackable_scopes_skip_sanitize_args
70
+ []
71
+ end
72
+
73
+ # Bare list of all potentially searchable attributes. Searchable attributes
74
+ # need to be explicitly allowlisted through the `ransackable_attributes`
75
+ # method in each model, but if you're allowing almost everything to be
76
+ # searched, this list can be used as a base for exclusions.
77
+ #
78
+ def authorizable_ransackable_attributes
79
+ if Ransack::SUPPORTS_ATTRIBUTE_ALIAS
80
+ column_names + _ransackers.keys + _ransack_aliases.keys +
81
+ attribute_aliases.keys
82
+ else
83
+ column_names + _ransackers.keys + _ransack_aliases.keys
84
+ end.uniq
85
+ end
86
+
87
+ # Bare list of all potentially searchable associations. Searchable
88
+ # associations need to be explicitly allowlisted through the
89
+ # `ransackable_associations` method in each model, but if you're
90
+ # allowing almost everything to be searched, this list can be used as a
91
+ # base for exclusions.
92
+ #
93
+ def authorizable_ransackable_associations
94
+ reflect_on_all_associations.map { |a| a.name.to_s }
95
+ end
96
+
97
+ private
98
+
99
+ def deprecated_ransackable_list(method)
100
+ list_type = method.to_s.delete_prefix("ransackable_")
101
+
102
+ if explicitly_defined?(method)
103
+ warn_deprecated <<~ERROR
104
+ Ransack's builtin `#{method}` method is deprecated and will result
105
+ in an error in the future. If you want to authorize the full list
106
+ of searchable #{list_type} for this model, use
107
+ `authorizable_#{method}` instead of delegating to `super`.
108
+ ERROR
109
+
110
+ public_send("authorizable_#{method}")
111
+ else
112
+ raise <<~MESSAGE
113
+ Ransack needs #{name} #{list_type} explicitly allowlisted as
114
+ searchable. Define a `#{method}` class method in your `#{name}`
115
+ model, watching out for items you DON'T want searchable (for
116
+ example, `encrypted_password`, `password_reset_token`, `owner` or
117
+ other sensitive information). You can use the following as a base:
118
+
119
+ ```ruby
120
+ class #{name} < ApplicationRecord
121
+
122
+ # ...
123
+
124
+ def self.#{method}(auth_object = nil)
125
+ #{public_send("authorizable_#{method}").sort.inspect}
126
+ end
127
+
128
+ # ...
129
+
130
+ end
131
+ ```
132
+ MESSAGE
133
+ end
134
+ end
135
+
136
+ def explicitly_defined?(method)
137
+ definer_ancestor = singleton_class.ancestors.find do |ancestor|
138
+ ancestor.instance_methods(false).include?(method)
139
+ end
140
+
141
+ definer_ancestor != Ransack::Adapters::ActiveRecord::Base
142
+ end
143
+
144
+ def warn_deprecated(message)
145
+ caller_location = caller_locations.find { |location| !location.path.start_with?(File.expand_path("../..", __dir__)) }
146
+
147
+ warn "DEPRECATION WARNING: #{message.squish} (called at #{caller_location.path}:#{caller_location.lineno})"
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end