Fleximage News - gem, S3 and Heroku
December 13th, 2009
First of all, yes I am a douchebag for no posting anything in forever. Life has been busy, but I’m starting to recollect my voice, and we will see how it goes.
So, Fleximage! recently a few things have gone into the popular image plugin.
1. Ruby Gem
gem install fleximage
Currently just 1.0.0, but you no longer need to install fleximage as a plugin. It now works as a gem. Just install the gem and add a config.gem 'fleximage' to your app’s initialization and you have finer version control and an all around cleaner way to manage your fleximage installation.
2. Amazon S3
You can now use Amazon S3 as a store for your master images.
1 2 3 4 5 6 7 8 9 10 11 12 |
class Photo < ActiveRecord::Base acts_as_fleximage do s3_bucket 'mywebsite-com-user-uploads' end end # a new initializer require 'aws/s3' AWS::S3::Base.establish_connection!( :access_key_id => 'my_s3_key_here', :secret_access_key => 'my_s3_secret_here' ) |
Now new Photos will be uploaded to and read from your Amazon S3 account. This isn’t super fast, but with proper page caching it shouldn’t be a big problem. And there are some server configurations where file system storage is not possible, and database storage is impractical.
Which brings us to…
3. Heroku
The S3 support now allows fleximage to run on Heroku without database image storage. Use S3 for storing your images, and you are done!
What about cacheing? you ask. Well Heroku uses Cache-Control headers to auto cache your content. And fleximage will automatically render it’s images with a 24 hour cache header. So it should just work. Just note that it’s not simple to expire a cached image. So i usually construct my fleximage models so that the image on a particular model will never change. Meaning that if I want a new image, I probably just want to delete that model and upload a new image to a new one. or you can just wait a day for the new image to reappear.
I’ll be working on better solutions to Heroku caching when I can, but for now this should work well enough for most apps.
Ruby Tricks you Probably knew but I didn't: Array#&
July 31st, 2009
I had to intersect 2 arrays today. Basically I had 2 arrays and wanted to only the objects that both arrays contain. Yeah, I could have done some select or reject loop, but I stumbled upon…
[:a, :b, :c, :d] & [:a, :c, :e]
#=> [:a, :c]
Who knew? I think I should really use operator overloading more often, and just so pleasing using an operator for an operation. Go figure.
Fleximage meets Aviary Phoenix
May 1st, 2009
Aviary has been some cool stuff lately. Recently they offered up an API that allows external images to be edited, and pushed back to the server they came from. I thought that it would be awesome if Fleximage made this easy, so here you go.
It’s fairly simple and only involves three lines of code added to your app, and I think it’s pretty badass. I’ve created a page all about how to take advantage of this new feature in the github wiki.
Fleximage displays virtual images
February 28th, 2009
In the past, Fleximage has been constrained to rendering uploaded images from uploaded sources. Resize, crop, apply effects, and send out to the client. Well what if you want to render an image, but the model data you want to render is not really image based? Introducing Fleximage::Blank.
Lets say you have a Comment model. A Comment belongs_to a User. For whatever reason, you need an image that represents any comment. This image might looks like this:
![]()
A template like this might create this image:
1 2 3 4 5 6 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 |
# app/views/comments/show.png.flexi Fleximage::Blank.new('400x150')).operate do |image| # Start with a chat bubble image as the background image.image_overlay('public/images/comment_bubble.png') # Assuming that the user model acts_as_fleximage, this will draw the users image. image.image_overlay(@comment.user.file_path, :size => '50x50', :alignment => :top_left, :offset => '10x10' ) # Add the author name text image.text(@comment.author, :alignment => :top_left, :offset => '10x10', :color => 'black', :font_size => 24, :shadow => { :blur => 1, :opacity => 0.5, } ) # Add the comment body text image.text(@comment.body, :alignment => :top_left, :offset => '10x90', :color => color(128, 128, 128), :font_size => 14 ) end |
Note that the Comment does not need a call to acts_as_fleximage. The Comment model itself has no image data in itself, but now it has an easy way to create an image based view of itself.
Checkout the wiki entry on GitHub for more info.
IE7 header issues
July 20th, 2008
I got to deploy a new build to TheWineSpies.com this weekend, which among many other things, upgraded the app to rails 2.1. This process had me refactoring the admin to be RESTfull-er, and incorporating the latest version of Fleximage. I thought everything was dandy.
The Problem
My client was doing some testing on this code with IE7, their browser of choice. But something odd was happening. They would click a link triggering a resources show action, and instead of a html page about that resource, they would just get the image. At first I was stumped. I never thought cross browser issues could change server behavior. Firefox got a page of HTML and IE7 got an image. And I confirmed that the server was actually sending different content to the different browsers. The truly bizarre part, was that after clicking a link to this page, you could refresh and get the content you were expecting.
What the hell?
The Code
The Wine Spies uses Fleximage enahnced models across a few different resources, but here is a simple action that was causing me grief.
1 2 3 4 5 6 7 8 9 10 |
def show @product = Product.find(params[:id]) respond_to do |format| format.html format.jpg { render :template => '/some/path/small.flexi' } format.xml { render :xml => @product.to_xml } end end |
This is pretty straightforward.
- If
htmlis requested, render the default template - If
jpgis requested, render some.flexitemplate - If
xmlis requested, dump the object to xml and send it out
But still, IE7 on a url of /products/123 would trigger the jpg format renderer. Somehow rails was thinking that IE7 wanted a jpeg image instead of HTML. Where other browser were making rails think they want HTML unless overridden by a format extension on the url.
Tracking down the cause
I began to think back to the DHH keynote “World of Resources” and some of the early stuff that was forming around rails, and luckily, I remembered something important. I tend to use this format pattern a lot, and I usually trigger it by url extensions like /products/123.jpg or /products/123.xml. But rails looks at something else too.
Your browser, or any HTTP client, sends along a header named HTTP_ACCEPT with any request. I decided to add some debug code to my action to see what was in this header:
raise request.headers['HTTP_ACCEPT'] |
In Firefox 3, the result was (minor edit for simplicity):
text/html,application/xhtml+xml,application/xml,*/* |
This is a comma separated list of MIME types. The purpose of this header is to let to receiver know what kind of data the client wants, or what it will “accept”. It’s a prioritized list where the first items are wanted more then the items at the end of the list. Firefox is saying “Please give me html. If you don’t have that give me xhtml. But I guess xml would be ok too if that’s all you got. You got none of those? Well give me whatever you got then, I don’t care.”
Ok what does IE7 send?
image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/ag-plugin, */* |
Until I refreshed the page, instead of clicking a link to this page, and got:
*/* |
What the hell?
IE7 doesn’t say it wants HTML at all! It says it would rather have a gif, bitmap, jpg, flash, or even a plugin, rather than any other MIME type, including html. Rails gets this header, and sees that is no explicit format on the URL, so it goes down the list:
- Does this action respond to the
image/gifformat? nope. - How about the
image/x-bitmapformat? no. - Maybe the
image/jpegformat? Oh look at that yes it does!
The item that would have matched the html renderer */* is too far down the list, and we don’t get to it before a suitable responder is found.
Since IE7 sends a different HTTP_ACCEPT of */* on a refresh, it is declaring it has no preferred format at all. Rails then renders the default: html.
The Solution
After trying many ways to capture the damn header, override it somehow, shoving some Mime::Type object into request.format, and other failed solutions, here is what I finally ended up with:
1 2 3 4 5 6 7 |
#application.rb before_filter :set_default_format def set_default_format params[:format] ||= 'html' end |
This basically tells rails to ignore the HTTP_ACCEPT header. If a format is not explicitly declared on the URL, then force it to be HTML. It’s as if every html page on the site has a .html appended to the URL.
And finally salvation from that circle of hell.
Conclusions
What makes a good HTTP_ACCEPT header? I think Firefox has it right. Being a web browser, its main job is to display HTML, with embedded media. So it should want HTML more than anything since the images are just there in support of the html (mostly anyway).
IE7 makes 2 mistakes:
- It sends different headers depending on how the page was loaded
- It states that is prefers images over HTML
HTTP headers are a powerful tool. They can make interfacing with web applications and API’s much cleaner. But as we depend on them increasingly, we need have a level of trust with the clients that people use to connect. IE7 said it wanted one thing, and I forced to create a hack in order to tell IE7 “No, you don’t really want that. You really want something else.” And that makes me sad.
I thought clients who don’t know what they want are pain, but now browsers have the same problem. IE7 is a huge improvement over IE6, however it obviously still has its issues for web developers. The simple fact is that both versions of this browser have cost me way too much time, and that means it cost me money. The number of hours I have spent troubleshooting issues like this, as well as CSS and javascript issues, is way more than I want to admit to.
And that makes cranky. So tell your parents, “Save a web developer. Switch to Firefox.” Then maybe the world will be a better place.
Rails Documentation Patches
May 21st, 2008
I have just commited a documentation patch to Rails which adds instructions on how to use ActiveResource::HttpMock to test your ActiveResource models. But the really cool thing is how easy it was to do.
If you ever have been frustrated because something wasnt documented clearly, or documented at all in the case of ActiveResource::HttpMock, I really encourage you to fix up that part of the rails documentation and commit a patch. The steps are simple:
- Read the docrails conventions wiki page
- Send lifo:”http://github.com/lifo” a message asking for commit access to the docrails project on GitHub. You may want to include a brief description of what you intend to fix, just so he knows your cool.
git clonethe docrails project, and write some documentation.rake rdocand review that the new documentation looks great when converted to HTML.git commitandgit push, and you are now a rails contributor!
A useful tool in this endeavor was rstakeout. It’s a script by Geoffrey Grossenbach that allows to run a command everytime a set of watched files changed. You can use it to run tests, compile HAML or SASS outside of rails, or generate the documentation when you save.
Copy this script to somewhere in your PATH and make sure its executable. Remove the .rb extension so it can be called like any other command line program. Now when working on the documentation:
cdinto the rails component you are writing documentation for.rstakeout "rake rdoc" lib/**/*This will watch all files in all directories directly underlibfor changes. This is a typical glob format and you can use as many globs as you like if you want it to watch lots of files.
Now everytime you switch over the your browser, the newly generated docs will be up to date and waiting for you to preview them after a simple refresh. Sure does save you some time.
Fleximage now form redisplay safe
April 15th, 2008
There was a minor annoyance with all version of Fleximage up to this point. If you upload an image to a model, and validation fails for whatever reason, then you would have to find the image on your disk again, re-upload the image again, before you resubmit the form. Wouldn’t it be nice of the file stayed uploaded, even if the record isnt ready to be saved yet? How about getting a preview of the uploaded image too?
It’s all possible with the latest version of Fleximage up on GitHub. Checkout this GitHub wiki page for details.
Settings Plugin update
April 12th, 2008
Since GitHub makes open source so easy I opened up my old Settings plugin after almost a year and put it up with a few improvements.
Most importantly, I got the tests working. I also created a less ugly way of defining defaults:
1 2 3 4 5 6 |
Settings.defaults[:foo] = 'bar' # or Settings.defaults = { :foo => 'bar', :baz => 'faz', }.with_indifferent_access |
Ruby Experts
April 6th, 2008
Hey look, I’m a Ruby expert
Not sure how I stack up with people that wrote Ruby books… Had I realized that I was going to be quoted in such a manner, perhaps I would have answered with slightly more verbosity. Live and learn.
Heroku and the Hillcrest Development Watch
March 29th, 2008
A friend asked me to donate a tiny google maps application to a non-profit cause. The Hillcrest Development Watch monitor housing and construction in their area and they wanted an easier way to do it than emailing a spreadsheet around. Now, being a Rails programmer, of course I wanted to deal with this in Rails. Sadly Rails is a pain to host right?
Wrong. Enter Heroku. Their fantastic setup is free (for now). They create a git repository for your app when you create your app. Then you simply suck down that git, commit to it and push it back. Their server software automatically updates your working code and reboots your app to the latest code, simply by pushing your commits to the server. It is the least painful rails deployment process I have ever used. In fact, I would go so far as to call it pleasurable, which is a big deal to say about rails deployment.
Check out Hillcrest Development Watch
The site itself is a simple single resource web app. It tracks properties, their addresses and development states. For a supre small app like this, Heroku even provides access to its user login system. It lets you use the user logged into heroku.com as a user in your app. So if your needs are simple, you can have a user authentication system, and have your app not care about registration, authentication, or user management. This app simply show some admin function if the user is authorized to edit this heroku app. This wouldn’t stand up to the needs of anything more complex, but it saved a huge bundle of time for this project.
In case this lengthy prose didn’t convey my point:
Heroku is Aweome!
FleursFrance.com
February 21st, 2008
I have been developing a little site for the florist of my recent wedding. It’s a simple custom designed Rails CMS. Its got some page content management, a cool gallery manager, and of course, FlexImage is used to resize images and stamp them with a custom copyright.
The main problem with the images is that some were taken by the florist herself, but other are taken by professional photographers, and proper credit needed to be given. So I provided a simple text field that will write anything to the bottom left of an image allowing custom copyright on a per photo basis. And permanently stamping it on the image meaning it can’t be stolen, at least without a nasty cropping, but there is only so much you can do against that.
It’s been a fun little project.
Invisbly remember state with Ajax
July 22nd, 2007
A few times now I have used a useful pattern. The problem is that I want to remember the state of a javascript driven effect across multiple pages. For instance, one of my projects has a context sensitive administration pane that can be shown or hidden on any page. I want someone to be able to show this admin pane, go to another, and have the admin pane for that page already opened. Then I want them to be able to close the pane, and have it stay closed on all pages until it’s manually opened again.
How do manage this, when the opening and closing of the pane is entirely client side driven javascript? With Ajax, of course!
Read the rest of this entryHaml and Sass
June 23rd, 2007
I have now begun a project that I plan to do entirely and Haml and Sass. In case that’s Greek to you, checkout this page out.
So far, I like then both. Although I like Sass much more than Haml. Maybe it’s because CSS is more broken than XHTML as far as ease of authoring. And Sass greatly improves the ease CSS authoring. The constants, the nesting, the math. It’s all just brilliant. Sass improves CSS creation in virtually every way.
For example, here’s some Sass:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
body.home-index
img.photo
:float right
:margin-left 5px
h1
:text-align center
:line-height 0.9em
span
:font-size 26px
:color #5DB63C |
And the corresponding CSS:
1 2 3 4 5 6 7 8 9 10 11 |
body.home-index img.photo {
float: right;
margin-left: 5px; }
body.home-index h1 {
text-align: center;
line-height: 0.9em; }
body.home-index h1 span {
font-size: 26px;
color: #5DB63C; } |
Haml, on the other hand, does improve standard XHTML authoring quite a bit, but it comes with some drawbacks. I think this is mainly due to the whitespace restrictions. For instance, if I want this HTML.
1 2 3 4 5 6 7 8 |
<h1> Ruby<br /> <span>on</span><br /> Rails </h1> <p> Rails is <strong>Awesome!</strong> </p> |
I have to use this haml
1 2 3 4 5 6 7 8 9 |
%h1 Ruby %br/ %span on %br/ Rails %p Rails is %strong Awesome! |
I guess Haml handles the block level stuff well, but the inline markup can make your template messier and harder to understand than it’s XHTML equivalent.
The other thing that bothers me about Haml is the lack of closing tags. I know, this is by design of the language. But what I am used to is to create a closing tags along side every opening tags. The bodies of those tags get flushed out, and I know exactly where the next element goes based on the closing tag. With only indents to guide your nesting, I have had to scroll up and down in a big page and try to discern just where a particular element stops. Or what indent level to stick a new element.
Perhaps, I’m just set in my ways. I think I’ll get used to it, but it still bothers me a bit. And, to be clear, I still think this is an improvement on RHTML and plan to use it in more projects.
Short Version
- Haml: Cooler than Rhtml, most of the time.
- Sass: Utterly and Completely fantastic
New FlexImage website and repository
June 20th, 2007
This information is now old. A new version of the plugin can be found here with lots of instructions and examples.
FlexImage has officially been moved to RubyForge. Find all the new Goodies here:
fleximage.rubyforge.org
New SVN: svn://rubyforge.org/var/svn/fleximage
It’s got a new getting started guide, as well as an extensive examples section.
The README is still a bit out of date and I will hopefully be updating that soon. But this new site should make it far easier to get people up and running with FLexImage the right way, and get them doing it properly, with .flexi templates and all that jazz.
Just in time for me to show this off tomorrow night at the North Bay Ruby Users Group. All you Sonoma County Rubyists may as well stop on by!
super is awesome
June 7th, 2007
First of all, sorry for the lack of posting lately. I do have lots of goodies, it’s just been a bit crazy lately. I have transitioned from 9-5 desk job, to a chaotic and uncertain freelance-ish position. And yeah, it’s been a little nuts.
Anyways, on to some ruby goodness.
I am going to give a small example of how awesome the super method is. In case you don’t know super is a special method that executes the parent method of the same name. Confused? Try this simple example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Foo def bar 'Bar!' end end foo = Foo.new foo.bar # => 'Bar!' class Foo2 < Foo def bar "This method says: " + super end end foo2 = Foo2.new foo2.bar # => 'This method says: Bar!' |
When foo2 calls bar it calls super witch executes the method in the parent class with the same name. This lets us append something to the returned value without have any idea what it is.