Skip to content

Commit c4d399c

Browse files
committed
Merge branch 'feature/checklists' of github.com:better-together-solutions/community-engine-rails into feature/checklists
2 parents 9a2e147 + 3847caa commit c4d399c

14 files changed

+196
-159
lines changed

app/controllers/better_together/checklist_items_controller.rb

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,12 @@ def position # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
9292
respond_to do |format|
9393
format.html { redirect_to request.referer || checklist_path(@checklist), notice: t('flash.generic.updated') }
9494
format.turbo_stream do
95-
render turbo_stream: turbo_stream.replace(helpers.dom_id(@checklist, :checklist_items),
96-
partial: 'better_together/checklist_items/checklist_item', collection: @checklist.checklist_items.with_translations, as: :checklist_item)
95+
render turbo_stream: turbo_stream.replace(
96+
helpers.dom_id(@checklist, :checklist_items),
97+
partial: 'better_together/checklist_items/checklist_item',
98+
collection: @checklist.checklist_items.with_translations,
99+
as: :checklist_item
100+
)
97101
end
98102
end
99103
end
@@ -119,8 +123,12 @@ def reorder # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
119123
respond_to do |format|
120124
format.json { head :no_content }
121125
format.turbo_stream do
122-
render turbo_stream: turbo_stream.replace(helpers.dom_id(@checklist, :checklist_items),
123-
partial: 'better_together/checklist_items/checklist_item', collection: @checklist.checklist_items.with_translations, as: :checklist_item)
126+
render turbo_stream: turbo_stream.replace(
127+
helpers.dom_id(@checklist, :checklist_items),
128+
partial: 'better_together/checklist_items/checklist_item',
129+
collection: @checklist.checklist_items.with_translations,
130+
as: :checklist_item
131+
)
124132
end
125133
end
126134
end
@@ -129,40 +137,36 @@ def reorder # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
129137

130138
def set_checklist
131139
key = params[:checklist_id] || params[:id]
132-
133140
@checklist = nil
134141
if key.present?
135-
# Try direct id/identifier lookup first (fast)
136-
@checklist = BetterTogether::Checklist.where(id: key).or(BetterTogether::Checklist.where(identifier: key)).first
137-
138-
# Fallbacks to mirror FriendlyResourceController behaviour: try translated slug lookups
139-
if @checklist.nil?
140-
begin
141-
# Try Mobility translation lookup across locales
142-
translation = Mobility::Backends::ActiveRecord::KeyValue::StringTranslation.where(
143-
translatable_type: 'BetterTogether::Checklist',
144-
key: 'slug',
145-
value: key
146-
).includes(:translatable).last
147-
148-
@checklist ||= translation&.translatable
149-
rescue StandardError
150-
# ignore DB/translation lookup errors and continue to friendly_id fallback
151-
end
152-
end
153-
154-
if @checklist.nil?
155-
begin
156-
@checklist = BetterTogether::Checklist.friendly.find(key)
157-
rescue StandardError
158-
@checklist ||= BetterTogether::Checklist.find_by(id: key)
159-
end
160-
end
142+
@checklist = find_by_id_or_identifier(key) || find_by_translation_slug(key) || find_by_friendly_or_id(key)
161143
end
162144

163145
raise ActiveRecord::RecordNotFound unless @checklist
164146
end
165147

148+
def find_by_id_or_identifier(key)
149+
BetterTogether::Checklist.where(id: key).or(BetterTogether::Checklist.where(identifier: key)).first
150+
end
151+
152+
def find_by_translation_slug(key)
153+
translation = Mobility::Backends::ActiveRecord::KeyValue::StringTranslation.where(
154+
translatable_type: 'BetterTogether::Checklist',
155+
key: 'slug',
156+
value: key
157+
).includes(:translatable).last
158+
159+
translation&.translatable
160+
rescue StandardError
161+
nil
162+
end
163+
164+
def find_by_friendly_or_id(key)
165+
BetterTogether::Checklist.friendly.find(key)
166+
rescue StandardError
167+
BetterTogether::Checklist.find_by(id: key)
168+
end
169+
166170
def checklist_item
167171
@checklist_item = set_resource_instance
168172
end

app/helpers/better_together/badges_helper.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def privacy_badge(entity, rounded: true, style: nil)
3636
# styling elsewhere (for example: tinting checkboxes to match privacy badge).
3737
def privacy_style(entity)
3838
return nil unless entity.respond_to?(:privacy) && entity.privacy.present?
39+
3940
privacy_key = entity.privacy.to_s.downcase
4041
privacy_style_map = {
4142
'public' => 'success',

app/helpers/better_together/checklist_items_helper.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1+
# frozen_string_literal: true
2+
13
module BetterTogether
4+
# Helper methods for rendering and formatting checklist items in views.
5+
#
6+
# Provides small view helper utilities used by checklist-related templates.
27
module ChecklistItemsHelper
38
# Build an option title for a checklist item including depth-based prefix and slug.
49
# Example: "— — Subitem label (subitem-slug)"

app/helpers/better_together/translatable_fields_helper.rb

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# frozen_string_literal: true
22

33
module BetterTogether
4-
# Helps with rendering content for translatable fields
4+
# Helpers for rendering and interacting with translatable form fields.
5+
# These helpers build UI elements for locale tabs, translation dropdowns
6+
# and translation indicators used across the admin forms.
57
module TranslatableFieldsHelper
68
# Helper to render a translation tab button
79
def translation_tab_button(attribute:, locale:, temp_id:, model:) # rubocop:todo Metrics/MethodLength
@@ -70,24 +72,24 @@ def dropdown_button(locale, unique_locale_attribute, translation_present) # rubo
7072

7173
# Generates the dropdown menu with translation options
7274
def dropdown_menu(_attribute, locale, unique_locale_attribute, base_url) # rubocop:todo Metrics/MethodLength
73-
content_tag(:ul, class: 'dropdown-menu') do
74-
items = I18n.available_locales.reject do |available_locale|
75-
available_locale == locale
76-
end.map do |available_locale|
77-
content_tag(:li) do
78-
link_to "AI Translate from #{I18n.t("locales.#{available_locale}")}", '#ai-translate',
79-
class: 'dropdown-item',
80-
data: {
81-
'better_together--translation-target' => 'aiTranslate',
82-
action: 'click->better_together--translation#aiTranslateAttribute',
83-
'field-id' => "#{unique_locale_attribute}-field",
84-
'source-locale' => available_locale,
85-
'target-locale' => locale,
86-
'base-url' => base_url # Pass the base URL
87-
}
88-
end
75+
locales = I18n.available_locales.reject { |available_locale| available_locale == locale }
76+
77+
items = locales.map do |available_locale|
78+
content_tag(:li) do
79+
link_to "AI Translate from #{I18n.t("locales.#{available_locale}")}", '#ai-translate',
80+
class: 'dropdown-item',
81+
data: {
82+
'better_together--translation-target' => 'aiTranslate',
83+
action: 'click->better_together--translation#aiTranslateAttribute',
84+
'field-id' => "#{unique_locale_attribute}-field",
85+
'source-locale' => available_locale,
86+
'target-locale' => locale,
87+
'base-url' => base_url # Pass the base URL
88+
}
8989
end
90+
end
9091

92+
content_tag(:ul, class: 'dropdown-menu') do
9193
safe_join(items)
9294
end
9395
end

app/models/better_together/checklist_item.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def completion_record_for(person)
6161
end
6262

6363
def self.permitted_attributes(id: false, destroy: false)
64-
super + %i[checklist_id parent_id position]
64+
super + %i[checklist_id parent_id position]
6565
end
6666

6767
# Scope positions per-parent so items are ordered among siblings

app/policies/better_together/checklist_item_policy.rb

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def reorder?
2525
end
2626

2727
class Scope < ApplicationPolicy::Scope # rubocop:todo Style/Documentation
28-
def resolve
28+
def resolve # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
2929
result = scope.with_translations.order(created_at: :desc)
3030

3131
table = scope.arel_table
@@ -47,9 +47,7 @@ def resolve
4747
)
4848
end
4949

50-
if scope.ancestors.include?(BetterTogether::Creatable)
51-
query = query.or(table[:creator_id].eq(agent.id))
52-
end
50+
query = query.or(table[:creator_id].eq(agent.id)) if scope.ancestors.include?(BetterTogether::Creatable)
5351
end
5452

5553
result = result.where(query)

app/policies/better_together/checklist_policy.rb

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def completion_status?
2929
end
3030

3131
class Scope < ApplicationPolicy::Scope # rubocop:todo Style/Documentation
32-
def resolve
32+
def resolve # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
3333
result = scope.with_translations.order(created_at: :desc)
3434

3535
table = scope.arel_table
@@ -51,9 +51,7 @@ def resolve
5151
)
5252
end
5353

54-
if scope.ancestors.include?(BetterTogether::Creatable)
55-
query = query.or(table[:creator_id].eq(agent.id))
56-
end
54+
query = query.or(table[:creator_id].eq(agent.id)) if scope.ancestors.include?(BetterTogether::Creatable)
5755
end
5856

5957
result = result.where(query)
Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# frozen_string_literal: true
22

3+
# Migration to add a counter cache column for number of children on checklist items.
34
class AddChildrenCountToChecklistItems < ActiveRecord::Migration[7.1]
45
disable_ddl_transaction!
56

@@ -12,22 +13,25 @@ def change
1213

1314
reversible do |dir|
1415
dir.up do
15-
# Only backfill if parent_id column exists
16-
if column_exists?(:better_together_checklist_items, :parent_id)
17-
# Backfill counts without locking the whole table
18-
execute(<<-SQL.squish)
19-
UPDATE better_together_checklist_items parent
20-
SET children_count = sub.count
21-
FROM (
22-
SELECT parent_id, COUNT(*) as count
23-
FROM better_together_checklist_items
24-
WHERE parent_id IS NOT NULL
25-
GROUP BY parent_id
26-
) AS sub
27-
WHERE parent.id = sub.parent_id
28-
SQL
29-
end
16+
backfill_children_count if column_exists?(:better_together_checklist_items, :parent_id)
3017
end
3118
end
3219
end
20+
21+
private
22+
23+
def backfill_children_count # rubocop:disable Metrics/MethodLength
24+
# Backfill counts without locking the whole table
25+
execute(<<-SQL.squish)
26+
UPDATE better_together_checklist_items parent
27+
SET children_count = sub.count
28+
FROM (
29+
SELECT parent_id, COUNT(*) as count
30+
FROM better_together_checklist_items
31+
WHERE parent_id IS NOT NULL
32+
GROUP BY parent_id
33+
) AS sub
34+
WHERE parent.id = sub.parent_id
35+
SQL
36+
end
3337
end

db/migrate/20250901203001_add_parent_to_checklist_items.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# frozen_string_literal: true
22

3+
# Migration to add a parent reference to checklist items (self-referential association).
34
class AddParentToChecklistItems < ActiveRecord::Migration[7.1]
45
def change
56
add_reference :better_together_checklist_items,
Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# frozen_string_literal: true
22

3+
# Migration to add children_count column and backfill existing counts for checklist items.
34
class AddChildrenCountToChecklistItems < ActiveRecord::Migration[7.1]
45
disable_ddl_transaction!
56

@@ -10,20 +11,14 @@ def change
1011
add_index :better_together_checklist_items, :children_count
1112

1213
reversible do |dir|
13-
dir.up do
14-
# Backfill counts without locking the whole table
15-
execute(<<-SQL.squish)
16-
UPDATE better_together_checklist_items parent
17-
SET children_count = sub.count
18-
FROM (
19-
SELECT parent_id, COUNT(*) as count
20-
FROM better_together_checklist_items
21-
WHERE parent_id IS NOT NULL
22-
GROUP BY parent_id
23-
) AS sub
24-
WHERE parent.id = sub.parent_id
25-
SQL
26-
end
14+
dir.up { backfill_children_count }
2715
end
2816
end
17+
18+
private
19+
20+
def backfill_children_count
21+
sql = "UPDATE better_together_checklist_items parent SET children_count = sub.count FROM (SELECT parent_id, COUNT(*) as count FROM better_together_checklist_items WHERE parent_id IS NOT NULL GROUP BY parent_id) AS sub WHERE parent.id = sub.parent_id" # rubocop:disable Layout/LineLength
22+
execute(sql)
23+
end
2924
end

0 commit comments

Comments
 (0)