Skip to content

Commit b183385

Browse files
Add drafting stage for session dates
The "back" button on the session dates edit page was broken. Even when one clicked back, the changes made were still saved. MAV-516 includes a bug report for this. By adding a new model which is a draft version of the session dates we can allow modification of session dates in the edit page without immediately saving them to the database.
1 parent 76862e0 commit b183385

File tree

3 files changed

+347
-65
lines changed

3 files changed

+347
-65
lines changed

app/controllers/session_dates_controller.rb

Lines changed: 127 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,33 @@
22

33
class SessionDatesController < ApplicationController
44
before_action :set_session
5+
before_action :set_draft_session_dates
56

67
def show
7-
@session.session_dates.build if @session.session_dates.empty?
8-
end
9-
10-
def update
11-
@session.assign_attributes(remove_invalid_dates(session_params))
12-
@session.set_notification_dates
8+
initialize_draft_from_session
139

14-
render :show, status: :unprocessable_content and return if @session.invalid?
15-
16-
@session.save!
17-
18-
# If deleting dates, they don't disappear from `session.dates` until
19-
# the model has been saved due to how `accepts_nested_attributes_for`
20-
# works.
21-
if any_destroyed?
22-
@session.session_dates.reload
23-
@session.set_notification_dates
24-
@session.save!
10+
if params[:add_another] ||
11+
@draft_session_dates.session_dates_attributes.empty?
12+
add_blank_session_date
2513
end
14+
end
2615

27-
StatusUpdaterJob.perform_later(session: @session)
16+
def update
17+
@draft_session_dates.session_dates_attributes =
18+
fetch_draft_session_dates_from_form
2819

29-
if params.include?(:add_another)
30-
@session.session_dates.build
20+
if params[:delete_date]
21+
delete_session_date(form_index_to_attr_index(params[:delete_date]))
22+
return render_with_error if @draft_session_dates.errors.any?
23+
render :show
24+
elsif params[:add_another]
25+
add_blank_session_date
3126
render :show
3227
else
33-
redirect_to(
34-
if any_destroyed?
35-
session_dates_path(@session)
36-
else
37-
edit_session_path(@session)
38-
end
39-
)
28+
unless @draft_session_dates.save(context: :continue)
29+
return render_with_error
30+
end
31+
apply_changes_and_redirect
4032
end
4133
end
4234

@@ -46,41 +38,121 @@ def set_session
4638
@session = policy_scope(Session).find_by!(slug: params[:session_slug])
4739
end
4840

49-
def session_params
50-
params.expect(
51-
session: {
52-
session_dates_attributes: [%i[id value _destroy]]
53-
}
41+
def set_draft_session_dates
42+
@draft_session_dates =
43+
DraftSessionDates.new(
44+
request_session: session,
45+
current_user: current_user,
46+
session: @session,
47+
wizard_step: :dates
48+
)
49+
end
50+
51+
def draft_session_dates_params
52+
params
53+
.fetch(:draft_session_dates, {})
54+
.permit(
55+
session_dates_attributes: [
56+
:id,
57+
:value,
58+
:_destroy,
59+
"value(1i)",
60+
"value(2i)",
61+
"value(3i)"
62+
]
63+
)
64+
.merge(wizard_step: :dates)
65+
end
66+
67+
def initialize_draft_from_session
68+
attributes = {}
69+
70+
@session
71+
.session_dates
72+
.order(:value)
73+
.each_with_index do |session_date, index|
74+
attributes[index] = {
75+
"id" => session_date.id.to_s,
76+
"value" => session_date.value
77+
}
78+
end
79+
80+
@draft_session_dates.session_dates_attributes = attributes
81+
@draft_session_dates.save!(context: :initialize)
82+
end
83+
84+
def add_blank_session_date
85+
current_attrs = @draft_session_dates.session_dates_attributes
86+
next_index = (current_attrs.keys.map(&:to_i).max || -1) + 1
87+
current_attrs[next_index] = { "value" => nil }
88+
@draft_session_dates.session_dates_attributes = current_attrs
89+
end
90+
91+
def render_with_error
92+
render :show, status: :unprocessable_content
93+
end
94+
95+
def apply_changes_and_redirect
96+
@draft_session_dates.write_to!(@session)
97+
session.delete(@draft_session_dates.request_session_key)
98+
StatusUpdaterJob.perform_later(session: @session)
99+
redirect_to edit_session_path(@session)
100+
rescue ActiveRecord::RecordInvalid => e
101+
@draft_session_dates.errors.add(
102+
:base,
103+
"Failed to save session dates: #{e.message}"
54104
)
105+
render_with_error
55106
end
56107

57-
def any_destroyed?
58-
session_params[:session_dates_attributes].values.any? do
59-
_1[:_destroy].present?
108+
def form_index_to_attr_index(form_index)
109+
current_attrs = @draft_session_dates.session_dates_attributes
110+
corresponding_form_index = -1
111+
current_attrs.each do |real_index, attrs|
112+
corresponding_form_index += 1 unless attrs["_destroy"] == "true"
113+
114+
return real_index if corresponding_form_index.to_s == form_index
60115
end
116+
117+
(
118+
form_index.to_i - corresponding_form_index.to_i + current_attrs.length
119+
).to_s
61120
end
62121

63-
def remove_invalid_dates(obj, key: "session_dates_attributes")
64-
return obj if obj[key].blank?
65-
66-
obj[key] = obj[key].transform_values do |value|
67-
if value.key?("value(1i)") && value.key?("value(2i)") &&
68-
value.key?("value(3i)")
69-
begin
70-
Date.new(
71-
value["value(1i)"].to_i,
72-
value["value(2i)"].to_i,
73-
value["value(3i)"].to_i
74-
)
75-
value
76-
rescue StandardError
77-
{}
78-
end
79-
else
80-
value
81-
end
122+
def fetch_draft_session_dates_from_form
123+
current_attrs = @draft_session_dates.session_dates_attributes
124+
125+
form_params = draft_session_dates_params[:session_dates_attributes] || {}
126+
127+
merged_attrs = {}
128+
129+
current_attrs.each do |index, attrs|
130+
merged_attrs[index] = attrs if attrs["_destroy"] == "true"
82131
end
83132

84-
obj
133+
form_params.each do |form_index, form_attrs|
134+
attr_index = form_index_to_attr_index(form_index)
135+
merged_attrs[attr_index] = form_attrs
136+
end
137+
138+
merged_attrs
139+
end
140+
141+
def delete_session_date(index)
142+
current_attrs = @draft_session_dates.session_dates_attributes
143+
144+
if current_attrs[index]
145+
if @draft_session_dates.non_destroyed_session_dates_count <= 1
146+
@draft_session_dates.errors.add(
147+
:base,
148+
"You cannot delete the last session date. A session must have at least one date."
149+
)
150+
return
151+
end
152+
153+
current_attrs[index]["_destroy"] = "true"
154+
@draft_session_dates.session_dates_attributes = current_attrs
155+
@draft_session_dates.save!(context: :update)
156+
end
85157
end
86158
end

0 commit comments

Comments
 (0)