Skip to content

Instantly share code, notes, and snippets.

@frankie-loves-jesus
Last active August 29, 2015 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save frankie-loves-jesus/b86a6678b7ec779992a7 to your computer and use it in GitHub Desktop.
Save frankie-loves-jesus/b86a6678b7ec779992a7 to your computer and use it in GitHub Desktop.

Paperclip animated GIF to MP4

Problem: stack level too deep

SystemStackError in Forem::TopicsController#create
stack level too deep

actionpack (4.1.2) lib/action_dispatch/middleware/reloader.rb:79

photo.rb

class Photo < ActiveRecord::Base
  belongs_to :post, class_name: "Forem::Post"

  ATTACHMENT_STYLES = lambda do |attachment|
    if animated_gif?(attachment)
      {medium: {format: "flv"}, thumbnail: {format: "png"}}
    else
      {medium: "x300>", thumbnail: "50x50#"}
    end
  end
  ATTACHMENT_PROCESSORS = lambda { |instance| animated_gif?(instance.attachment) ? [:ffmpeg] : [:thumbnail] }

  has_attached_file :attachment,
    styles: ATTACHMENT_STYLES,
    processors: ATTACHMENT_PROCESSORS,
    url: "/:class/:attachment/:id/:style_:filename",
    path: ":rails_root/public/system/:attachment/:id/:style/:filename"
    
  validates_attachment :attachment, presence: true, content_type: { content_type: ["image/jpg", "image/jpeg", "image/png", "image/gif"] }
  
  def self.animated_gif?(attachment)
    attachment_path = attachment.instance.new_record? ? attachment.queued_for_write[:original].path : attachment.path
    rmagick = Magick::ImageList.new(attachment_path)

    if attachment.content_type =~ /gif/ && rmagick.scene > 0
      return true
      
      # http://stackoverflow.com/questions/19338570/set-a-boolean-value-to-false
  
      update_attribute(:attachment_is_animated, true)
    end
  end
end

application_helper.rb

module ApplicationHelper
  def animated_gif?(photo)
    true if photo.attachment_is_animated?
  end
end

_post.html.erb

<% for photo in post.photos %>
  <% if animated_gif?(photo) %>
    <%= video_tag photo.attachment.url(:medium) %>
  <% else %>
    <%= image_tag photo.attachment.url(:medium) %>
  <% end %>
<% end %>

Database

rails generate migration AddAttachmentIsAnimatedToPhotos

class AddAttachmentIsAnimatedToPhotos < ActiveRecord::Migration
  def self.up
    add_column :photos, :attachment_is_animated, :boolean
  end

  def self.down
    remove_column :photos, :attachment_is_animated, :boolean
  end
end

Log in with admin@example.com / admin1234 in order to upload.


@billguy
Copy link

billguy commented Dec 4, 2014

Try this instead:

ATTACHMENT_PROCESSORS = lambda { |photo| is_animated_gif?(photo.attachment) ? [:ffmpeg] : [:thumbnail] }

https://github.com/thoughtbot/paperclip#dynamic-processors

@billguy
Copy link

billguy commented Dec 5, 2014

self.is_animated_gif? should probably be something like:

  def self.is_animated_gif?(attachment)
    attachment_path = attachment.instance.new_record? ? attachment.queued_for_write[:original].path : attachment.path
    rmagick = Magick::ImageList.new(attachment_path)
    true if attachment.content_type =~ /gif/ && rmagick.scene > 0
  end

You'll probably need to explicitly set the url & path for has_attached_file : attachment to avoid Paperclip::Errors::InfiniteInterpolationError.

Moreover, running the same attachment through rmagick every time seems like a code smell. Perhaps adding a bool 'attachment_is_animated' attribute on your db and setting it once might be more efficient.

You can put is_animated_gif? into a helper and call it from your model with YourController.helpers.is_animated_gif?

@billguy
Copy link

billguy commented Dec 8, 2014

class Photo < ActiveRecord::Base
  belongs_to :post, class_name: "Forem::Post"

  has_attached_file :attachment,
                    styles: {
                        medium_animated: { geometry: "100x100", format: "flv", time: 0.1, processors: [:ffmpeg] },
                        medium: "x300>",
                        thumbnail_animated: { geometry: "50x50", format: "png", time: 0.1, processors: [:ffmpeg] },
                        thumbnail: "50x50#"
                    }

  before_save :set_is_animated_gif

  validates_attachment :attachment, presence: true, content_type: { content_type: ["image/jpg", "image/jpeg", "image/png", "image/gif"] }

  def attachment_url(style = :medium)
    style = is_animated_gif ? "#{style.to_s}_animated".to_sym : style
    attachment.url(style)
  end

  private

    def set_is_animated_gif
      attachment_path = attachment.queued_for_write[:original] ? attachment.queued_for_write[:original].path : attachment.path
      rmagick = Magick::ImageList.new(attachment_path)
      self.is_animated_gif = (attachment.content_type =~ /gif/ && rmagick.scene > 0)
    end

end

I assumed you're using https://github.com/owahab/paperclip-ffmpeg.
Then you can just call photo.attachment_url(:thumbnail) or photo.attachment_url(:medium) in your view.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment