Front-end Maintainability with Sass and Style Guides »
Created at: 20.01.2011 04:22, source: Engine Yard Blog, tagged: Uncategorized haml sass ui ux
At Engine Yard, the User Experience team works frequently on the front-end (HTML & CSS) of our application, AppCloud. It's also common that our Ruby developers write front-end code as well. When the UX team began realigning the AppCloud UI, it involved refactoring the HTML & CSS for better efficiency. We also created a style guide to document the new front-end architecture. We're sharing the methods we've used and how it's helped us to work more efficiently on the AppCloud UI.
Modular CSS
Haml and Sass are two gems that are easy to include into your Ruby on Rails application. At Engine Yard, we use both of these to maintain our front-end code. Sass variables and mix-ins are amazing resources that make managing styles much easier. This is fantastic for maintaining UI elements and adhering to brand guidelines. Within our AppCloud front-end framework we have variables we've set up for our colors based on our branding color palette. That can look something like this:// --------------------------------------------------
// COLOR
// --------------------------------------------------
$color_border = #ccc // light grey
$color_background = #f8f8f8 // lightest grey
$color_background_alt = #cfdbe8 // light blue
$color_background_alt2 = #e3e5cf // light beige
$color_text = #555 // dark grey
$color_text_alt = #999 // medium grey
$color_text_alert = #910f0f // bold red
$color_text_callout = #236DA6 // bold blue
This way, when we need to use the color for our borders, we can just call on the color variable, $color_border. If we decide to change this color, we only need to change it in one place. If we need variations on this color (like for shadows and highlights), we can use that variable combined with Sass's built-in functions:
h1 {
border-bottom-color: darken($color_border, 10%);
}
We've used the "color_" prefix in these variable names to help avoid any clashes we might run into. It also helps provide some inline context (documentation is always a good thing). The important thing here is we keep our variable and mix-in names descriptive, but we avoid using presentational names that could change one day. By using $color_text_callout instead of $color_text_blue we don't have to change all of our variable names if we change the text from blue to red. We can use comments to help remind us of hex value colors which are located in the one place we'd make changes, if need be.
Variables and mix-ins are a great way to help improve and clean up semantic HTML (if it's done right). In our last related blog post, we mentioned that we're using the 960 Grid System which uses CSS classes like “grid_1”, “prefix_9”, and “alpha”. For the semantic front-end neat-freaks out there, this can be cringe-worthy. However, if you're not already using a framework like Compass, you can simply modify the 960 Grid System, allowing you to have the best of both worlds (modular efficiency and clean, semantic HTML). You can turn all the class names within the framework into mix-ins, which will make HTML go from this:
<div id="sidebar" class="grid_1 prefix alpha">
(content goes here)
</div>
to this:
<div id="sidebar">
(content goes here)
</div>
That's so much better, isn't it? We can do this for other common styles like clear fixes, rounded corners, visibly hiding elements, etc. If you define your UI elements' visual design styles as variables or mix-ins, you can have a much easier time updating these styles in a consistent way.
Maintaining an Interface Style Guide
Interface Style Guides are an essential way to keep track of branding and visual design guidelines and front end architecture requirements. The key to keeping a style guide useful is that it should stay relevant and informative. However, this can be a tedious task that often gets forgotten or avoided. Online style guides are easier to maintain and distribute as opposed to printed documents. To keep our style guide relevant, it lives in our internal-only admin section on the very same application it describes. We display our color palette alongside the relevant Sass variables and since we've built the style guide into the application using the same front-end, we can use the same variables we're referencing to render this palette. When we change values to these variables, the palette updates automatically.more »
Rails and Merb Merge: ORM Agnosticism (Part 5 of 6) »
Created at: 23.02.2010 20:15, source: Engine Yard Blog, tagged: Technology ActionPack ActiveModel activerecord api datamapper haml Rails 3 Railties
It’s been a little while since I’ve last posted in this series. During that time, we released Rails 3.0 beta, and announced the launch of RailsPlugins.org. Plugin authors have registered almost 150 plugins, with 40 already boasting compatibility with Rails 3. Over the next few weeks, we’re going to roll out some more features to help users find projects to help get updated, so keep an eye out.
Today I’m going to talk about the features we added to Rails 3 to provide ORM agnosticism. When we first started, the idea of such agnosticism was pretty fuzzy. As we approached the beta, we became convinced that we would shoot for the moon and give DataMapper, Sequel and other ORMs first-class access to all of the same parts of the framework that ActiveRecord had. Again, this sounds pretty fuzzy, so let me lay it out for you.
ActiveRecord is a Framework Extension
You read that right. While Rails itself ships with ActiveRecord as a default, the Railties gem, responsible for bootstrapping Rails, knows nothing about ActiveRecord. In order to achieve this, we had to make that bootstrapping process much more pluggable. While this is amazing for extensions, like DataMapper, that want to replace a built-in framework, it also exposes more functionality to any Rails extension distributed as a gem.
Rails::Railtie
In short, Railties now coordinates the initialization process, which involves the activation of a number of individual Railtie subclasses. Cute, no? Every Rails framework has its own Railtie subclass, which provides a number of useful pieces of functionality:
- The ability to add a key (like
config.active_record) to an Application’s configuration, and assign it defaults that will exist before Application configuration. For instance, a plugin could use this functionality to set a configuration key as an Array, so the Application could simply doconfig.action_view.view_paths << "my_path". While this isn’t exactly earth-shattering, it levels the playing field between Rails components, like ActiveRecord, and third-party extensions, like DataMapper or Haml - The ability to create additional generators that hook into Rails’ default generators. For instance, Rails’ scaffold generator invokes sub-generators for stylesheets, template engine, test framework, helpers, and ORM. For instance, when a user installs Haml as a gem, it can register itself as the handler for template engine generators, and provide replacements for each case where Rails provides a default implementation. In this case, Haml would replace the template engine generators provide by ActionController’s Railtie
- The ability to supply Rake tasks to load when the user invokes the Rake command. If DataMapper supplies the same named Rake tasks as those supplied by the ActiveRecord Railtie, the user can completely remove ActiveRecord and replace it with DataMapper, retaining all of the named Rake tasks. This would allow other tasks, such as those used in testing, to automatically prepare the database and other tasks it performs by invoking tasks with certain names (like
db:create) - Supply a log subscriber to integrate seamlessly with the uniform request logging. This allows extensions like DataMapper to add their timings into the log output. In this case, DataMapper simply replaces the “Model” timing that ActiveRecord provides, allowing a level of very tight integration with the rest of the framework
- Specify initializers that should run at specific points in the initialization process. This allows extensions to set things up very early in the boot process, but then defer some setup until after the user has configured their application, or after specific parts of the initialization process have occurred. Each initializer also receives an instance of the Application object, giving it full access to the user’s configuration
In fact, if you take a look at ActiveRecord’s deep integration with the rest of the framework (which is roughly equivalent to its highly coupled implementation in Rails 2.3), you’ll find that it looks extremely similar to DataMapper’s equally deep integration. In fact, a major goal of the work we put into improving modularity in Rails 3 was to maintain the same level of stack integration we’ve historically had, while exposing the same toolchain for those who wanted to replace only certain elements of the stack.
The ActiveModel API
Giving DataMapper access to the same level of integration with Railties as ActiveRecord is one of two major pillars in making Rails truly ORM agnostic. The second part is decoupling Rails’ historic connection between ActiveRecord, its ORM, and ActionPack, its controller and view layer. In this area, Rails takes a holistic, very conventional approach to linking the model and the view using REST principles.
In particular, domain objects, persisted via the ORM, can have canonical URLs that are used pervasively throughout the controller and view layer. The specific URLs can be configured via the router, and Rails 3’s router is particularly powerful, but once configured, objects do have canonical URLs.
@post = Post.first redirect_to @post #=> Location: /posts/orm-agnositicism redirect_to Post #=> Location: /posts form_for @post #=> <form action="/posts/orm-agnosticism" method="PUT"> form_for Post.new #=> error_messages_for @post #=> a representation of the validation errors that exist on the object link_to @post.title, @post #=> <a href="/posts/orm-agnosticism"> # Rails and Merb Merge: ORM Agnosticism (Part 5 of 6) # </a> posts_path #=> "/posts" post_path(@post) #=> "/posts/orm-agnosticism" @posts = Post.where(:author => "wycats") render @post #=> renders "_post.html.erb", passing in @post as a local render @posts #=> renders a collection of "_post.html.erb", passing in each # Post instance as a local in turn respond_with @post #=> performs content negotiation between the formats # the client is willing to Accept (xml, json, html), # and the formats the @post object is willing to # provide. The available providable formats are # transparently determined by introspecting the @post # object. Additionally, if the object has not been persisted, # redirect it back to the editing page for further modification. # If it has been persisted, redirect it back to the index (or # some other appropriate path).</form>
In short, Rails 2.3 provided a fair bit of integrated functionality between ActiveRecord and ActionPack. For instance, to determine what an object’s canonical URL was, Rails called an internal .class.naming method on it, which provided the information needed to form the canonical URLs. And while other ORMs could attempt to emulate these internals, there was no guarantee that they’d be used in the same way from release to release (and, in fact, they evolved quite a bit, making them a moving target at best).
In Rails 3, we opened them up, exposing an explicit public API via ActiveModel. The ActiveModel API requires that objects respond to to_model, returning an Object that complies with the larger ActiveModel API. This allows objects that already implement methods with the same names as those required by the API to create a facade that presents itself to ActionPack as a fully compliant model.
The API itself is fairly small, with a few methods around validation, the ability to determine whether an object has persisted or not (which can be safely stubbed by objects without persistence), and a number of methods that tell ActionPack how to convert the object into a canonical URL or template name. By doing this, Rails has completely decoupled ActionPack from ActiveRecord directly, and ActiveRecord becomes just one of many ORMs to implement the ActiveModel API.
The DataMapper ORM has already released a Rails extension (called dm-rails) that implements both the Railtie functionality and ActiveModel, making it a full drop-in replacement for ActiveRecord. The Sequel ORM is also hard at work on their Railtie and ActiveModel adapter.
The really great thing about all of this is that we didn’t need to sacrifice one bit of the (some have said overly) tight integration between various parts of Rails, to provide the ability to swap in entirely different components with the same apparent “coupling” that the Rails frameworks have with each other.
As always, questions and comments are welcome!
more »
Double Shot #644 »
Created at: 09.02.2010 13:10, source: A Fresh Cup, tagged: auto_timeout aws css devise haml mapreduce rails riak ruby savon sinatra textmate
There's certainly no shortage of goings-on to link to lately.
- Devise 1.0.0 - Major milestone for this Rack-based authentication solution for Rails.
- Cloudfront: no-brainer CDN Support for S3 - I've got a couple of apps out there where I really should implement this.
- Save file and reload Safari from TextMate - Passed on by Alex Heaton.
- Bye Bye Github and GitHub post - Afterthoughts - Elad Meidar discusses expectations and git hosting.
- SendEmail 1.56 - Command line email sending that can handle TLS (and thus Google Mail servers). Requires some perl modules.
- sinatra_more - Gem to boost Sinatra to handling more complex applications.
- Auto timeout sessions in Rails - Useful plugin from Matthew Bass, for the times when you need to keep people from just idling. I ended up forking it to make it use jQuery instead of Prototype.
- MR.Flow - Web-based designer for MapReduce operations.
- EdgeRails.info - Ryan Daigle is moving all his edge content to a fresh domain.
- RubyInstaller Release Candidate 2 - 1.8.6, 1.8.7 and 1.9.1 - Useful tool for people who want to run Ruby on Windows without resorting to a virtual machine.
- Savon - Ruby SOAP client that includes WSSE authentication.
- Wrap your SQL head around Riak's Map-Reduce - Personally my SQL head says "no! enough already!" but I expect I'll have to learn this stuff sooner or later.
- Haml Sucks for Content - Actually a good post on some advanced HAML techniques rather than another entry in the holy war.
- Less.app - Autocompiler for your LESS CSS files. Well, if you have any.
more »
Double Shot #641 »
Created at: 04.02.2010 14:17, source: A Fresh Cup, tagged: Double Shot dterm haml localization maps os x tableau toto
Sleep seems overrated until you have to skip it for a while.
- gMap - jQuery plugin for Google Maps. Looks way easier than the last way I've done it.
- webtranslateit - Gem to integrate a Rails app with Web Translate It, a web service to help provide localization.
- Why use HAML (and SASS)? I already know HTML. - Another argument in favor of switching to HAML/SASS. This is rapidly becoming the vi vs. emacs of templating languages.
- toto - Blog engine built atop rack and aimed at heroku deployment.
- Ubiquitous Analytics and Tableau Public - This looks nice; the Tableau data visualization app is one of the things I remember from Windows days, and now they're bringing it to the web.
- DTerm - Popup command line for OS X.
more »
