Simplest static site on Heroku (plain Rack)?

gem 'rack-rewrite', '~> 1.0.0'
require 'rack/rewrite'

use Rack::Rewrite do
  rewrite '/favicon.ico', '/images/favicon.ico'
  rewrite '/', '/index.html'
end
run Rack::File.new('public')

Filed under  //   hosting   ruby   tech  

Comments [0]

Filed under  //   rack   ruby   tech   testing  

Comments [0]

Testing a rackup (config.ru) file with Rack::Test

The ever useful rack-test gem let's you easily integration test any rack project.  All you have to do is include the Rack::Test::Methods and define an app method that returns your rack app.  So people usually have a config.ru that just references their my_application.rb that they reference in their config.ru and then in their test file they can also reference that app and return it.  Something to to this effect:

I had a project where I was actually trying to better breakdown a more complex app, and I wanted to just be able to use Rack's built-in map method at the top level of my config.ru to route to different apps.  And in at least some of the cases I wanted to be able to test the whole thing.  Also, I figured sometimes it's useful to actually be able to test your rackup file itself, all routing/mapping included.  So I dug around in the rack code and found how the rackup command handles the .ru file, and came up with this:

Update

If you are running off of a new enough version of rack, you could also just use Rack::Builder.parse_file

Filed under  //   rack   ruby   tech   testing  

Comments [0]

Beware respond_to format with redirects in shared systems before_filter - DoubleRenderError

If you have global before_filters for things like requiring login to access pages (such as in authenticated_system.rb), be careful of missing formats in the respond_to.  I just tracked down a bug on an app where we were getting DoubleRenderErrors because of unauthenticated requests directly against a dynamic csv file.  

We had a before_filter that was denying request and redirecting them to login, in different ways, depending on the format, but hadn't thought to include csv.  In this case, it is wise to include a catch-all at the end using .any

Filed under  //   ruby   rubyonrails   tech  

Comments [0]

Simplicity *does* mean simple, readable methods

Following a link from @raganwald I came across an article where Mike Taylor was debating wether the concept of simplicity, as it pertains to the length and complexity of methods isn't subjective.  He read a decent chunk of Fowler's Refactoring, found himself disagreeing with the tendency to composable, well named methods, in favor larger methods with the low-level implementation in the method itself, and hoped maybe he was wrong, because the lure of The One True Way is strong.  While I am often a subjectivist, as I told my fiance, "Honey, somebody on the internet is wrong - I must inform them immediately."

Basically Mike breaks it down into two approaches: top-down, where the methods are named what they do and abstracted away so you don't see each step of implementation at the top, and bottom-up, where the main method is a little larger and is built up of the implementation itself.  He favors bottom-up, and I am a partisan of the other camp, as rubyists often seem to be.

I think there is one most important reason to favor the big-picture top-down in this dichotomy.  From top-down you can dive down into the implementation and see the details if you chose, but in bottom-up there is no way to get the equivalent top-down view without just reading and understanding the whole program.  Basically, advocating the bottom up approach is like making world-maps illegal, because you can get a better feel for navigating your hometown with a city-map.

From this flows the second most important reason, the inability to mentally page out to disk, so to speak, means you have to hold more of the program in your head to understand what is going on.  That means as the program grows in size, it gets harder and harder to keep track of it all.  And the reason this is really a problem, is when it comes time to introduce new people to the code.  By not abstracting things away into bite-sized chunks you've just forced them to learn every piece of everything involved to have a hope of understand things enough to actually get any work done.

A third point: various software engineering theories like: cyclomatic complexity and single-responsibility principle.

I will admit that getting carried away with classitis and class hierarchies, Java style, has some cost, when it comes to following what a program does.  There is a little balancing act required there.  But, I do think, that decomposing methods is an unequivocal win.  I think Rein's tongue-in-cheek talk on Unfactoring is a better visual, code-based proof of the importance of this for maintainability than anything I could whip up here (about 5 minutes in he gets into the examples).

Lastly, who hasn't gone back and looked at their old code and wondered what they were doing?  If you want to go back and tweak something, it's painful if you have to refigure out every piece of implementation.  This is a case where scanability and readability is a huge win.
Filed under  //   internetdebates   ruby   tech  

Comments [10]

Using open3 in ruby to call an interactive shell command with all three pipes while avoiding block

Apparently when using the three standard pipes (stdin, stdout, stderr)
in your own programming, it is REALLY easy to block or deadlock on
them. At first I figured there were problems in the ruby *open3
library, but this is not ruby specific, I found message board
discussions about similar problems using perl open3 libraries.

Trying to figure out these quirks is made harder by the fact that all
of the common ruby examples are non-interactive, and just close the
stdin before trying to read any output. Even worse, many, many shell
programs don't use stderr and stdout in what I understood as the
proper way. For instance I first as trying to use ftp as the command,
but this proved beyond my abilities. I then came up with a simple
working example that calls dc (the simple reverse polish calculator
available on most unixes), and discovered that on errors it outputs to
both stderr and stdout (different text). I was not able to in any way
to get the output from stderr until I closed stdin (short of
redirecting stderr to a temp file).

This drives home the point that you shouldn't be doing this too much,
in ruby. Generally, use a better, task-specific ruby library, for
these sort of tasks. If you want to use ftp, use net-ftp, for
instance. If you want to use more extensive interactive shell
sessions, check out Ara Howard's session
gem

*Open3 as a naming convention tends to be a library to call shell
commands with the three aforementioned pipes.

Filed under  //   jruby   ruby  

Comments [3]

Filed under  //   jruby   ruby   tech  

Comments [0]

Making config.gem in Rails 2.3.x allow you to install from a direct url or the local filesystem

If you are on Rails 2.3.x (pre-Bundler) and want to organize some of your shared functionality into gems, but they are for internal use only, you could set-up a private gem server and point the :source at this server.  And then you could deal with authentication, and then...

Or as a quick hack you could just allow for config.gem to reference the gemfile directly, which would then mean 'rake gems:install' would work, even if the gem were stored locally, or on a file-server, etc.  Also useful as you could then just point at a .gem file on github.

Filed under  //   ruby   rubyonrails  

Comments [0]

"Object is not missing constant XXX" and "A copy of YYY has been removed from the module tree but is still active" when using Rails metal

If you have a Rails metals that has enough code to have its own subdirectories that live in your Rails load_paths you can get stuck in dependency hell. The combinations of autoloading, rails reloading on development, and running through the metal can intersect in nasty ways: on the first request you get "Object is not missing constant XXX" and subsequent requests kick off "A copy of YYY has been removed from the module tree but is still active."

The easiest solution is to kill magic reloading for this metal's code by adding the metal's directories of code to the Rails load_once_paths and then using explicit require_dependency calls for any files that give you trouble. For example, I have a MadMetal that referenced a Mad which has a whole sub-directory structure of code that, for now, lives under lib/mad:

#config/environment.rb
config.load_once_paths += Dir["#{RAILS_ROOT}/lib/mad/**/"]

#app/metal/mad_metal.rb
require_dependency 'mad'
class MadMetal
  def self.call(env)
    if (env["PATH_INFO"] == '/the_path_to_my_metal')
      Mad.call(env)
    else
      [404, {"Content-Type" => "text/html"}, ["Not Found"]]
    end
  end
end

And wallah, no more conflicts between development auto-reloading and metal.

Of course, now you need to restart the server if you change code in lib/mad. In this case it's not a problem for me because the app is also a stand-alone rack app that I run with shotgun when I want development environment reloading.

Filed under  //   metal   ruby   rubyonrails  

Comments [0]

Avoiding some of the negative trade-offs in the template pattern with ruby's dynamicism?

So my buddy Tammer's recent post about the Gang of Four's Template Pattern reminded me of some code I saw recently. A start-up's greenfield project had it's authorization done in a pretty clean way using the template pattern. Basically every object determined what could be done to it, something like this:

After continuing this approach to fully cover CRUD you make a straight-forward set of accessors that can be used to easily enforce permissions in the controller in a programmatic way (this project was using on of the inherited resourceful-controller plugins, so that was a big plus). The developer who implemented this commented that the trade-off for this simplicity was having to look in each individual model file to figure out what a user can do overall.

I figured I liked everything about this scheme except that trade-off, and since ruby is so dynamic, why settle for almost. Why not just reopen each class in the authorization file and add the methods. You still get the simplicity and encapsulation of having the model able to determine it's own permissions, based on it's state and methods, and there is still one place to look to review/change the permissions for the whole project:

Thoughts?

Filed under  //   ruby   rubyonrails   tech  

Comments [2]