Tolase Adegbite
Tolase Adegbite

Reputation: 33

How to automatically update dominant color of an image in Rails 7 using MiniMagick after image upload or change?

I am working on a Rails 7 application and I'm trying to implement a feature where I calculate and update the dominant color of an event image whenever it is uploaded or changed. I'm using MiniMagick to process the image, and I want to store the dominant color in a dominant_color column in the events table.

What I am trying to achieve:

What I’ve implemented so far:

I’ve created a dominant_color column in my events table and wrote the following code in my Event model to calculate and store the dominant color when the image is attached or changed:

# app/models/event.rb

require 'mini_magick'

class Event < ApplicationRecord
   # Change to after_commit and use a different detection method
  after_commit :check_and_update_dominant_color, on: [:create, :update]

  private

  def should_update_dominant_color?
    image.attached? && 
    (saved_change_to_attribute?('image_attachment_id') || image.attachment&.saved_change_to_blob_id?)
  end

  def update_dominant_color
    return unless image.attached?

    # Ensure we're working with the actual blob data
    image.open do |tempfile|
      img = MiniMagick::Image.read(tempfile)
      img.resize '1x1'
      pixel = img.get_pixels[0][0]
      hex_color = rgb_to_hex(pixel)
      
      # Use update_column to avoid callbacks
      update_column(:dominant_color, hex_color)
    end
  end

  def rgb_to_hex(rgb_array)
    "#" + rgb_array[0..2].map { |c| c.to_s(16).rjust(2, '0') }.join
  end
end

Problem:

What I’ve tried:

My questions:

  1. Is there a more efficient or reliable way to detect changes to the image attachment that would guarantee the dominant color is updated correctly?
  2. Is using after_commit the best approach for this, or should I consider a different callback?
  3. Any tips on optimizing this process or handling edge cases like image deletion or updates?

I’d really appreciate any feedback, especially from those who’ve worked with MiniMagick or have implemented similar features. Thanks!

Edit: Testing the color extraction manually in the console worked

event = Event.find(3)
event.send(:update_dominant_color)
event.reload.dominant_color

Upvotes: 0

Views: 46

Answers (1)

Igor Kasyanchuk
Igor Kasyanchuk

Reputation: 774

Check why this doesn't work

  def should_update_dominant_color?
    image.attached? && 
    (saved_change_to_attribute?('image_attachment_id') || image.attachment&.saved_change_to_blob_id?)
  end

maybe there is some other way to check if the image was changed.

You can try to use some other callback like "before_save" and check if an image was changed and set some flag. And later use "after_commit" and that flag to run your logic.

In general I think your code should be working but difficult to say why not. What gem are you using for attachments?

Upvotes: 0

Related Questions