Skip to content

Conversation

@ragingdave
Copy link
Collaborator

@ragingdave ragingdave commented Jun 11, 2024

Summary by CodeRabbit

  • New Features
    • Expanded compatibility: supports Ruby 2.7.8+ and Rails 4.2+.
  • Bug Fixes
    • Improved stability and consistency of positioning behavior across supported Rails versions.
  • Dependencies
    • Adjusted gem requirements, including lowering ActiveSupport/ActiveRecord minimums and updating database adapter constraints (e.g., PostgreSQL pg < 1.0).
  • Tests
    • Updated test suite for cross-version compatibility and enabled SQL logging during tests.
  • Chores
    • Simplified CI matrix to a narrower set of environments for faster, more focused builds.

@coderabbitai
Copy link

coderabbitai bot commented Sep 4, 2025

📝 Walkthrough

Walkthrough

Broad downgrades for legacy compatibility: CI matrix narrowed to Ruby 2.7.8, Rails ~> 4.2, Postgres only. Gemspec and Gemfile dependency constraints reduced. Core positioning logic adjusted for older AR/Rails APIs (selection, change tracking, range queries). Tests updated for compatibility and logging enabled.

Changes

Cohort / File(s) Summary
CI workflow
\.github/workflows/main.yml
Matrix reduced to Ruby 2.7.8, Rails ~> 4.2, DB=postgresql; removed excludes; added env sourcing from matrix.
Dependencies
Gemfile, positioning.gemspec
Postgres gem pinned to < 1.0. Required Ruby lowered to >= 2.7.8. activesupport/activerecord lowered to >= 4.2. Added several development deps (bigdecimal, minitest-hooks, mocha, mysql2, pg, sqlite3).
Positioning core (compat fixes)
lib/positioning.rb, lib/positioning/healer.rb, lib/positioning/mechanisms.rb
Enforce base-class check via base_class == self. Reordered attribute change notification after super. Replaced reselect with unscope(:select).select(...). Replaced pick with limit(1).pluck(...).first. Adjusted range conditions and where syntax for older AR. Removed a memoization call in move_out_of_the_way.
Test models
test/models/category.rb, test/models/post.rb
Removed optional: true from belongs_to associations.
Test support
test/support/active_record.rb
Enabled SQL logging to stdout.
Test suite adjustments
test/test_positioning.rb
Replaced pick with limit(1).pluck(...).first, pluck-based pair extraction with map, chained where for SQL expectations, updated change-detection to previous_changes.include?, added compatibility comments and a temporary explicit string position; includes a stray debug puts.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (6)
test/support/active_record.rb (1)

115-115: Make SQL logging opt-in to keep CI output and runtime lean.

Always-on SQL logs can drown CI; gate via env.

Apply:

-ActiveRecord::Base.logger = ActiveSupport::Logger.new($stdout)
+if ENV["SQL_LOG"] == "1"
+  logger = ActiveSupport::Logger.new($stdout)
+  logger.level = Logger::INFO
+  ActiveRecord::Base.logger = logger
+end
positioning.gemspec (1)

31-38: Alphabetize runtime deps (and optionally dev deps) to satisfy Gemspec/OrderedDependencies.

Minor style nit: place activerecord before activesupport. The diff above covers runtime deps; consider alphabetizing dev deps as well if you keep expanding this list.

lib/positioning.rb (1)

50-53: Setter dirty tracking: consider dropping the explicit will_change!.

After super(position), Rails’ writer already marks the attribute dirty when the value changes. Calling will_change! post-assignment can record an incorrect “was” value in some versions and is likely unnecessary now that retrieval uses pluck. Simplify:

-            # Flipped order here to make rails 4 happy
-            super(position)
-            send :"#{column}_will_change!"
+            # Rely on default writer for dirty tracking (Rails 4–7)
+            super(position)

If you still need explicit dirty marking for edge cases, guard it with a version check and call it before assignment only where required.

lib/positioning/mechanisms.rb (2)

112-119: Prefer Arel over string SQL; also quiets Brakeman.

Build predicates with Arel and wrap update_all expressions with Arel.sql to make intent explicit and reduce false positives.

Apply this diff:

-      if range.end.nil? # This branch for rails < 6
-        scope.where("#{quoted_column} >= ?", range.begin).update_all "#{quoted_column} = #{quoted_column} * -1"
-      else
-        scope.where("#{@column}": range).update_all "#{quoted_column} = #{quoted_column} * -1"
-      end
-
-      scope.where("#{quoted_column} <= ?", -1).update_all "#{quoted_column} = #{quoted_column} * -1 + 1"
+      arel_col = base_class.arel_table[@column]
+      if range.end.nil? # rails < 6 (endless range)
+        scope.where(arel_col.gteq(range.begin)).update_all Arel.sql("#{quoted_column} = #{quoted_column} * -1")
+      else
+        scope.where(@column => range).update_all Arel.sql("#{quoted_column} = #{quoted_column} * -1")
+      end
+
+      scope.where(arel_col.lteq(-1)).update_all Arel.sql("#{quoted_column} = #{quoted_column} * -1 + 1")

122-131: Mirror the Arel refactor in contract.

Keep both paths consistent and scanner-friendly.

Apply this diff:

-      if range.end.nil? # This branch for rails < 6
-        scope.where("#{quoted_column} >= ?", range.begin).update_all "#{quoted_column} = #{quoted_column} * -1"
-      else
-        scope.where("#{@column}": range).update_all "#{quoted_column} = #{quoted_column} * -1"
-      end
-
-      scope.where("#{quoted_column} <= ?", -1).update_all "#{quoted_column} = #{quoted_column} * -1 - 1"
+      arel_col = base_class.arel_table[@column]
+      if range.end.nil? # rails < 6 (endless range)
+        scope.where(arel_col.gteq(range.begin)).update_all Arel.sql("#{quoted_column} = #{quoted_column} * -1")
+      else
+        scope.where(@column => range).update_all Arel.sql("#{quoted_column} = #{quoted_column} * -1")
+      end
+
+      scope.where(arel_col.lteq(-1)).update_all Arel.sql("#{quoted_column} = #{quoted_column} * -1 - 1")
test/test_positioning.rb (1)

1490-1491: Stabilize equality assertions across AR versions.

Relation equality can vary; compare arrays to avoid surprises.

Apply this diff:

-          assert_equal list.authors, models # TODO: if broken, add to_a for older rails
-          assert_equal other_list.authors, other_models  # TODO: if broken, add to_a for older rails
+          assert_equal list.authors.to_a, models
+          assert_equal other_list.authors.to_a, other_models
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2a8766e and 6ea74fb.

📒 Files selected for processing (10)
  • .github/workflows/main.yml (1 hunks)
  • Gemfile (1 hunks)
  • lib/positioning.rb (2 hunks)
  • lib/positioning/healer.rb (1 hunks)
  • lib/positioning/mechanisms.rb (3 hunks)
  • positioning.gemspec (2 hunks)
  • test/models/category.rb (1 hunks)
  • test/models/post.rb (1 hunks)
  • test/support/active_record.rb (1 hunks)
  • test/test_positioning.rb (7 hunks)
🧰 Additional context used
🪛 RuboCop (1.76.1)
positioning.gemspec

[convention] 32-32: Dependencies should be sorted in an alphabetical order within their section of the gemspec. Dependency activerecord should appear before activesupport.

(Gemspec/OrderedDependencies)

🪛 ast-grep (0.38.6)
lib/positioning/mechanisms.rb

[warning] 112-112: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: scope.where("#{quoted_column} >= ?", range.begin)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html

(hardcoded-secret-rsa-passphrase-ruby)


[warning] 125-125: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: scope.where("#{quoted_column} >= ?", range.begin)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html

(hardcoded-secret-rsa-passphrase-ruby)

🪛 Brakeman (7.0.2)
lib/positioning/mechanisms.rb

[weak] 118-118: Possible SQL injection
Type: SQL Injection
Confidence: Weak
More info: https://brakemanscanner.org/docs/warning_types/sql_injection/

(SQL Injection)


[weak] 128-128: Possible SQL injection
Type: SQL Injection
Confidence: Weak
More info: https://brakemanscanner.org/docs/warning_types/sql_injection/

(SQL Injection)


[weak] 113-113: Possible SQL injection
Type: SQL Injection
Confidence: Weak
More info: https://brakemanscanner.org/docs/warning_types/sql_injection/

(SQL Injection)


[weak] 115-115: Possible SQL injection
Type: SQL Injection
Confidence: Weak
More info: https://brakemanscanner.org/docs/warning_types/sql_injection/

(SQL Injection)


[weak] 131-131: Possible SQL injection
Type: SQL Injection
Confidence: Weak
More info: https://brakemanscanner.org/docs/warning_types/sql_injection/

(SQL Injection)


[weak] 126-126: Possible SQL injection
Type: SQL Injection
Confidence: Weak
More info: https://brakemanscanner.org/docs/warning_types/sql_injection/

(SQL Injection)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Ruby 2.7.8, DB postgresql, Rails ~> 4.2.0
🔇 Additional comments (14)
.github/workflows/main.yml (1)

18-20: Verify Rails 4.2 on Ruby 2.7 in ubuntu-latest; consider pinning Postgres.
Rails 4.2 on Ruby 2.7 can be brittle and GitHub’s ubuntu-latest image may ship varying libpq versions. Manually confirm on a fresh runner by installing Bundler and running

gem install bundler  
bundle install --jobs=3 --retry=3  
bundle exec rake -T  

If you see intermittent failures, add a Postgres service container (e.g., postgres:12) to lock in headers/libs.

test/models/post.rb (1)

2-2: LGTM: removal of optional: true is necessary for Rails 4.2 compatibility.

Ensure fixtures/factories always provide a Blog when creating Post records under this suite.

test/models/category.rb (1)

2-2: LGTM: aligns association API with Rails 4.2 (no optional: keyword).

Double-check any tests that relied on parent being nil to avoid unintended validation assumptions.

lib/positioning/healer.rb (1)

11-12: Reselect → unscope+select+distinct looks correct; confirm AR 4.2 method coverage and no behavior drift.

  • Semantics match the intent of reselect while remaining Rails 4–safe. Dropping order via unscope(:order) is fine here since grouping by distinct doesn’t rely on ordering.
  • Please verify on AR 4.2 that:
    • Relation#unscope(:select) and Relation#distinct are present,
    • ActiveRecord::Base#slice is available (used later to build the where hash),
    • Relation#lock! behaves as expected in your target versions (Rails typically uses lock on relations and lock! on records).

Would you like a small script to assert these capabilities against your CI matrix?

positioning.gemspec (2)

12-12: Ruby 2.7.8 × Rails 4.2 compatibility risks—please validate.

Rails 4.2 predates Ruby 2.7 and may hit keyword-argument and BigDecimal changes. Ensure your CI truly runs Rails 4.2 on Ruby 2.7.8 without patch gems.

I can provide a quick script to print RUBY_VERSION, ActiveRecord::VERSION::STRING, and run a smoke query if helpful.


33-38: Recheck dev dependency versions for Ruby 2.7.

  • bigdecimal "~> 1.4.0" may conflict with Ruby 2.7’s stdlib BigDecimal (2.x). You may not need this pin on 2.7.
  • pg "< 1.0": OK for Rails 4.2; consider narrowing to a known-good (e.g., "~> 0.21") if CI confirms.
  • sqlite3 "~> 1.7.2": compatible with Ruby 2.7, but Rails 4.2 historically paired with older sqlite3; confirm test matrix is green.

If you want, I’ll generate a Gemfile.lock sanity script to assert resolution on Ruby 2.7.8 across adapters.

lib/positioning.rb (1)

22-23: Base class guard is Rails 4–safe.

unless base_class == self correctly mirrors base_class? for older Rails.

lib/positioning/mechanisms.rb (2)

100-101: Compat: pick → limit(1).pluck(...).first is fine.

Good fallback for AR 4.x without behavior change.


176-176: Compat: pluck-first for relative record is OK.

Matches the position_was change and remains efficient.

test/test_positioning.rb (5)

106-107: Using map for cross-AR compatibility is fine.

Slightly more object work, but OK in tests.


225-225: Compat: limit(1).pluck(...).first is fine.

Aligns with library change.


515-515: Chained where for deterministic SQL shape.

Good for stable to_sql assertions across AR versions.


525-528: Explicit where chaining: good.

Makes the expected SQL order obvious.


1565-1565: previous_changes.include?(:list_id) is a reasonable cross-version check.

Works on AR 4.x+. LGTM.

end
when "postgresql"
gem "pg", "~> 1.5.5"
gem "pg", "< 1.0" # Decreased to enable compatibility
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Tighten pg constraint; '< 1.0' is too broad and risky on Ruby 2.7/modern libpq.

Pin to a known Rails 4.2-compatible minor (e.g., 0.21.x) to avoid surprise downgrades, build issues, or security regressions. Consider gating by RAILS_VERSION if you plan to support newer Rails in other matrices later.

Proposed change:

-  gem "pg", "< 1.0" # Decreased to enable compatibility
+  gem "pg", "~> 0.21.0" # Rails 4.2 compatibility; stable on common CI images

Quick check script to validate availability and Ruby requirement metadata:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
curl -s https://rubygems.org/api/v1/versions/pg.json \
| jq -r '[.[] | select(.number=="0.21.0")][0] | {version:.number, ruby_version}'

Length of output: 216


Fix pg version constraint for Ruby 2.7 compatibility. (Gemfile:28) Version 0.21.0 declares a Ruby requirement of “>= 2.0 and < 2.5,” so pinning ~> 0.21.0 will fail under Ruby 2.7. Gate the 0.21.x constraint by Ruby or Rails version (e.g. only for Ruby < 2.5 or Rails 4.2) and allow pg >= 1.0 for Ruby >= 2.5.

🤖 Prompt for AI Agents
In Gemfile around line 28, the current pin "pg", "< 1.0" breaks Ruby 2.7 because
pg 0.21.x requires Ruby < 2.5; change the declaration to gate the 0.21.x
constraint to older Rubies/Rails and allow pg >= 1.0 for newer runtimes.
Concretely, detect Ruby (or Rails) version in the Gemfile (e.g. if RUBY_VERSION
< "2.5" or if Rails.version starts_with?("4.2")), then add the legacy pin for
"~> 0.21.0" (or "< 1.0") inside that conditional, otherwise declare "pg", ">=
1.0"; keep only one gem declaration active so Bundler picks the compatible pg
for the running Ruby/Rails.

Comment on lines +31 to +32
spec.add_dependency "activesupport", ">= 4.2" # Decreased to enable compatibility
spec.add_dependency "activerecord", ">= 4.2" # Decreased to enable compatibility
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add upper bounds to Rails deps to prevent accidental installs on unsupported Rails versions.

Given the PR targets Rails ~> 4.2, leave headroom but cap major upgrades. Example below also satisfies the “ordered dependencies” RuboCop hint.

Apply:

-  spec.add_dependency "activesupport", ">= 4.2" # Decreased to enable compatibility
-  spec.add_dependency "activerecord", ">= 4.2" # Decreased to enable compatibility
+  spec.add_dependency "activerecord", ">= 4.2", "< 5.0" # Rails 4.x only
+  spec.add_dependency "activesupport", ">= 4.2", "< 5.0"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
spec.add_dependency "activesupport", ">= 4.2" # Decreased to enable compatibility
spec.add_dependency "activerecord", ">= 4.2" # Decreased to enable compatibility
spec.add_dependency "activerecord", ">= 4.2", "< 5.0" # Rails 4.x only
spec.add_dependency "activesupport", ">= 4.2", "< 5.0"
🧰 Tools
🪛 RuboCop (1.76.1)

[convention] 32-32: Dependencies should be sorted in an alphabetical order within their section of the gemspec. Dependency activerecord should appear before activesupport.

(Gemspec/OrderedDependencies)

🤖 Prompt for AI Agents
In positioning.gemspec around lines 31-32, the Rails dependencies lack upper
bounds and may allow installs on unsupported major Rails versions; change
spec.add_dependency "activesupport", ">= 4.2" and spec.add_dependency
"activerecord", ">= 4.2" to include an upper bound like ">= 4.2", "< 5.0" for
each, and reorder the dependency lines alphabetically (activerecord before
activesupport) to satisfy the RuboCop ordered-dependencies hint.

Comment on lines +810 to 812
puts "THIS ONE"
@second_item.update list: @second_list, position: " 2" # NOTE: The same position it already had; adding hack to ensure rails sees this as a change remove when rails detects it right again
@third_item.update list: @second_list, position: 1
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Remove debug output and avoid string “hack” in tests.

  • Drop puts to keep CI noise-free.
  • Prefer fixing dirty-tracking in the setter over relying on " 2" to coerce a change.

Apply this diff in the test:

-    puts "THIS ONE"
-    @second_item.update list: @second_list, position: " 2" # NOTE: The same position it already had; adding hack to ensure rails sees this as a change remove when rails detects it right again
+    @second_item.update list: @second_list, position: 2

If this fails on older AR due to change tracking, consider adjusting the library setter to mark the attribute dirty before write (so the test can stay clean). For example (outside this file):

# lib/positioning.rb (example)
def #{column}=(value)
  attribute_will_change! :#{column} # call before assignment for AR 4.x
  super(value)
end

To confirm no stray debug prints remain:


🏁 Script executed:

#!/bin/bash
rg -nP '^\s*puts\s+' --type rb

Length of output: 59


To verify that no stray puts debug statements remain, rerun the search with proper file-type matching:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# Search all Ruby files for debug output using 'puts'
rg -n '^\s*puts ' -g '*.rb'

Length of output: 98


Remove debug output and string “hack” in the test

--- test/test_positioning.rb
+++ test/test_positioning.rb
@@ -810,3 +810,3 @@
-    puts "THIS ONE"
-    @second_item.update list: @second_list, position: " 2" # hack to force dirty-tracking
+    @second_item.update list: @second_list, position: 2

Run the full test suite to ensure no failures. If this change breaks under older ActiveRecord versions (due to dirty-tracking), consider marking the attribute dirty in the setter (e.g., calling attribute_will_change! before assignment).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
puts "THIS ONE"
@second_item.update list: @second_list, position: " 2" # NOTE: The same position it already had; adding hack to ensure rails sees this as a change remove when rails detects it right again
@third_item.update list: @second_list, position: 1
@second_item.update list: @second_list, position: 2
@third_item.update list: @second_list, position: 1
🤖 Prompt for AI Agents
In test/test_positioning.rb around lines 810 to 812, remove the debug puts "THIS
ONE" and replace the string-hack update (@second_item.update list: @second_list,
position: " 2") with a normal numeric assignment matching intent (e.g.,
position: 2), then run the full test suite; if tests fail on older ActiveRecord
due to dirty-tracking, update the model setter to call attribute_will_change!
(or the equivalent) before assigning the position so AR detects the change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants