summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-06-26 05:19:28 +0200
committererdgeist <erdgeist@erdgeist.org>2026-06-26 05:19:28 +0200
commita1ddc25da0d2aa79a4d9216ef7792f26233bd38e (patch)
tree4d53e6ccb631e588c9e1d25c7a2dc5ef2ef44135
parentfa0ccc43010297c0c10e3075095c0a9171989498 (diff)
Stage 5 fixes: RouteWithParams removal, Globalize fallbacks, search stub, to_s(:db) → to_fs(:db), LockedByAnotherUser autoload, test environment config
- Remove safe_path helper and content_path shim from link_helper.rb - Update all safe_path call sites in views to use named route helpers directly - Fix Globalize fallbacks via config.i18n.fallbacks in application.rb, remove i18n initializer - Stub Node.search returning none (search disabled pending PostgreSQL upgrade) - Replace to_s(:db) with to_fs(:db) in node.rb, nodes_helper.rb, link_helper.rb, admin view - Move LockedByAnotherUser to app/models/locked_by_another_user.rb for Zeitwerk autoloading - Fix config/environments/test.rb: config.assets removed, cache_classes → enable_reloading, test_order removed, minitest pinned to ~> 5.25 - Fix config/environments/development.rb: cache_classes → enable_reloading - Park search vector migration in doc/ pending PostgreSQL and plpgsql availability
-rw-r--r--Gemfile1
-rw-r--r--Gemfile.lock7
-rw-r--r--app/helpers/link_helper.rb35
-rw-r--r--app/helpers/nodes_helper.rb2
-rw-r--r--app/models/locked_by_another_user.rb1
-rw-r--r--app/models/node.rb13
-rw-r--r--app/views/admin/_recent_changes.html.erb2
-rw-r--r--app/views/content/_search.html.erb2
-rw-r--r--app/views/content/_tags.html.erb2
-rw-r--r--app/views/layouts/application.html.erb4
-rw-r--r--config/application.rb1
-rw-r--r--config/environments/development.rb2
-rw-r--r--config/environments/test.rb4
-rw-r--r--config/initializers/i18n.rb3
-rw-r--r--config/initializers/will_paginate_patch.rb13
-rw-r--r--doc/20260626025705_add_search_vector_to_page_translations.rb.pending47
16 files changed, 75 insertions, 64 deletions
diff --git a/Gemfile b/Gemfile
index 2f99c64..2f6e394 100644
--- a/Gemfile
+++ b/Gemfile
@@ -26,6 +26,7 @@ group :assets do
26 gem 'sass-rails', '~> 6.0' 26 gem 'sass-rails', '~> 6.0'
27 gem 'coffee-rails', '~> 4.0' 27 gem 'coffee-rails', '~> 4.0'
28 gem 'uglifier', '>= 1.0.3' 28 gem 'uglifier', '>= 1.0.3'
29 gem 'minitest', '~> 5.25'
29end 30end
30 31
31group :test do 32group :test do
diff --git a/Gemfile.lock b/Gemfile.lock
index 357998d..9d5ec90 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -157,9 +157,7 @@ GEM
157 marcel (1.2.1) 157 marcel (1.2.1)
158 mini_mime (1.1.5) 158 mini_mime (1.1.5)
159 mini_portile2 (2.8.9) 159 mini_portile2 (2.8.9)
160 minitest (6.0.6) 160 minitest (5.27.0)
161 drb (~> 2.0)
162 prism (~> 1.5)
163 net-imap (0.6.4.1) 161 net-imap (0.6.4.1)
164 date 162 date
165 net-protocol 163 net-protocol
@@ -323,6 +321,7 @@ DEPENDENCIES
323 globalize (~> 7.0) 321 globalize (~> 7.0)
324 jquery-rails 322 jquery-rails
325 libxml-ruby (~> 5.0) 323 libxml-ruby (~> 5.0)
324 minitest (~> 5.25)
326 nokogiri (~> 1.18) 325 nokogiri (~> 1.18)
327 pg (~> 1.4.6) 326 pg (~> 1.4.6)
328 puma 327 puma
@@ -394,7 +393,7 @@ CHECKSUMS
394 marcel (1.2.1) sha256=1678e9360e32f9eafa917c80029e2f6d10b2715c66a4b87b6d0da9b9cd1f859f 393 marcel (1.2.1) sha256=1678e9360e32f9eafa917c80029e2f6d10b2715c66a4b87b6d0da9b9cd1f859f
395 mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef 394 mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef
396 mini_portile2 (2.8.9) sha256=0cd7c7f824e010c072e33f68bc02d85a00aeb6fce05bb4819c03dfd3c140c289 395 mini_portile2 (2.8.9) sha256=0cd7c7f824e010c072e33f68bc02d85a00aeb6fce05bb4819c03dfd3c140c289
397 minitest (6.0.6) sha256=153ea36d1d987a62942382b61075745042a2b3123b1cd48f4c3675af9cc7d6f1 396 minitest (5.27.0) sha256=2d3b17f8a36fe7801c1adcffdbc38233b938eb0b4966e97a6739055a45fa77d5
398 net-imap (0.6.4.1) sha256=29f0360d75a7efd3539f16ac1957dea5c0a51ddeceb348db4553c3120914ea0d 397 net-imap (0.6.4.1) sha256=29f0360d75a7efd3539f16ac1957dea5c0a51ddeceb348db4553c3120914ea0d
399 net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3 398 net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3
400 net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8 399 net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8
diff --git a/app/helpers/link_helper.rb b/app/helpers/link_helper.rb
index 39ec495..cb13c8d 100644
--- a/app/helpers/link_helper.rb
+++ b/app/helpers/link_helper.rb
@@ -1,5 +1,5 @@
1module LinkHelper 1module LinkHelper
2 2
3 def content_path_helper path_array 3 def content_path_helper path_array
4 url_for( 4 url_for(
5 :controller => :content, 5 :controller => :content,
@@ -8,11 +8,11 @@ module LinkHelper
8 :page_path => path_array 8 :page_path => path_array
9 ) 9 )
10 end 10 end
11 11
12 def content_url_helper path_array 12 def content_url_helper path_array
13 request.protocol + request.host_with_port + content_path_helper(path_array) 13 request.protocol + request.host_with_port + content_path_helper(path_array)
14 end 14 end
15 15
16 def link_to_path title, path, html_options = {} 16 def link_to_path title, path, html_options = {}
17 return "" if path.nil? 17 return "" if path.nil?
18 18
@@ -22,9 +22,7 @@ module LinkHelper
22 end 22 end
23 23
24 active_class = active ? {:class => 'active'} : {:class => 'inactive'} 24 active_class = active ? {:class => 'active'} : {:class => 'inactive'}
25
26 html_options = html_options.merge(active_class) 25 html_options = html_options.merge(active_class)
27
28 locale = params[:locale] || I18n.locale 26 locale = params[:locale] || I18n.locale
29 27
30 link_to( 28 link_to(
@@ -39,34 +37,13 @@ module LinkHelper
39 return :class => "selected" 37 return :class => "selected"
40 end 38 end
41 end 39 end
42 40
43 def unlock_link 41 def unlock_link
44 message = "Are you sure you want to unlock?\n" + 42 message = "Are you sure you want to unlock?\n" +
45 "Locked by #{@node.lock_owner.login}\n" + 43 "Locked by #{@node.lock_owner.login}\n" +
46 "Last modified #{@page.updated_at.to_s(:db)}" 44 "Last modified #{@page.updated_at.to_fs(:db)}"
47
48 link_to 'Unlock', safe_path(:unlock_node_path, @node), :method => :put, :data => { :confirm => message }
49 end
50
51 # Rails 6.1 workaround: content_path named helper returns RouteWithParams
52 # when called from within a catch-all glob route request context.
53 # Rails 6.1 workaround: named route helpers return RouteWithParams when called
54 # from within a catch-all glob route request context.
55 # Remove this method when upgrading to Rails 7.0+, where this is fixed.
56 def safe_path(name, *args)
57 Rails.application.routes.url_helpers.send(name, *args)
58 end
59 45
60 def content_path(page_path = nil, options = {}) 46 link_to 'Unlock', unlock_node_path(@node), :method => :put, :data => { :confirm => message }
61 if page_path.is_a?(Hash)
62 options = page_path
63 page_path = options.delete(:page_path)
64 end
65 options[:locale] ||= params[:locale] || I18n.locale
66 Rails.application.routes.url_helpers.content_path(
67 Array(page_path).join("/").sub(/^\//, ""),
68 options
69 )
70 end 47 end
71 48
72end 49end
diff --git a/app/helpers/nodes_helper.rb b/app/helpers/nodes_helper.rb
index 204ad8a..c739ccd 100644
--- a/app/helpers/nodes_helper.rb
+++ b/app/helpers/nodes_helper.rb
@@ -31,7 +31,7 @@ module NodesHelper
31 31
32 def event_information 32 def event_information
33 if @node.event 33 if @node.event
34 "#{@node.event.start_time.to_s(:db)} - #{@node.event.end_time.to_s(:db)} > " \ 34 "#{@node.event.start_time.to_fs(:db)} - #{@node.event.end_time.to_fs(:db)} > " \
35 "#{link_to 'show', event_path(@node.event)} " \ 35 "#{link_to 'show', event_path(@node.event)} " \
36 "#{link_to 'edit', edit_event_path(@node.event)}" 36 "#{link_to 'edit', edit_event_path(@node.event)}"
37 else 37 else
diff --git a/app/models/locked_by_another_user.rb b/app/models/locked_by_another_user.rb
new file mode 100644
index 0000000..6f9e272
--- /dev/null
+++ b/app/models/locked_by_another_user.rb
@@ -0,0 +1 @@
class LockedByAnotherUser < StandardError; end
diff --git a/app/models/node.rb b/app/models/node.rb
index f7a70d0..41c3867 100644
--- a/app/models/node.rb
+++ b/app/models/node.rb
@@ -73,7 +73,7 @@ class Node < ApplicationRecord
73 raise( 73 raise(
74 LockedByAnotherUser, 74 LockedByAnotherUser,
75 "Page is locked by another user who is working on it! " \ 75 "Page is locked by another user who is working on it! " \
76 "Last modification: #{draft.updated_at.to_s(:db)}" 76 "Last modification: #{draft.updated_at.to_fs(:db)}"
77 ) 77 )
78 else 78 else
79 lock_for! current_user 79 lock_for! current_user
@@ -211,6 +211,13 @@ class Node < ApplicationRecord
211 self.created_at < new_id_format_date ? unique_path : id 211 self.created_at < new_id_format_date ? unique_path : id
212 end 212 end
213 213
214 # TODO: restore full-text search once PostgreSQL is upgraded.
215 # The tsvector/plpgsql approach requires PostgreSQL 10+ with plpgsql available.
216 # For now, search is disabled to unblock the Rails 7.2 upgrade.
217 def self.search(term, _ = {})
218 none
219 end
220
214 protected 221 protected
215 def lock_for! current_user 222 def lock_for! current_user
216 self.lock_owner = current_user 223 self.lock_owner = current_user
@@ -255,7 +262,3 @@ class Node < ApplicationRecord
255 end 262 end
256 end 263 end
257end 264end
258
259class LockedByAnotherUser < StandardError; end
260
261
diff --git a/app/views/admin/_recent_changes.html.erb b/app/views/admin/_recent_changes.html.erb
index 300d088..88b5e93 100644
--- a/app/views/admin/_recent_changes.html.erb
+++ b/app/views/admin/_recent_changes.html.erb
@@ -13,7 +13,7 @@
13 <td><%= truncated_title_for_node node %></td> 13 <td><%= truncated_title_for_node node %></td>
14 <td><%= node.unique_name %></td> 14 <td><%= node.unique_name %></td>
15 <td><%= node.draft.user.login rescue "" %></td> 15 <td><%= node.draft.user.login rescue "" %></td>
16 <td><%= node.updated_at.to_s(:db) %></td> 16 <td><%= node.updated_at.to_fs(:db) %></td>
17 <td class="actions"> 17 <td class="actions">
18 <%= link_to 'Show', node_path(node) %> 18 <%= link_to 'Show', node_path(node) %>
19 <%= link_to "Revisions", revision_path(:id => node.id) %> 19 <%= link_to "Revisions", revision_path(:id => node.id) %>
diff --git a/app/views/content/_search.html.erb b/app/views/content/_search.html.erb
index f732fca..aa91424 100644
--- a/app/views/content/_search.html.erb
+++ b/app/views/content/_search.html.erb
@@ -1,3 +1,3 @@
1<%= form_tag safe_path(:search_path), :method => 'get' do %> 1<%= form_tag search_path, :method => 'get' do %>
2 <div><%= text_field_tag :search_term, params[:search_term], :placeholder => 'suchen', :type => 'search' %></div> 2 <div><%= text_field_tag :search_term, params[:search_term], :placeholder => 'suchen', :type => 'search' %></div>
3<% end %> 3<% end %>
diff --git a/app/views/content/_tags.html.erb b/app/views/content/_tags.html.erb
index 387f51c..f0e7210 100644
--- a/app/views/content/_tags.html.erb
+++ b/app/views/content/_tags.html.erb
@@ -3,7 +3,7 @@
3 <h2>Tags</h2> 3 <h2>Tags</h2>
4 <ul class="teasertext"> 4 <ul class="teasertext">
5 <% @page.tags.each do |tag| %> 5 <% @page.tags.each do |tag| %>
6 <li><%= link_to tag.name, safe_path(:tag_path, tag.name) %></li> 6 <li><%= link_to tag.name, tag_path(tag.name) %></li>
7 <% end %> 7 <% end %>
8 </ul> 8 </ul>
9</div> 9</div>
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 84dcdc6..c5cbf14 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -52,8 +52,8 @@
52 <div class="main_navigation"> 52 <div class="main_navigation">
53 <h2>Admin</h2> 53 <h2>Admin</h2>
54 <ul> 54 <ul>
55 <li><%= link_to raw('<span class="inactive admin_edit_link">⚙️ Overview</span>'), safe_path(:admin_path) %></li> 55 <li><%= link_to raw('<span class="inactive admin_edit_link">⚙️ Overview</span>'), admin_path %></li>
56 <li><%= link_to raw('<span class="inactive admin_edit_link">✎ Edit</span>'), safe_path(:node_path, @page.node) %></li> 56 <li><%= link_to raw('<span class="inactive admin_edit_link">✎ Edit</span>'), node_path(@page.node) %></li>
57 </ul> 57 </ul>
58 </div> 58 </div>
59 <% end %> 59 <% end %>
diff --git a/config/application.rb b/config/application.rb
index 1a7f32b..d92802f 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -54,6 +54,7 @@ module Cccms
54 # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 54 # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
55 # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')] 55 # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')]
56 config.i18n.default_locale = :de 56 config.i18n.default_locale = :de
57 config.i18n.fallbacks = { en: [:en, :de] }
57 58
58 config.filter_parameters += [:password, :password_confirmation] 59 config.filter_parameters += [:password, :password_confirmation]
59 config.serve_static_files = true 60 config.serve_static_files = true
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 8e2e7ef..43a6846 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -4,7 +4,7 @@ Cccms::Application.configure do
4 # In the development environment your application's code is reloaded on 4 # In the development environment your application's code is reloaded on
5 # every request. This slows down response time but is perfect for development 5 # every request. This slows down response time but is perfect for development
6 # since you don't have to restart the webserver when you make code changes. 6 # since you don't have to restart the webserver when you make code changes.
7 config.cache_classes = false 7 config.enable_reloading = true
8 8
9 # Log error messages when you accidentally call methods on nil. 9 # Log error messages when you accidentally call methods on nil.
10 10
diff --git a/config/environments/test.rb b/config/environments/test.rb
index a23c6d4..48aafe8 100644
--- a/config/environments/test.rb
+++ b/config/environments/test.rb
@@ -1,6 +1,6 @@
1Cccms::Application.configure do 1Cccms::Application.configure do
2 2
3 config.cache_classes = true 3 config.enable_reloading = false
4 4
5 config.action_controller.consider_all_requests_local = true 5 config.action_controller.consider_all_requests_local = true
6 config.action_controller.perform_caching = false 6 config.action_controller.perform_caching = false
@@ -10,10 +10,8 @@ Cccms::Application.configure do
10 config.action_mailer.delivery_method = :test 10 config.action_mailer.delivery_method = :test
11 11
12 config.active_support.deprecation = :log 12 config.active_support.deprecation = :log
13 config.active_support.test_order = :sorted
14 13
15 config.eager_load = false 14 config.eager_load = false
16 config.public_file_server.enabled = true 15 config.public_file_server.enabled = true
17 config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=3600' } 16 config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=3600' }
18 config.assets.compile = true
19end 17end
diff --git a/config/initializers/i18n.rb b/config/initializers/i18n.rb
deleted file mode 100644
index 0190f63..0000000
--- a/config/initializers/i18n.rb
+++ /dev/null
@@ -1,3 +0,0 @@
1require "i18n/backend/fallbacks"
2I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
3I18n.fallbacks.map "en" => ["de"]
diff --git a/config/initializers/will_paginate_patch.rb b/config/initializers/will_paginate_patch.rb
deleted file mode 100644
index d03c882..0000000
--- a/config/initializers/will_paginate_patch.rb
+++ /dev/null
@@ -1,13 +0,0 @@
1require 'will_paginate/view_helpers/action_view'
2
3WillPaginate::ActionView::LinkRenderer.class_eval do
4 def url(page)
5 path = @template.request.path
6 page_param = WillPaginate::PageNumber(page)
7 if page_param == 1
8 path
9 else
10 "#{path}?#{@options[:param_name]}=#{page}"
11 end
12 end
13end
diff --git a/doc/20260626025705_add_search_vector_to_page_translations.rb.pending b/doc/20260626025705_add_search_vector_to_page_translations.rb.pending
new file mode 100644
index 0000000..0747637
--- /dev/null
+++ b/doc/20260626025705_add_search_vector_to_page_translations.rb.pending
@@ -0,0 +1,47 @@
1class AddSearchVectorToPageTranslations < ActiveRecord::Migration[7.2]
2 def up
3 add_column :page_translations, :search_vector, :tsvector
4
5 execute <<~SQL
6 UPDATE page_translations
7 SET search_vector = to_tsvector(
8 'simple',
9 coalesce(title, '') || ' ' ||
10 coalesce(abstract, '') || ' ' ||
11 coalesce(body, '')
12 )
13 SQL
14
15 add_index :page_translations, :search_vector,
16 using: :gin,
17 name: 'index_page_translations_on_search_vector'
18
19 execute <<~SQL
20 CREATE OR REPLACE FUNCTION page_translations_search_vector_update()
21 RETURNS trigger AS $$
22 BEGIN
23 NEW.search_vector := to_tsvector(
24 'simple',
25 coalesce(NEW.title, '') || ' ' ||
26 coalesce(NEW.abstract, '') || ' ' ||
27 coalesce(NEW.body, '')
28 );
29 RETURN NEW;
30 END;
31 $$ LANGUAGE plpgsql;
32
33 CREATE TRIGGER page_translations_search_vector_trigger
34 BEFORE INSERT OR UPDATE ON page_translations
35 FOR EACH ROW EXECUTE PROCEDURE page_translations_search_vector_update();
36 SQL
37 end
38
39 def down
40 execute <<~SQL
41 DROP TRIGGER IF EXISTS page_translations_search_vector_trigger ON page_translations;
42 DROP FUNCTION IF EXISTS page_translations_search_vector_update();
43 SQL
44 remove_index :page_translations, name: 'index_page_translations_on_search_vector'
45 remove_column :page_translations, :search_vector
46 end
47end