Code and Ruby on Rails06 Jan 2006 06:46 pm

Hot on the heels of my previous announcement, there is now a bundled_resource plugin that takes advantage of all of my previous work in this area at syncPEOPLE, plus some (download).

What’s it for?

If your development is in any way similar to mine, there are a number of useful resources out there that make web applications shine beautifully. For example, there’s the Dynarch calendar and the textarea tools. There are a number of others—too many, in fact. The problem is that as a web developer, it sometimes takes some real surgery to put each one of these in to an application. And then when you create a new page that uses these resources (even within the same app), you have to figure out which pieces to cut and paste to get it functional.

Take the Dynarch calendar, for instance. There are 4 javascript files, 1 CSS file (among several to choose from), 2 images, several helper methods, and a controller method that you’ll need in order to get it to work with Rails. Sometimes it’s easier just to ignore the calendar bit because it’s such a pain to set up.

How does BundledResource help?

But what if it weren’t a pain? What if you could write this at the top of your page:

  <% require_bundle :dynarch_calendar %>

And your dynarch calendar would just work? That’s what bundled_resource does.

Now you can use this method:

  dynarch_date_select 'post', 'publish_date'

anywhere on the page, and it’ll work. Easy :)

So it looks easy… what’s going on?

What the bundled_resource plugin does is it keeps all of your resources (javascripts, stylesheets, images) within the plugin’s directory structure and copies them in to the public folder whenever your app starts. This is very similar to James Adam’s technique that he uses with Rails Engines.

The advantage, of course, is that you don’t have to worry about copying and pasting files all over the place whenever you want a new bundled_resource. They all belong together in one little folder inside the plugin.

Pre-packaged Bundles

Included with this release (0.7) are three bundles: the Dynarch Calendar, Textarea Tools and qForms. Setting up an app to use them is simple:

  1. Install bundled_resource
  2. Add the following two lines to your layout (just like the RequireResourceHelper):
      <%= stylesheet_auto_link_tags %>
      <%= javascript_auto_include_tags %>
    
  3. Add a require_bundle :[bundle name] at the top of your view file.
  4. For example:

    require_bundle :qforms
    

    And that’s it! Welcome to Easier Resource Management for Rails.

Ruby on Rails05 Jan 2006 11:05 pm

One of the design goals of Family Connection is to make it very easy to install as a Rails application. That includes showing the user what errors are happening even during the installation.

The Problem

So what do I mean by that? Well, currently, whenever Rails encounters a database error (for example, if your username or password is incorrectly set in the database.yml file, or if the database doesn’t yet exist) then Rails throws a fit. In some cases, it doesn’t even register that an error occurred. Because the database is loaded dynamically (as a consequence of automatically requiring the models), there’s no way for a controller to catch the error and display a user-friendly error page.

The Solution

So here’s what you do: create a “Pre-Dispatcher” that intercepts the CGI requests before the Rails dispatcher gets to do its job. If everything’s OK, pass the request on and all is well. But if there’s a problem, then render a pre-defined controller and view.

Tricky, Tricky

How do we do this without actually modifying with the Rails internals? Can we use a plugin? Yes and no. The dispatcher code is actually loaded after the plugins. This means we can’t re-open the class and modify as needed. Instead, we put a file called “dispatcher.rb” in the lib/ folder (or, if we wanted, in a plugin’s lib/ folder since they are all added to the $LOAD_PATH as well). It just so happens that this name conflicts with the “dispatcher.rb” file that Rails normally loads—exactly as we want. Once we’ve gotten Rails to load our dispatcher file instead, we load the real thing, and then patch it by re-opening the class (yay ruby!) and adding our code.

Download

You can download the source code to the pre_dispatcher plugin here. Just drop it in to your application’s lib/ folder and it’ll automatically be loaded by Rails.

Caveats

First, when a database exception occurs, the controller name that we’ll use is hard-coded inside that dispatcher file. I called mine “DatabaseExceptionController”. You can name yours however you like.

Second, I couldn’t seem to get plugins to work within my DatabaseExceptionController. While not strictly necessary in my case, it was kind of troubling that they wouldn’t load. I’m not sure what the difference is between my dispatcher’s call to the controller and the regular dispatcher’s call to other controllers. If you figure it out, please tell me.

Life04 Jan 2006 06:17 pm

I’ve read two of C. Terry Warner’s books before and met him in person once. I can honestly recommend him as one of the most spiritually insightful people I know.

With that said, I must also confess that I haven’t yet read the article I’m about to post: my mom sent me the link and spoke very highly of it. I’d like to share it here and then get back to it in a peaceful and reflective moment.

C. Terry Warner’s “Honest, Simple, Solid, True”

Code and Ruby on Rails04 Jan 2006 12:29 pm

Whenever a Rails exception occurs, it spits out a backtrace full of filenames and line numbers. I’ve often thought, “Wouldn’t it be nice if I could just click on one of those and it would take me to the problem?” Well, it is nice—and you can use this new plugin with TextMate too, if you’d like.

The textmate_backtracer plugin (download) will make each of the backtrace lines clickable in your browser. I’ve tested this with FireFox and Safari. It’s not a debugger, but it makes life easier :)

To install, just download to your rails app’s ‘plugins’ folder and untar/unzip it. Then restart your server (webrick or Lighty). Enjoy!

Update: I’ve fixed a couple of things in the latest download—there was some debug info being written to STDERR (now removed), and backtrace lines without a method were not clickable (now clickable).

Ruby on Rails03 Jan 2006 03:01 pm

A friend of mine recently expressed interest in this code snippet, so I thought I’d send it out to anyone else who’s interested. This module makes it a lot easier to ‘require’ javascript and cascading stylesheet dependencies inside your views or controllers. By ‘convention’, the code will automatically include any javascript or CSS files whose name matches the current controller’s name. In addition, any file named like ‘controller_name_action_name.css’ will also be included for specific actions (likewise for JS). It was inspired by a portion of code I saw from Demetrius Nunes.

Usage

To use it, put the following in your application.rb:

	class ApplicationController < ActionController::Base
	  helper 'require_resource'
	end

Then in your layout’s HTML “head” section:

	< %= stylesheet_auto_link_tags %>
	< %= javascript_auto_include_tags %>

Example

Supposing I am writing an action for WelcomeController called ‘index.rhtml’, (and that each of the files actually exists), I can now assume that this HTML will be present in the layout:

	<script src=\"/javascripts/welcome.js\" type=\"text/javascript\"></script>
	<script src=\"/javascripts/welcome_index.js\" type=\"text/javascript\"></script>
	<link href=\"/stylesheets/welcome.css\" media=\"screen\" rel=\"Stylesheet\" type=\"text/css\" />
	<link href=\"/stylesheets/welcome_index.css\" media=\"screen\" rel=\"Stylesheet\" type=\"text/css\" />

Note: Once again, WordPress is adding extra backslashes to the quotes—they are not in the code itself. If the files don’t exist, the above HTML won’t be included.

In the case that the CSS or JS is not named ‘by convention’ as a file that corresponds with the controller’s name, I use the “require_javascript” code. In one of my views (index.rhtml, for example):

	< % require_javascript 'popitup' %>

Then, I can call the js function popitup later:

< %= link_to_function \"click me\", \"popitup('#{url_for :action => ‘click’}')” %>

The Module

Update: Since the quotes are getting munged by WP, I’ve uploaded the source file so you can download it directly.

Code30 Dec 2005 02:02 pm

So I did some searching around the net and found this step-by-step guide to installing rmagick on OS X on the RubyForge site. It fails to mention, however, that there’s a much simpler way of doing things now through the ports system:

$ sudo port install rb-rmagick

Special thanks to whoever put together the official rb-rmagick darwinports page. Life is so much easier on Mac OS because of people like you! :)

Code25 Dec 2005 09:45 pm

Just thought I’d post this up for anyone looking to move to Ruby from a Java programming background:

Andrew Glover has written an excellent article at IBM developerWorks on Ruby’s terse syntax and intelligent design decisions. He points out that his article is not a “Ruby on Rails” info packet—to the contrary, it’s just pure Ruby doing what it does best.

Life21 Dec 2005 10:34 am

Just found out about this fantastic Firefox plugin that lets you blog about a web page while you’re visiting the page.  Cool!

Performancing Firefox: Tabs, Windows and Browsers | Performancing.com

Ruby on Rails20 Dec 2005 11:54 pm

Let’s say we have the following has_and_belongs_to_many relationship:

class Contacts < ActiveRecord::Base
  has_and_belongs_to_many :companies
end
	
class Company < ActiveRecord::Base
  has_and_belongs_to_many :contacts
end

Now, if you create a new contact:

friend = Contact.new

and then add some companies:

friend.companies = [Company.new, Company.new]

you will find that nothing was stored in the database. On the other hand, if friend is an already-existing object, as in the following example, then the same assignment to companies will result in a save to the database:

friend = Contact.find :first
friend.companies = [Company.new, Company.new]

In fact, both of those new (and as yet unsaved) company objects are first stored in the database, and then the join table gets two new rows to associate friend with the Company objects.

Hmph

That’s not very good if you want to construct associated objects in memory, validate, and then save them. After several hours of, well, you can imagine how one feels after several hours of any sort of problem, here’s a workaround I found:

friend = Contact.find :first
new_record_state = friend.instance_variable_get \"@new_record\"
friend.instance_variable_set \"@new_record\", true
friend.companies = [Company.new, Company.new]
friend.instance_variable_set \"@new_record\", new_record_state

This will trick the automated :after_add hook in to thinking that friend is a new object (and thus, has no id). As a result, the companies will not be saved in the database, even though the association will exist in memory.

Whew.

Scripture18 Dec 2005 02:43 pm

Going to church is one of the “sharpening the saw” activities in my life that inspire me to be a better person. Today, I was enlightened by our discussion in Sunday School (specifically, the Priesthood lesson) on the subject of Light, and I’d like to share a few principles that I learned.

Adam Was Given the Breath of Life, not the Light of Life

Some of you may have read the story of the Brother of Jared in the Book of Mormon. In that story, the Brother of Jared seeks to build several primitive “submarines” in which he and his people can cross the great deep (probably the Pacific Ocean). In order to use these underwater vessels, however, he realizes that two things are necessary: air and light. He prays to the Lord and asks for these things, and the Lord shows him how he will be able to have air throughout the journey. With regard to the request for light, however, the Lord turns the question back on the Brother of Jared and asks, “What do you want me to do so that you can have light?” In this story is a profound truth: that while we are given breath and physical life freely, it is up to us to seek light—to ask questions, find truth, and live the best we know how—to work for it and find it on our own. God will not grant that to us without a price.

Truth Can Be Taught Without the Spirit of Truth

In the Doctrine and Covenants (a book of revelations to Joseph Smith) there is an interesting section (#50) in which God tells certain missionaries that they are not to teach truth except by “the Spirit of Truth.” In our Sunday School lesson today, I finally began to understand the significance of this. Have you ever had the experience of talking with missionaries who are trying to “convince you” of the truth? Or have you been a part of a debate team when you feel so frustrated that the other side doesn’t “get it”? These situations are examples of truth without the Spirit of Truth. There may be some good thing that is being shared, but the manner of its communication—something outside the content of the message itself—is amiss. On the other hand, when the Spirit of Truth is present, both the giver and the receiver are “edified, and rejoice together.”

Truth is Quantum

A graduate student in chemistry spoke up during our discussion on Light and drew another interesting analogy between physical light and spirtual light: spiritual light, or “truth” is quantum. Just like modern physics has revealed that physical light comes in packets (light is not a continuous stream), truth comes in packets to our minds. We have “revelations” that suddenly enlighten us and inspire new thoughts. We learn “line upon line, precept upon precept.”

Spiritual Growth is Discovering the Source of Indirect Lighting

Another member of our class pointed out that we all have spiritual experiences—it’s just that some of us, during those moments of revelation, search for the source and become more acquainted with truth. I thought that was an interesting take on spiritual growth—rather than paying attention only to the thing that is being lit up, we need to also pay attention to the thing that is doing the lighting. In this way, our lives will grow brighter and brighter because we can draw nearer to the source of light.

Next Page »