Auto Update Assets In Refinery

by Jess Brown

Refinery uses the Dragonfly gem to upload images and files. It's a really nice gem, but there is a problem when using it in RefineryCms. The problem is, that every time you update an image or file with Dragonfly, you get a new url to the asset. Dragonfly uses a job id in the asset url to encode the path to the image. So the image url may look like:

/system/resources/W1siZiIsIjIwMTQvMTEvMjYvMThfMTZfMjdfNzA4X3Rlc3QucGRmIl1d/test.pdf

and the path to the image is would look like 2014/11/26/18/16/27/708/test.pdf, which you'll see is a directory path of a timestamp.

So what's the problem?

If you link to this pdf in 10 pages of content, and later someone comes up with an edit to the pdf, you'll need to reupload the pdf, which will generate a new link to the pdf and break all of the links to the old version. This is really annoying because people like to update pdf's and images quite frequently and are used to updating the file or image without breaking the links.

How to fix?

Originally I tried to figure out a way to configure Dragonfly so that it would not regenerate the path or that maybe it would not use such a specific timestamp method of creating the directory. I could not figure this out. Plus, if do you that, then you still have an issue with caching, especially if you're using a CDN like CloudFront (note the remark about fingerprinting if you visit the link).

Then I had a thought. What if we just automated the updating of links each time an asset was updated? Well, I started exploring and it turns out it's pretty easy. Here's how it works.

First you need an after_update hook for the Resource (files) and Image models. Since these models are in the refinery gem, the best way is to use a decorator:

# app/decorators/models/refinery/image_decorator.rb
Refinery::Image.class_eval do
  include UpdateAssetReference
end

# app/decorators/models/refinery/resource_decorator.rb
Refinery::Resource.class_eval do
  include UpdateAssetReference
end

I created a concern here so we're not duplicating the content in both models:

# app/models/concerns/update_asset_reference.rb
module UpdateAssetReference
  extend ActiveSupport::Concern

  included do
    after_update :update_asset_references
  end

  def update_asset_references
    AssetUrlReplacer.new(self).update_asset_references
  end
end

In the concern, all we do is create the after_update hook and then pass in the instance of the file or image model to the AssetUrlReplacer, which is where all the real work is done.

# app/models/asset_url_replacer.rb
require 'nokogiri'

class AssetUrlReplacer
  attr_reader :asset

  def initialize(asset)
    @asset = asset
  end

  def asset_type
    if asset.is_a?(Refinery::Image)
      "image"
    else
      "file"
    end
  end

  def asset_name
    asset_type + "_name"
  end

  def references
    Refinery::PagePart::Translation
        .where("body like ?", "%#{asset.send(asset_name)}%")
  end

  def update_asset_references
    references.each do |translation|
      html = Nokogiri::HTML.fragment(translation.body)
      replace_attributes(html, "a", :href)
      replace_attributes(html, "img", :src)
      translation.body = html.to_html
      translation.save
    end
  end

  def replace_attributes(html, tag, attribute)
    if (tags = html.css(tag)).any?
      tags.each do |element|
        if element[attribute].include?(asset.send(asset_name)) 
          && element[attribute].include?("/system/")
          element[attribute] = asset.send(asset_type).url
        end
      end
    end
  end
end

Since the resource and image models use different method names to get the image url, we have to do a little meta programming. Other than that, the logic is rather straight forward. First we search for any references to the asset's file name. Then we loop through those records and search for either links or images that are referencing the file name. If there's a match, we update the html and save the record. We use nokogiri to parse the html so we don't have

That's it. Now whenever a client updates their files or images, they will be replaced in the content if they are referneced there.

What do you think? See any issues??

Do Good And Share With Others

by Jess Brown

This morning during my quiet / devotion / reflection time, I came across this Bible devotional. The focal point was a bible verse, Hebrews 13:16 that simply says: "remember to be good and share with others".

It's such a simple concept and yet...

I like to post things like this to help me remember. Sometimes it's just a postit note, or sometimes it's a framed calligraphy, but this time I wanted to make a desktop and iPhone wallpaper and like the verse says, "share it."

The font I used was Tablet Gothic Compressed from Typekit.

Here's the desktop version. Click to get the hi res version.

Here's the iPhone version:

October Mountain Trip 2014

by Jess Brown

Every year my family and extended family and friends take a trip up to the North Georgia Mountains. I thought I'd share some photos from our trip. The weather was beautiful!

Helton Creek Falls

Helton Creek is back a ways off Hwy 129 and it takes a little while to get to, but the ride is really nice. It's not much of a hike (just a few stairs) but worth the trip.

Drive through a few streams to get there!

You can see the falls from the road.


A video posted by Jess Brown (@bjessbrown) on

You have to hold on to this guy to keep him out of the water!

Sorghum Festival

The Sorghum Festival is an annual event held in Blairsville, GA each year. They actually make sorghum at the event!

There's fun stuff for the kids to do too!



Hiking the Appliciation Trail

We had the kids, so Patty and I didn't end up going too far...

But the views were great!

Hiking around Vogel State Park

Vogel is one of my favorite parks in Georgia. There's a lot of great hiking leaving from the park.

Gotta have hiking sticks!

Georgia Mountain Fair

Lots of crafts and food, and of course...toys for the kids.

A bit of history (glad I don't have to mow the grass with that)


Lots of demos on soap making, blacksmithing, broom making, moonshine, and even a real sawmill...

Learning Ember

by Jess Brown

Recently I've been working on a new product for my company and I decided it was a good fit for Ember. I'm just now learning Ember so it's a new endeavor for me.

I got about 60% of the way through the project and hit somewhat of a wall. I've gone about as far as the introduction tutorials I've found take you.

I've been pretty comfortable in my role as a senior or advanced rails developer for some time now. Not that I don't struggle or work on hard problems, but rails as a framework isn't getting in my way or slowing me down. I'm able to focus on my problems and not focus on the framework.

Now that I'm learning ember, I'm reminded of back when I was learning rails and how difficult and frustrating it can be to learn something new. To solve a simple problem, it requires a lot of digging and learning. But that's the price you pay for learning a framework. In a recent talk I gave about learning rails, I explained that it was difficult to learn rails (or any framework for that matter), but that the investment was well worth it.

I spent about 10-15 minutes live coding with them went through doing a quick prototype of their website. I saw some pretty impressed smiles from the crowd when they saw rails work it's magic.

I struggle with this upfront cost, but have to take some of my own medicine every now and then remember that it's worth it in the long run.

Writing Challenge Update

by Jess Brown

A few weeks ago, I took a blogging challenge and I failed in my goal of writing for 30 straight business days. I started on 9/1 and did pretty good for 3 straight weeks, writing 15 blog posts in total. My downfall was 2 weeks. My goal at the beginning of the challenge was to write at least 1 case study / white page on a recent project we'd completed. I figured it would take me about the same amount of writing 3 blog posts, so I set aside 3 days to complete it.

I did start it and I did write for those three days, but there was just too much to it all. I wanted to chronicle the step by step process we took in redesigning the www.montlick.com website. I had a lot of photos, screen shots, notes and sketches to pour over.

I'm still in the process of writing it and hope to publish it soon.

Couple of lessons learned...

Consistancy is hard

Doing anything consistently is hard. If you really want to do something consistently, you have to be truly dedicated to it...whether you're exercising, dieting, working, or blogging.

Long term goals are more difficult to achieve

When I was blogging daily, it was easier to publish something. The goal was clear, the end result was within grasp. I did fall behind once or twice, but I didn't want to miss a day so I always caught up. By contrast, the 3 days I spent writing the white paper was more ambiguous. I wasn't sure how much I needed to complete each day. Also, the goal of three days was not set in stone.

I liken this small example to working on creative projects, which are notorious for being late and over budget. If an overall project deadline is not set with milestones along the way, then there's usually a good chance the project will drag on and on. I learned this early on in my business. I'd have 2-3 larger projects to work on but also daily small tasks on existing projects. It's so easy to take care of the small tasks and forgo the dedication it takes to working on something due 3 months away.

Summary

Good habits are hard to form. Starting small and committing to be consistant are key.


Navigation