Skip to content

fix: Fix proposal order issue on "recent" - #1008

Merged
moustachu merged 3 commits into
developfrom
fix/proposals_order_ids
Jul 24, 2026
Merged

fix: Fix proposal order issue on "recent"#1008
moustachu merged 3 commits into
developfrom
fix/proposals_order_ids

Conversation

@AyakorK

@AyakorK AyakorK commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

🎩 Description

Fixes unstable/incorrect sort order on the public proposals index (?order=recent, az, za, etc.), which caused old proposals to sometimes appear ahead of much more recent ones.

Two separate bugs, both fixed:

  1. The final re-ordering step in proposals_controller_extends.rb used position(id::text in '...') to preserve sort order after pagination. Since that's a plain substring match, a short ID (e.g. 133) that's a substring of a longer, more recent ID (e.g. 2133) gets sorted next to it, regardless of actual date. Replaced with array_position(...), which matches IDs exactly instead of as text.
  2. None of the sort options (recent, most_voted, az, etc.) had a tie-breaker. When several proposals tie on the sorted column (same published_at from an import, several proposals with 0 votes, etc.), Postgres falls back to physical row order, which isn't stable. Added .order(id: :desc) as a tie-breaker via a prepended reorder.

Also found along the way: our ProposalsControllerExtends override was being silently overwritten on every request by decidim_awesome's MemoizeExtraFields concern. Switched it from include to prepend to fix that.

Testing

In rails console, on a Proposals component:

component = Decidim::Component.find(YOUR_COMPONENT_ID)

ActiveRecord::Base.connection.execute("SELECT setval('decidim_proposals_proposals_id_seq', 89)")
short_old = Decidim::Proposals::Proposal.new(component: component, title: { "en" => "AAA short old id" }, body: { "en" => "test" })
short_old.save!(validate: false)
short_old.update_columns(created_at: "2021-01-01".to_time, published_at: "2021-01-01".to_time)

ActiveRecord::Base.connection.execute("SELECT setval('decidim_proposals_proposals_id_seq', 899)")
long_recent = Decidim::Proposals::Proposal.new(component: component, title: { "en" => "ZZZ long recent id" }, body: { "en" => "test" })
long_recent.save!(validate: false)
long_recent.update_columns(created_at: Time.current, published_at: Time.current)

import_time = 3.years.ago
5.times do |i|
  p = Decidim::Proposals::Proposal.new(component: component, title: { "en" => "Tied import #{i}" }, body: { "en" => "test" })
  p.save!(validate: false)
  p.update_columns(created_at: import_time, published_at: import_time)
end

Expected, on /proposals?order=recent:

  • Sort is chronological: "ZZZ long recent id" on top, "AAA short old id" near the bottom with the other 2021-dated content.
  • Reloading the page repeatedly keeps the "Tied import" proposals in the same order every time.

Also check /proposals?order=az for tied/duplicate titles — order should stay stable across reloads.

📌 Related Issues

Tasks

  • Fix proposals controller extends
  • Add new extends that adds a tie-breaker to the reorder method for all sort options

@AyakorK
AyakorK marked this pull request as ready for review July 21, 2026 11:48
@AyakorK
AyakorK requested a review from moustachu July 21, 2026 11:48
@moustachu
moustachu merged commit e0835cb into develop Jul 24, 2026
8 checks passed
@moustachu
moustachu deleted the fix/proposals_order_ids branch July 24, 2026 08:51
moustachu added a commit that referenced this pull request Jul 24, 2026
* fix: Fix proposal order when ids are multi-matching (133 -> 1133)

* fix: Test failing

---------

Co-authored-by: moustachu <moustachu@opensourcepolitics.eu>
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.

2 participants