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:
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:
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.rbrequire'nokogiri'classAssetUrlReplacerattr_reader:assetdefinitialize(asset)@asset=assetenddefasset_typeifasset.is_a?(Refinery::Image)"image"else"file"endenddefasset_nameasset_type+"_name"enddefreferencesRefinery::PagePart::Translation.where("body like ?","%#{asset.send(asset_name)}%")enddefupdate_asset_referencesreferences.eachdo|translation|html=Nokogiri::HTML.fragment(translation.body)replace_attributes(html,"a",:href)replace_attributes(html,"img",:src)translation.body=html.to_htmltranslation.saveendenddefreplace_attributes(html,tag,attribute)if(tags=html.css(tag)).any?tags.eachdo|element|ifelement[attribute].include?(asset.send(asset_name))&&element[attribute].include?("/system/")element[attribute]=asset.send(asset_type).urlendendendendend
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.
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."
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.
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.
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.