summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-07-13 17:09:31 +0200
committererdgeist <erdgeist@erdgeist.org>2026-07-13 17:09:31 +0200
commitaa14587b052a0aa7884aaf27183981975168ab14 (patch)
tree2b043061a06474929bbfb9fe79a7985267ccef17
parent0b6ae26f3b4c3c8278e569fa6644a544e996c25d (diff)
Wire real autosave into translation editing
The shared TinyMCE setup initializes cccms.setup_autosave() on any page with a textarea.with_editor, unconditionally starting a 7-second interval that submits to the form's data-autosave-url -- which the translation edit form never set, so the interval PUT the current page URL itself and 404'd on a nonexistent route. Fixed by actually giving it something to talk to, rather than suppressing it: a real autosave endpoint, and update now goes through Node#autosave!/#save_draft! -- the same pipeline the primary editor uses, fixed earlier this session for exactly this kind of cross-locale carryover. This was the autosave-buffer parity already flagged as due after the proof of concept; the shared JS just forced the timing.
-rw-r--r--app/controllers/page_translations_controller.rb17
-rw-r--r--app/views/page_translations/edit.html.erb3
-rw-r--r--config/routes.rb7
-rw-r--r--test/controllers/page_translations_controller_test.rb19
4 files changed, 40 insertions, 6 deletions
diff --git a/app/controllers/page_translations_controller.rb b/app/controllers/page_translations_controller.rb
index 47f01f7..9446cd2 100644
--- a/app/controllers/page_translations_controller.rb
+++ b/app/controllers/page_translations_controller.rb
@@ -3,7 +3,7 @@ class PageTranslationsController < ApplicationController
3 3
4 before_action :login_required 4 before_action :login_required
5 before_action :find_node 5 before_action :find_node
6 before_action :find_locale, :only => [:show, :edit, :update, :destroy] 6 before_action :find_locale, :only => [:show, :edit, :update, :autosave, :destroy]
7 7
8 def index 8 def index
9 page = @node.draft || @node.head 9 page = @node.draft || @node.head
@@ -26,8 +26,8 @@ class PageTranslationsController < ApplicationController
26 end 26 end
27 27
28 def update 28 def update
29 draft = ensure_editable_draft 29 Globalize.with_locale(@locale) { @node.autosave!(translation_params, current_user) }
30 Globalize.with_locale(@locale) { draft.update!(translation_params) } 30 @node.save_draft!(current_user)
31 flash[:notice] = "#{@locale.upcase} translation saved. Publish the draft to make it live." 31 flash[:notice] = "#{@locale.upcase} translation saved. Publish the draft to make it live."
32 32
33 if params[:commit] == "Save + Unlock + Exit" 33 if params[:commit] == "Save + Unlock + Exit"
@@ -41,6 +41,17 @@ class PageTranslationsController < ApplicationController
41 redirect_to node_path(@node) 41 redirect_to node_path(@node)
42 end 42 end
43 43
44 def autosave
45 Globalize.with_locale(@locale) { @node.autosave!(translation_params, current_user) }
46 head :ok
47 rescue LockedByAnotherUser => e
48 render plain: e.message, status: :locked
49 rescue ActiveRecord::RecordInvalid => e
50 render plain: e.message, status: :unprocessable_entity
51 rescue StandardError => e
52 render plain: "Autosave failed", status: :internal_server_error
53 end
54
44 def destroy 55 def destroy
45 base = @node.draft || @node.head 56 base = @node.draft || @node.head
46 unless base && base.translated_locales.include?(@locale) 57 unless base && base.translated_locales.include?(@locale)
diff --git a/app/views/page_translations/edit.html.erb b/app/views/page_translations/edit.html.erb
index 7371a42..89b594e 100644
--- a/app/views/page_translations/edit.html.erb
+++ b/app/views/page_translations/edit.html.erb
@@ -18,7 +18,8 @@
18</div> 18</div>
19 19
20<div id="page_editor"> 20<div id="page_editor">
21 <%= form_with url: node_translation_path(@node, @locale), method: :patch, local: true, id: "translation_edit_form" do |f| %> 21 <%= form_with url: node_translation_path(@node, @locale), method: :patch, local: true, id: "translation_edit_form",
22 data: { autosave_url: autosave_node_translation_path(@node, @locale), show_url: node_path(@node) } do |f| %>
22 <div id="content"> 23 <div id="content">
23 <div class="node_description">Title</div> 24 <div class="node_description">Title</div>
24 <div class="node_content"> 25 <div class="node_content">
diff --git a/config/routes.rb b/config/routes.rb
index 38a497d..826bb18 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -58,8 +58,11 @@ Cccms::Application.routes.draw do
58 resources :translations, controller: 'page_translations', 58 resources :translations, controller: 'page_translations',
59 param: :translation_locale, 59 param: :translation_locale,
60 constraints: { translation_locale: /en/ }, 60 constraints: { translation_locale: /en/ },
61 only: [:index, :show, :edit, :update, :destroy] 61 only: [:index, :show, :edit, :update, :destroy] do
62 62 member do
63 put :autosave
64 end
65 end
63 66
64 resources :related_assets, only: [:create, :destroy, :update] do 67 resources :related_assets, only: [:create, :destroy, :update] do
65 collection do 68 collection do
diff --git a/test/controllers/page_translations_controller_test.rb b/test/controllers/page_translations_controller_test.rb
index d84ac45..8c899fd 100644
--- a/test/controllers/page_translations_controller_test.rb
+++ b/test/controllers/page_translations_controller_test.rb
@@ -18,6 +18,7 @@ class PageTranslationsControllerTest < ActionController::TestCase
18 node = Node.root.children.create!(:slug => "translations_create_test") 18 node = Node.root.children.create!(:slug => "translations_create_test")
19 Globalize.with_locale(:de) { node.draft.update!(:title => "Deutscher Titel") } 19 Globalize.with_locale(:de) { node.draft.update!(:title => "Deutscher Titel") }
20 node.publish_draft! 20 node.publish_draft!
21 node.lock_for_editing!(users(:quentin))
21 22
22 patch :update, params: { :node_id => node.id, :translation_locale => "en", :page => { :title => "English Title" } } 23 patch :update, params: { :node_id => node.id, :translation_locale => "en", :page => { :title => "English Title" } }
23 24
@@ -39,6 +40,7 @@ class PageTranslationsControllerTest < ActionController::TestCase
39 test "update with Save + Unlock + Exit unlocks the node and redirects to nodes#show" do 40 test "update with Save + Unlock + Exit unlocks the node and redirects to nodes#show" do
40 login_as :quentin 41 login_as :quentin
41 node = Node.root.children.create!(:slug => "translations_exit_test") 42 node = Node.root.children.create!(:slug => "translations_exit_test")
43 node.lock_for_editing!(users(:quentin))
42 44
43 patch :update, params: { :node_id => node.id, :translation_locale => "en", :page => { :title => "x" }, :commit => "Save + Unlock + Exit" } 45 patch :update, params: { :node_id => node.id, :translation_locale => "en", :page => { :title => "x" }, :commit => "Save + Unlock + Exit" }
44 46
@@ -50,6 +52,7 @@ class PageTranslationsControllerTest < ActionController::TestCase
50 login_as :quentin 52 login_as :quentin
51 node = Node.root.children.create!(:slug => "translations_update_test") 53 node = Node.root.children.create!(:slug => "translations_update_test")
52 Globalize.with_locale(:en) { node.draft.update!(:title => "Original") } 54 Globalize.with_locale(:en) { node.draft.update!(:title => "Original") }
55 node.lock_for_editing!(users(:quentin))
53 56
54 patch :update, params: { :node_id => node.id, :translation_locale => "en", :page => { :title => "Revised" } } 57 patch :update, params: { :node_id => node.id, :translation_locale => "en", :page => { :title => "Revised" } }
55 58
@@ -75,4 +78,20 @@ class PageTranslationsControllerTest < ActionController::TestCase
75 78
76 assert_match(/No EN translation exists/, flash[:error]) 79 assert_match(/No EN translation exists/, flash[:error])
77 end 80 end
81
82 test "autosave writes the translation without creating a new revision or touching the draft" do
83 login_as :quentin
84 node = Node.root.children.create!(:slug => "translations_autosave_test")
85 node.publish_draft!
86 node.lock_for_editing!(users(:quentin))
87 page_count_before = node.pages.count
88
89 put :autosave, params: { :node_id => node.id, :translation_locale => "en", :page => { :title => "in progress" } }
90
91 assert_response :success
92 node.reload
93 assert_not_nil node.autosave
94 assert_equal page_count_before, node.pages.count
95 assert_equal "in progress", Globalize.with_locale(:en) { node.autosave.title }
96 end
78end 97end