Class: LeanCms::PageContentsController

Inherits:
ApplicationController show all
Defined in:
app/controllers/lean_cms/page_contents_controller.rb

Instance Method Summary collapse

Instance Method Details

#editObject



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'app/controllers/lean_cms/page_contents_controller.rb', line 43

def edit
  @page = params[:page]
  @section = params[:section]

  # Find the LeanCms::Page by slug
  page_record = LeanCms::Page.find_by(slug: @page)
  
  @fields = if page_record
    # Use page_id for new data structure
    LeanCms::PageContent.where(page_id: page_record.id, section: @section).ordered
  else
    # Fallback to string-based lookup for legacy data
    LeanCms::PageContent.where("page = ? AND section = ?", @page, @section).ordered
  end

  redirect_to lean_cms_page_contents_path, alert: 'Section not found' if @fields.empty?
end

#edit_fieldObject



272
273
274
275
276
277
278
# File 'app/controllers/lean_cms/page_contents_controller.rb', line 272

def edit_field
  @field = LeanCms::PageContent.find(params[:id])

  render partial: 'lean_cms/page_contents/field_editor',
         locals: { field: @field },
         layout: false
end

#indexObject



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'app/controllers/lean_cms/page_contents_controller.rb', line 7

def index
  # Get all pages that have content associated with them
  @pages = LeanCms::Page
            .joins(:page_contents)
            .select('lean_cms_pages.*, MIN(lean_cms_page_contents.page_order) as min_page_order')
            .group('lean_cms_pages.id')
            .order('min_page_order, lean_cms_pages.position, lean_cms_pages.title')
            .distinct
            .map { |page| { key: page.slug, display_title: page.title, page: page } }

  @page_structure = {}
  @pages.each do |page_data|
    page_slug = page_data[:key]
    page = page_data[:page]

    sections = LeanCms::PageContent
                .where(page_id: page.id)
                .select(:section, :section_order, :display_title)
                .distinct
                .order(:section_order)
                .pluck(:section, :display_title)
                .uniq

    @page_structure[page_slug] = sections.map do |section, display_title|
      {
        section: section,
        display_title: display_title || section.humanize,
        field_count: LeanCms::PageContent.where(page_id: page.id, section: section).count,
        last_updated: LeanCms::PageContent.where(page_id: page.id, section: section).maximum(:updated_at),
        has_cards: LeanCms::PageContent.where(page_id: page.id, section: section, key: 'cards').exists?,
        has_bullets: LeanCms::PageContent.where(page_id: page.id, section: section, key: 'bullets').exists?
      }
    end
  end
end

#preview_undo_fieldObject



280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
# File 'app/controllers/lean_cms/page_contents_controller.rb', line 280

def preview_undo_field
  @field = LeanCms::PageContent.find(params[:id])

  previous_version = @field.versions.where(event: 'update').last

  if previous_version && previous_version.object
    previous_state = YAML.safe_load(
      previous_version.object,
      permitted_classes: [Symbol, Time, ActiveSupport::TimeWithZone, ActiveSupport::TimeZone, Date, DateTime],
      aliases: true
    )

    old_value = previous_state['value']

    if old_value
      render json: {
        success: true,
        current_value: @field.display_value.to_s,
        previous_value: old_value.to_s
      }
    else
      render json: { success: false, error: 'Could not extract previous value' }, status: :unprocessable_entity
    end
  else
    render json: { success: false, error: 'No previous version found' }, status: :not_found
  end
end

#undo_fieldObject



308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
# File 'app/controllers/lean_cms/page_contents_controller.rb', line 308

def undo_field
  @field = LeanCms::PageContent.find(params[:id])
  
  # Get the most recent version from PaperTrail
  previous_version = @field.versions.where(event: 'update').last
  
  if previous_version && previous_version.object
    # Parse the object to get the previous state
    # The 'object' column contains the state BEFORE the change
    previous_state = YAML.safe_load(
      previous_version.object, 
      permitted_classes: [Symbol, Time, ActiveSupport::TimeWithZone, ActiveSupport::TimeZone, Date, DateTime],
      aliases: true
    )
    
    Rails.logger.info "Previous state: #{previous_state.inspect}"
    
    # Extract the old value
    old_value = previous_state['value']
    
    if old_value
      # Set the old value back
      case @field.content_type.to_sym
      when :rich_text
        @field.rich_content = old_value
      else
        @field.value = old_value
      end
      
      @field.last_edited_by = current_user
      
      if @field.save
        Rails.logger.info "Field reverted to previous version. New value: #{@field.reload.display_value.inspect}"
        
        # Clear cache
        clear_page_cache(@field)
        
        render json: {
          success: true,
          value: @field.display_value,
          message: 'Reverted to previous version'
        }
      else
        render json: {
          success: false,
          error: 'Failed to save reverted version'
        }, status: :unprocessable_entity
      end
    else
      render json: {
        success: false,
        error: 'Could not extract previous value'
      }, status: :unprocessable_entity
    end
  else
    render json: {
      success: false,
      error: 'No previous version found'
    }, status: :not_found
    end
end

#updateObject



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'app/controllers/lean_cms/page_contents_controller.rb', line 61

def update
  @page = params[:page]
  @section = params[:section]

  success = true
  errors = []

  # Find the LeanCms::Page by slug
  page_record = LeanCms::Page.find_by(slug: @page)

  # Handle business hours special case (hours_json field)
  if params[:hours_labels].present? || params[:hours_note].present?
    hours_json_field = if page_record
      LeanCms::PageContent.find_by(page_id: page_record.id, section: @section, key: 'hours_json')
    else
      LeanCms::PageContent.find_by("page = ? AND section = ? AND key = ?", @page, @section, 'hours_json')
    end
    if hours_json_field
      hours_data = {
        'hours' => build_hours_array,
        'note' => params[:hours_note].to_s
      }
      hours_json_field.value = hours_data.to_json
      hours_json_field.last_edited_by = current_user
      unless hours_json_field.save
        success = false
        errors << "Hours: #{hours_json_field.errors.full_messages.join(', ')}"
      end
    end
  end

  # Handle bullets special case
  if params[:bullet_items].present? && params[:bullets_field_id].present?
    bullets_field = LeanCms::PageContent.find_by(id: params[:bullets_field_id])
    if bullets_field
      bullets_array = params[:bullet_items].map(&:to_s).reject(&:blank?)
      bullets_field.value = bullets_array.to_json
      bullets_field.last_edited_by = current_user
      unless bullets_field.save
        success = false
        errors << "Bullets: #{bullets_field.errors.full_messages.join(', ')}"
      end
    end
  end

  # Update each field in the section
  content_params = params[:page_contents] || {}

  content_params.each do |field_id, field_data|
    content = LeanCms::PageContent.find(field_id)
    content.last_edited_by = current_user

    # Handle different content types
    if content.rich_text?
      content.rich_content = field_data[:value]
    elsif content.image? && field_data[:image_file].present?
      content.image_file.attach(field_data[:image_file])
    elsif content.boolean?
      content.value = (field_data[:value] == '1' || field_data[:value] == 'true').to_s
    elsif content.cards?
      # For cards, the value is already JSON from the hidden input
      cards_json = JSON.parse(field_data[:value]) rescue []

      # Don't overwrite existing cards with an empty array — the cards editor
      # hidden input may be blank when editing other fields in the same section form.
      if cards_json.empty? && content.value.present?
        existing = JSON.parse(content.value) rescue []
        next if existing.any?
      end
      
      # Handle image uploads for cards
      if field_data[:card_images].present?
        # card_images is a hash with index keys: {"0" => file, "1" => file}
        field_data[:card_images].each do |index_str, image_file|
          index = index_str.to_i
          next unless image_file.present? && cards_json[index].present?
          
          # Attach the image to card_images collection
          blob = ActiveStorage::Blob.create_and_upload!(
            io: image_file,
            filename: image_file.original_filename,
            content_type: image_file.content_type
          )
          
          # Attach blob to the PageContent's card_images
          content.card_images.attach(blob)
          
          # Store blob ID in card data
          cards_json[index]['image_id'] = blob.id.to_s
          cards_json[index]['use_image'] = true
        end
      end
      
      # Update cards JSON with image IDs
      content.value = cards_json.to_json
    else
      content.value = field_data[:value]
    end

    unless content.save
      success = false
      errors << "#{content.label}: #{content.errors.full_messages.join(', ')}"
    end
  end

  if success
    # Clear cache for this page.
    # SolidCache does not support delete_matched, so enumerate keys explicitly.
    page_slug = @page.to_s
    cache_scope = page_record ?
      LeanCms::PageContent.where(page_id: page_record.id) :
      LeanCms::PageContent.where("page = ?", page_slug)

    cache_scope.pluck(:section, :key).each do |sec, k|
      Rails.cache.delete("page_content/#{page_slug}/#{sec}/#{k}")
    end
    cache_scope.distinct.pluck(:section).each do |sec|
      Rails.cache.delete("page_section/#{page_slug}/#{sec}")
    end
    Rails.cache.delete("page_structure/#{page_slug}")
    Rails.cache.delete("page_cards/#{page_slug}/#{@section}")
    Rails.cache.delete("page_bullets/#{page_slug}/#{@section}")
    
    # Touch the LeanCms::Page to bust fragment cache
    page_record&.touch

    redirect_to lean_cms_page_contents_path, notice: 'Content updated successfully.'
  else
    redirect_to edit_lean_cms_page_content_path(page: @page, section: @section),
                alert: "Errors: #{errors.join('; ')}"
  end
end

#update_fieldObject



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'app/controllers/lean_cms/page_contents_controller.rb', line 194

def update_field
  @field = LeanCms::PageContent.find(params[:id])
  @field.last_edited_by = current_user

  # Log what we're updating
  Rails.logger.info "Updating field ##{@field.id}: #{@field.page}/#{@field.section}/#{@field.key}"
  Rails.logger.info "Old value: #{@field.value.inspect}"
  Rails.logger.info "New value: #{params[:value].inspect}"
  Rails.logger.info "Content type: #{@field.content_type}"

  case @field.content_type.to_sym
  when :text, :url, :color, :dropdown
    @field.value = params[:value]
  when :rich_text
    @field.rich_content = params[:value]
  when :boolean
    @field.value = (params[:value] == '1' || params[:value] == 'true').to_s
  when :cards
    # Cards are sent as JSON string
    cards_json = JSON.parse(params[:value]) rescue []
    
    # Handle image uploads for cards
    if params[:card_images].present?
      # card_images is a hash with index keys: {"0" => file, "1" => file}
      params[:card_images].each do |index_str, image_file|
        index = index_str.to_i
        next unless image_file.present? && cards_json[index].present?
        
        # Attach the image to card_images collection
        blob = ActiveStorage::Blob.create_and_upload!(
          io: image_file,
          filename: image_file.original_filename,
          content_type: image_file.content_type
        )
        
        # Attach blob to the PageContent's card_images
        @field.card_images.attach(blob)
        
        # Store blob ID in card data
        cards_json[index]['image_id'] = blob.id.to_s
        cards_json[index]['use_image'] = true
      end
    end
    
    @field.value = cards_json.to_json
  when :bullets
    # Bullets can come as JSON string or array
    if params[:value].is_a?(Array)
      @field.value = params[:value].to_json
    else
      @field.value = params[:value]
    end
  when :image
    if params[:image_file].present?
      @field.image_file.attach(params[:image_file])
    end
  end

  if @field.save
    Rails.logger.info "Field saved successfully. New display value: #{@field.reload.display_value.inspect}"
    
    # Clear cache
    clear_page_cache(@field)

    render json: {
      success: true,
      value: @field.display_value,
      message: 'Content updated successfully'
    }
  else
    Rails.logger.error "Failed to save field: #{@field.errors.full_messages.join(', ')}"
    render json: {
      success: false,
      errors: @field.errors.full_messages
    }, status: :unprocessable_entity
  end
end