Showing posts with label haml. Show all posts
Showing posts with label haml. Show all posts

Monday, August 15, 2011

MailMatic: HTML emails using Haml and Sass

Developing static HTML emails is a pain in the butt. For best results, you need to inline all of your styles at HTML attributes instead of using real CSS (externally or inline). You also typically find yourself being very repetitive with your markup if you have a bunch of static emails that share common elements.

MailMatic to the rescue.

MailMatic is a Ruby gem, that is really just a mashup of tools, that aims to ease the burden of creating and maintaining static HTML emails. It uses StaticMatic, Haml, Sass, and Compass to let you author your HTML emails with all of the facilities you enjoy while creating your dynamic site: templates, partials, helper functions, inline Ruby code, reuse of markup and styles, etc. It uses Premailer to convert the HTML/CSS generated from Haml/Sass into self-contained HTML files that inline all of their styles. Premailer even gives you warnings about styles that may not work nicely in certain email readers.

Armed with this, you can accelerate your ability to crank out static HTML emails, and lessen the burden of maintaining them.

To get started with MailMatic, check out its installation and usage instructions on github at: https://github.com/scottwb/mailmatic.

Saturday, April 17, 2010

How to detect what other sites your visitors have been to

When someone visits your site, do you want to know where else they've been? Maybe you want to know if they've been to a competitor or affiliate site so you can make them special offers. Maybe you want to intelligently suggest they signup for your site with Facebook Connect, Twitter, Google OpenID, or Yahoo! ID, based on which of those sites you know they frequent. Maybe you're just nosy.

Regardless, there are pretty good controls in place with most browser to prevent you from developing javascript on your site that can sniff the user's browser history. There's one small loophole though...you can stick all the URLs you want to know about in your page, and test to see if they have been visited, using the CSS selector features of javascript frameworks such as jQuery and Prototype.js. This is not a fool-proof way to tell where they've been, but it might just be good enough for the kinds of suggestions you want to make to your user.

Based on ideas from Spyjax (described in this blog post), I whipped up a simpler demonstration of this using Haml to make a hidden list of URLs and, instead of trying to sniff links by their colors, using Prototype.js to detect which of them have been visited. This could have just as easily been done in jQuery:



One extension to this technique, if you have lots of URLs to test, might be to dynamically load 100 at a time via AJAX periodically, and asynchronously trigger actions in your page when visited URLs are detected.

Isn't that a little creepy? What if I don't want sites to get this info about me?

The Spyjax blog post linked to earlier has a decent answer for this:

The less browser history you store the fewer URLs someone can steal from that history. In Firefox you can change the amount of browser history by going to Tools -> Options -> Privacy and then either uncheck the “Remember visited pages” checkbox or change the number of days that history is stored for.

Sunday, November 30, 2008

Sharing a partial for both server-side and client-side HTML generation.

Say I have a page that shows a table of items (like a shopping cart), and I want to be able to generate the HTML for this table from the server-side (of course). Let's also say that I want to have client-side javascript be able to dynamically add items to this table without a round-trip to the server, based on data gathered on the client. What I end up with is some HTML code (actually, ERb or Haml) that defines the layout of a row in this table, and a duplicate piece of code in javascript that generates identical HTML. The server-side code uses a nice templating language like Haml to fill in the variable pieces, while the client-side code pieces together HTML embedded in strings concatenated with the dynamic data.

Not very DRY. Not easy to maintain. Not pretty to look at.

So...What's a good solution that allows me to write the HTML once, and have one place to maintain it, while still being able to use it to dynamically evaluate the template based on parameterized data on both the server and client sides?

Below is a solution that I came up with. (And I would love to hear any better ideas).

For brevity, I'll use a very simple HTML structure in these examples, but in practice I have used this with much more complex structure and logic. Here's what our example table looks like:


<table id="items">
<tr>
<td class="name">Shirt</td>
<td class="desc">White short-sleeved shirt</td>
<td class="price">$5.99</td>
</tr>

<tr>
<td class="name">Pants</td>
<td class="desc">Blue pants with zipper</td>
<td class="price">$25.99</td>
</tr>
</table>


Assume we have this built using Haml, and there are two partials: one for the top-level table, and one for an individual row. E.g.:

items_table.haml:

%table#items
- items.each do |item|
= render :partial => 'item_row', :locals => {:item => item}


item_row.haml:

%tr
%td.name= item.name
%td.desc= item.desc
%td.price= item.price


In the client-side javascript in our top-level Haml partial, assume we have some function that gets called from some user input action (like filling out a form and clicking a button). E.g.:


:javascript
var addItem = function(name, desc, price) {
var html =
"<tr>" +
" <td class=\"name\">" + name + "</td>" +
" <td class=\"desc\">" + desc + "</td>" +
" <td class=\"price\">" + price + "</td>" +
"</tr>";
$('items').insert(html); // using prototype.js
};


OK...so this doesn't seem so bad with such a simple example, but imagine that the HTML structure for a table row is something much more complex, with conditionals based on the item, and maybe even usage of additional sub-partials. This maintenance for this becomes a nightmare.

This first thing I am going to do is change the item_rows.haml partial. Instead of having it actually render the item's values, it's going to render template replacement variables using #{...} syntax. Note, these are NOT interpolated in the partial. We'll do that in a separate phase from rendering:

item_row.haml:

%tr
%td.name #{item_name}
%td.desc #{item_desc}
%td.price #{item_price}


Next, let's make a couple helper methods. The first one returns this partial rendered as a string. (I do this because in the real world, this takes a number of parameters, and adding a helper layer makes things easier to manage than always calling render directly). The second one renders this partial and then interpolates the #{...} strings inside it, based on the properties of the item we want to render -- effectively making this equivalent to rendering the original version of this template.

item_helper.rb:

module ItemHelper
# Make ActionController::Base#render_to_string available.
helper_method :render_to_string

def item_row_template
render_to_string :partial => item_row
end

def item_row(item)
# Get the template.
t = item_row_template

# Define the template replacement variables.
item_name = item.name
item_desc = item.desc
item_price = item.price

# Evaluate the template
eval(t.inspect.gsub("\\#", "#"))
end
end


This, of course, means we change the top-level partial to use this new item_row helper, like so:

items_table.haml:

%table#items
- items.each do |item|
= item_row(item)


At this point, we've got a functionally equivalent server-side. But the big benefit is that now the HTML template returned by the item_row_template helper method can also be used to do the same substitutions on the client side, thanks to the handy Template class in prototype.js. The Haml that defines the javascript addItem method now looks like this:


:javascript
var addItem = function(name, desc, price) {
var html = new Template(
'#{escape_javascript(item_row_template)}'
).evaluate({
item_name : name,
item_desc : desc,
item_price : price
});
$('items').insert(html);
};


Now, when the markup for the item row changes, it only needs to change in one place, and both the server-side and client-side benefit from it. This certainly feels more DRY...but also seems like a hefty price to pay in terms of complexity...

Monday, November 17, 2008

Bug in Haml Partial Rendering?

I have stumbled across what I think is a bug in rendering a Haml partial in Ruby on Rails. The issue is that when I use render(:partial => '...', :locals => {...}), and one of the locals I define is a Boolean, it seems that if I pass a value of false, that value erroneously gets converted to nil. This causes a problem with a partial that wants to treat false, true, and nil as meaning different things.

Consider the following example:

I have a simple TestController:

class TestController < ApplicationController
def index
end
end


Then, the haml template for that controller:

!!!
%html
%head
%title haml partial test
%body
%b Rendering a Haml Partial
%br
= render :partial => 'test_haml', :locals => {:flag1 => true, :flag2 => false}

%hr
%b Rendering an RHTML Partial
%br
= render :partial => 'test_rhtml', :locals => {:flag1 => true, :flag2 => false}


Notice that partial renders two partials. One is a haml partial, one is an rhtml partial. The rthml one behaves as I would expect, the haml one does not.

Here is what the haml partial looks like:

- if flag1 == false
flag1 is false
- elsif flag1 == true
flag1 is true
- elsif flag1 == nil
flag1 is nil
- else
= "flag1 is #{flag1.inspect}"

%br
%br

- if flag2 == false
flag2 is false
- elsif flag2 == true
flag2 is true
- elsif flag2 == nil
flag2 is nil
- else
= "flag2 is #{flag2.inspect}"


Here is what the rhtml partial looks like:

<% if flag1 == false %>
flag1 is false
<% elsif flag1 == true %>
flag1 is true
<% elsif flag1 == nil %>
flag1 is nil
<% else %>
flag1 is <%= flag1.inspect %>
<% end %>






<% if flag2 == false %>
flag2 is false
<% elsif flag2 == true %>
flag2 is true
<% elsif flag2 == nil %>
flag2 is nil
<% else %>
flag2 is <%= flag2.inspect %>
<% end %>


Here is what the output looks like:



Notice the discrepancy between the output of the haml partial versus the rhtml partial, with respect to flag2.

This is gonna turn out to be a real drag on a project that I am converting from rhtml to haml that has a number of partials that assume that false means false and not nil.

Anybody out there have any thoughts on this?