h1

Rails: Render in a model

June 19, 2008

OK, this is really out there. Yes, the real answer is, “Don’t do it.”

Are you sure you aren’t going to be sad when the content of your database doesn’t change to keep up with your refactoring? Have you sufficiently explored other options and questioned the wisdom of what you are trying to do? Are you being asked to just to it anyway?

I found two approaches at http://davetroy.blogspot.com/2008/02/actsasrenderer-brings-output-to-models.html and http://blog.choonkeat.com/weblog/2006/08/rails-calling-r.html. I only tried the second of these, which didn’t like my use of polymorphic URLs and named routes in the template. I didn’t find the first approach before I had an interesting realization: if functional tests can do it then why can’t models?

def render_as_test(render_options, vars = {})
  controller = ApplicationController.new
  class << controller
    def set_instance_variables_and_render(render_options, vars)
      vars.keys.each do |k|
        instance_variable_set "@#{k}", vars[k]
      end
      render render_options
    end
  end
  require 'action_controller/test_process'
  request = ActionController::TestRequest.new
  response = ActionController::TestResponse.new
  controller.process(request, response,
    :set_instance_variables_and_render,
    render_options, vars).body
end

Now all my URLs generate. Use it responsibly. In fact, don’t use it at all. I am definitely not interested in pluginizing.

Advertisements
h1

Speed tests in Ruby

April 11, 2008

Maybe this is already somewhere, but I did not find it in the

Test::Unit::TestCase

documentation where I expected it. I want to make sure that a certain block of code would execute within a given time period. Granted, it’s a bit obvious, but in case you searched first like I did and found this:

class Test::Unit::TestCase
def assert_faster_than(delta)
    start = Time.now.to_f
    yield
    finish = Time.now.to_f
    assert_in_delta start, finish, delta, "Expected to take less than #{delta} seconds but took #{finish-start}."
  end
end

# Then just use it like this....
assert_faster_than(3) { something_that_could_take_a_while }
h1

GM Pass Key? I’ll pass.

December 30, 2007

It worked well for me for about ten years, but I finally got fed up with not being able to start my own car with my own key. I don’t like to get screwed on car repairs, so here’s what happened. I used Google for a while and found some websites with more information than I really needed, and I read it all. If you are having the same problem, you have probably figured out what is going on. You turn the key. The car doesn’t start, but the ‘SECURITY’ indicator blinks. You give up, and it stays lit. You know that the little resistor in the key is not making good contact.

You can go Google for those other sites as well, but you really don’t need all the information they give. I had been putting off the job because I thought I was going to have to crack open my steering column. This was not the case. Here’s how it worked on my 97 Camaro:

  1. Go to the electronics store and pick up a cheap multimeter. Open the box in the store and try to read your key with it. Quickly discover that this one is a total piece and you shouldn’t have wasted your money on it. Good thing you didn’t. Close the box and spend $50 on a real nice overkill version with auto-ranging. It’s still less than the $500 model.
  2. Leave the store and measure the resistance of the key in the peace and quiet of the hurting car. In my case it’s 886 Ohms. I’m no expert, but I bet GM picked values that don’t match up with widely available resistors.
  3. Well the store has 820. Will it work? I didn’t have the table I found online with the ranges about each of the 15 possible values in pass key. That’s OK. 1/(1/8200+1/1000) = 891. This is the resistance of an 8.2 kOhm and a 1 kOhm resistor in parallel. Don’t make this as hard as I did. Bring a calculator, or at least a pen. Buy the resistors and a 40W soldering iron.
  4. Here’s the action: twist the leads on the resistors together and solder them. Get down under the steering while and take all the screws out of the trim. Pull pretty hard on the trim to get it off.
  5. Literally the first thing you see is an orange wire coming out of the bottom of the steering column, housing two white wires. It’s plugged into another pair. One is black and white, and the other is purple and white. That pair is the car side. Cut it. Strip the ends and jury-rig twist the strands around the ends of the resistor.
  6. Try to start the car. It works. Try to start it again. It works again. Sweet. If it doesn’t work for you, go back to math and maybe buy more resistors. Better to get it close the first time.
  7. Solder each end of the newly-parallel resistors to one of those wires. Let the orange wire hang. Ensure a good solder job so there won’t be problems in the future. Wrap the whole thing in electrical tape and put the trim back on.
  8. Start the car again it works. Try again. It works again.

This is much better than having to try 6 times, waiting 4 minutes between each attempt, when I’m already late for work. I am thrilled to know that when I go to start my car tomorrow morning it will not be a 50/50 chance.

h1

FAILSAFE in my Rails production log

December 15, 2007

I’ll keep this one short and sweet. I was watching my production log and saw this:

/!\ FAILSAFE /!\ Sat Dec 15 19:48:06 -0800 2007
Status: 500 Internal Server Error
connect, accepted HTTP methods are delete, head, get, post, and put

I wondered what was going on, and after a check with the Apache log and Google, I found that the weird request was a CONNECT coming from freenode to make sure I didn’t have an abusable proxy or IIS. “What,” you say, “you’re running an IRC client on a Rails production server?” To that I say, “Yes.” Anyway, I stopped those requests from going to rails like this:

# First exclude some funky freenode port sniffing.
RewriteCond %{REQUEST_METHOD} !CONNECT
RewriteCond %{SERVER_NAME} teamdawg

That needs to be put before the line that finally redirects requests to your Mongrel cluster. (Of course you need to replace “teamdawg” in the second part with something that will match your own server name, or just leave the second part out.)

It occurs to me that maybe the “standard” Apache reverse proxy / rewriting config should have one additional condition before sending the request to the balancer. Most sample configs I have seen in blogs don’t have it:

RewriteCond %{REQUEST_METHOD} (GET|POST|PUT|HEAD|DELETE)

h1

Installing Rails without root

December 9, 2007

Updated the script Jan 6, 2010 to add mkdir INSTALL_ROOT (excellent suggestion), use recent versions of ruby and rubygems (the old script was broken for me), and pull the versions into variables so it is easier to tweak this later.

It might also help to note that you will need the zlib and openssl development packages, and if you plan to use the console you almost certainly want readline as well, and all of that before you build ruby. On Debian these were libssl-dev, zlib1g-dev, and libreadline5-dev.

Some people are concerned with keeping their /usr hierarchy clean. Some people have no root access to the system that they are on. Some people don’t like using /usr/local. These people still want to install and run Ruby and Rails, but it will be best for them if it is done in a way that will keep gem working as it should.

I like to tell these people, “Oh it should be easy,” but I had to really make sure. There is one little trick, which is to make sure you really are using the right ruby when you install rubygems and then the right gem when you install Rails (and forever after).

As much for my own benefit as for anyone else’s, I put together a script so that I don’t forget. This should work on any UNIX that has the build dependencies for Ruby. That includes Linux of flavors Redhat, Ubuntu, Debian, and Slackware for all you Google fans out there. (The guy whose problems prompted me to put this together was using Ubuntu.) I like Debian but have found that Rails changes way too fast for Debian packages to be a viable way to install it. Gem is much better and standard in the Rails community, so you should do a local install of Ruby from source and then install rubygems using that version.

Without further ado, here’s the script that will save you time. You will need to edit it some unless you want /opt/rails. Personally I use /usr/local. It will also leave a build subdirectory in whatever location you use. It is your option to remove it after the fact. I would do so myself.

#!/bin/bash
INSTALL_ROOT=/home/matt/rails

RUBY_PATH=ftp://ftp.ruby-lang.org/pub/ruby/1.8/
RUBY_FILE=ruby-1.8.7-p248.tar.gz
RUBY_DIR=ruby-1.8.7-p248

RUBYGEMS_PATH=http://gemcutter-production.s3.amazonaws.com/rubygems/
RUBYGEMS_FILE=rubygems-1.3.5.tgz
RUBYGEMS_DIR=rubygems-1.3.5

mkdir $INSTALL_ROOT
cd $INSTALL_ROOT
mkdir build

cd $INSTALL_ROOT/build

wget $RUBY_PATH$RUBY_FILE
tar zxvf $RUBY_FILE
cd $RUBY_DIR
./configure --prefix=$INSTALL_ROOT
make
make install

cd $INSTALL_ROOT/build
wget $RUBYGEMS_PATH$RUBYGEMS_FILE
tar zxvf $RUBYGEMS_FILE

# This is crucial. rubygems setup really cares where ruby ran from, and if
# you have a system-wide ruby then it might get confused.
export PATH=$INSTALL_ROOT/bin:$PATH
# Of course you will also want to make sure you include this wherever you
# normally set your PATH.

cd $INSTALL_ROOT/build/$RUBYGEMS_DIR
ruby setup.rb

cd $INSTALL_ROOT
which ruby
which gem

gem install rails

gem environment
which rails
rails --version
h1

IE6 Nasty CSS Freeze

October 30, 2007

I was pulling my hair out for most of the day. I had a page that was working fine in Firefox and Safari, but every time a certain AJAX response came back, IE 6 would hang. It would go to 90% CPU and need to be killed from Task Manager.

I spent hours digging through JavaScript and ERB code, commenting things out, trying to track it down. I got it down to a single table. I commented out various parts of the ERB generating the table for about an hour. The syntax was fine. I was sure the code had no bugs. Getting frustrated I removed almost everything from the table. It was when I removed the style attribute that things finally started working.

Here’s the change that got it working in the end:


/* padding: 5px 0px 5px 0px; */
padding-left: 5px;
padding-top: 5px;

They do exactly the same thing, but for some reason the first is big trouble. Google points me to other people who have had this problem. From what I can tell, it may be triggered only inside floating div’s. I probably had one of those but was ready to call it a day once I found the problem.

If you are experiencing a nasty IE6 freeze then check your CSS for shorthand padding like the above.