Friday, June 27, 2008
Broken 'pre' tags with Blogger
Sometime in the last week, a significant change was introduced into Blogger. Previously, any content inside of a <pre> section was left alone. Now, a <br/> tag is insterted for every line break within a <pre> tag, which results in a double line break. As a result, all of my code snippets have an extra line break.
I will write a more relevant post tomorrow. I just wanted to explain why my existing snippets look wrong.
Tuesday, June 24, 2008
Googtaculous
To follow up on my post about Google's Ajax library API, I made a plugin that you can install to make your life easier.
script/plugin install git://github.com/matthuhiggins/googtaculous.git
The name is pretty clever, eh?
Friday, June 20, 2008
Clearing memcache without restart
Up until now, I always restarted memcache to clear it. However, you can make a rake task to do so:
Drop this into /lib/tasks/cache.rake. Now just run the task:
rake cache:clear
This only works if you have configured action_controller.cache_store to be memcache.
Have a good weekend!
Saturday, June 14, 2008
Rails: Where to put the 'other' files
Introduction
When starting a Rails project, four golden folders are predefined: Models, Views, Controllers, Helpers. Could we possibly need anything more? In my experience, the answer is yes. This leads to the question of, where do these extra files go? Compared to models, views, controllers and helpers, Rails provides little guidance about where to put this other stuff. Fortunately, Rails comes packaged with two folders to put additional Ruby code: lib and config/initializers. Each have their unique properties, and they can be used together to neatly package your Ruby code.
The weakling lib folder
In Agile Web Development on Rails, the authors describe how to use a naming convention, such that your lib file names match the classes they contain. For example, a class of FooBar must be in the file foo_bar.rb. Classes can even be namespaced. For example, Foo::Bar will be loaded if placed inside of foo/bar.rb.
Files in lib are not loaded when Rails starts. Rails has overridden both Class.const_missing and Module.const_missing to dynamically load the file based on the class name. In fact, this is exactly how Rails loads your models and controllers.
While the functionality of the lib folder is nice, it is extremely limited. It prevents writing modules to extend or override the functionality of another class, because they will never get loaded.
The bloated initializers folder
Rails first loads the framework, then plugins, and finally, it loads the files inside of config/initializers (in alphabetic order, no less). Previous to 2.0, naughty developers pasted code at the bottom of environment.rb, and the initializer folder was a welcome convention to help organize this madness.
I find myself using the initializer folder to configure plugins such as HAML, or loading the action_mailer configuration out of a YML file.
Unfortunately, I see many code snippets showing how to extend the functionality of Rails simply by creating a new file in initializers, and pasting in the code. In a matter of fact, my last post suggested doing this. This is OK in light doses, but after a few months of this practice, you will find yourself with an initializers folder with many files and little structure, not to mention that they get loaded in alphabetic order.
Lib folder, meet initializers
I think I hurt lib and initializer's feelings. I feel bad about this, so maybe it is time to introduce them to each other. A simple example is in order:
We want to add a new 'user_logger' mixin to ActionController::Base. Any controller can choose to enable 'user_logger', and it will put the current user's name in the log file for each request they make. This won't be the last time we extend ActionController's functionality in this project, so let's do it the Right Way.
We first write the module. Start by creating a new folder inside of /lib called rails_extensions. Now paste this code inside the file user_logger.rb:
Next, create the file rails_extensions.rb in /config/initializers. Paste this code inside:
You may want to create an even deeper directory structure inside of rails_extensions. In my larger projects, I keep a folder for action_controller, active_record, etc. Nonetheless, using initializers and lib together can help you avoid a bloated initializer folder and weak set of functionality in the lib folder.
Tuesday, June 10, 2008
Using Google Ajax Libraries API with Ruby on Rails
Intro
The new Google Ajax Libraries API can help you offload bandwidth from your site. Their servers are configured with gzip, expires headers and e-tags, which leads to good scores from YSlow. I will show two ways to use Google's new API to offload Ruby on Rails javascript (prototype and scriptaculous). In both solutions, your existing calls to javascript_include_tag can be left the same, because all of the magic is handled beneath the covers.
Implementation #1: Create a module
This first example is a module that chains the expand_javascript_sources method found in ActionView::Helpers::AssetTagHelper. If prototype or a scriptaculous file is loaded via javascript_include_tag, we will replace the normal functionality with a path to the file on Google's servers. Start by creating the file /config/initializers/google_asset_tag_helper.rb. Paste in the following:
This defines GoogleAssetTagHelper, which chains expand_javascript_sources. The module is included into ActionView::Base. Notice that on line 12, the original method is only aliased if ActionController::Base.consider_all_requests_local is false. Since this is set to true in development mode, it is a sufficient way to determine whether or not Google AJAX Library should be used. If using the remote libraries in development is desirable, the condition can be safely removed.
Implementation #2: Assign lambda to ActionController::Base.asset_host
An alternative solution uses ActionController::Base.asset_host to determine the root path to the javascript files. In /config/environments/production.rb, you find:
config.action_controller.asset_host = "http://some.asset.host/"
As of Rails 2.0.2, asset_host can a string or Proc. Since we want to conditionally change the asset_host based on what file is being include, a Proc is needed:
In this example, the code assumes that you do not already have an asset_host defined. If you do, simply replace the false expression on line 10 with your original asset_host string.
(The variable google_paths is defined inside of production.rb for brevity. However, I recommend defining it as a constant elsewhere in your own project.)
Using the javascript_include_tag
As mentioned in the introduction, your existing javascript_include_tag calls remain the same:
javascript_include_tag 'prototype', 'effects', 'controls', 'application'
Subscribe to:
Posts (Atom)