Daniel's Stuff

I write code

Category: Rails

JRuby, Rails and Development mode

Well, that was fun…  I spent quite a bit of time today beating my head against a “memory leak” only to remember that JRuby + Rails + Development mode = very leaky.  Switch to production mode and the problem goes away.

A simple little Rails app with one controller and one model is all that is needed to exercise the problem.  Run rails in development mode, and hit it with requests, memory usage soon skyrockets and the app starts to fall over.  Switch to production mode and the same app runs really nicely 🙂

ASP.Net blows chunks

Really big nasty chunks! I guess I’ve been spoilt by working with rails, and to be fair it’s not really ASP.Net I don’t like, it’s ADO.Net. I mean really, who wants to write 12 lines of code to fill a grid with data from a database! 
 
1. construct a new SqlConnection object 
2. construct a new SqlCommand object 
3. construct a new SqlParameter object 
4. set the parameter name 
5. set the parameter value 
6. add the parameter to the select command 
7. construct a new DataSource object 
8. construct a new SqlDataAdapter object 
9. fill the DataSource using the SqlDataAdapter 
10. connect the DataSource property of the grid to the DataSource object constructed earlier 
11. call the DataBind method of the grid to actually load the data 
12. close the database connection 
 
I guess it’s all supposed to be used via the GUI editing tools which should build a lot of that stuff for me automatically. I assume the GUI built data binding can handle parameters for the select. 
 
Another feature of Rails that I’m missing in ASP.Net is partials. I’m using master pages to give me some of the things that I would have used a layout for in Rails, but there doesn’t seem to be anything quite like partials in ASP.Net 🙁 Fortunately for me it’s a simple application I have to build so there are only a couple of repeated sections of code. 
 
Also, what’s up with not allowing the TextBox control to be bound to a DataSource? I’ve got better things to do with my time than to write a line of code for each TextBox on my form to fill it with data and another to then put that data back into a DataTable so I can have it saved to a database. 
 
A word of advice to all ASP.Net developers who read this, don’t use Ruby on Rails. It will only make you realize how bad you’ve got it 😉

Working from Linux

I’ve been using Linux as my primary development environment in my day job for a couple of months now and for the most part I’m enjoying the change. It’s amazing that the same hardware running Linux seems to run so much faster than when running XP. Maybe I it’s just time for the semi-anual windows reinstall 😉 
 
I thought I’d go the whole hog and try using Emacs as well. I tooled up with all the various
Emacs bits and pirces I needed to make doing rails development under Emacs nice and off I went. It only took a couple of days to get used to the cursor movement and cut/copy/paste commands, but in the end I decided to go back to eclipse :(, and then spent the next day or so wondering why Ctrl-K and Alt-W didn’t do what I wanted 😉 I have to say I enjoyed the couple of weeks I spent with Emacs, but I’m still not ready to give up my modern UI addiction 😉 
 
Maybe one day I’ll give XEmacs a go…

before_create considered harmful

I had a fsck of a time today working with rails. Normally I love Ruby on Rails, but today it gave me the screaming shifts!

I had a model class to which I wanted to add some sensible default values to satisfy some constraints in the database.
The logical place for that was before_create, so I did something like the following

class MyModel < ActiveRecord::Base

def before_create

self.foo ||= true
self.bar ||= Time.now
self.baz ||= false

end

end

Now, I would have thought that would work, but whenever I tried to save an instance of my class to the database the save method would return false 🙁
Hmmmm. Ok, let’s add some logging code and see what the problem is… Are there any errors? Nope. Does the instance think it’s valid? Yes. OK, that’s weird. Maybe there is something going on and the exception is getting eaten by some other code in the application (there are three of us working on this code and we’re not all in the same state, so who knows what one of the others may have done 😉 ). I try creating an instance using the rails console. Same thing (which is to be expected, but I was starting to get a little desperate by this stage).

What was the next thing to do? Go through the code and remove things line by line until I start getting some exceptions. Finally in desperation I took out my before_create method, and lo and behold my error messages come back. It was then that I was struck by the thought that Ruby methods take their return value from the last expression evaluated in their body, so the before_create method was returning false. It seems that there is a nice undocumented “feature” in ActiveRecord that allows application code to stop an object being saved to the database by returning false from before_create, and I imagine before_save.

A little note to that affect in the documentation would have saved me quite a bit of time today.

Ah well. Live and learn I guess 🙂

Multiple ruby on rails applications under different folders served by Apache on Mac OS X

I’ve been doing quite a bit of development recently using Ruby on Rails under Mac OS X. Unfortunately it can be a little tricky to get rails apps deployed nicely under Apache. The machine I’m using is an aging G4 with very little RAM so running rails apps in CGI mode is very slow! Initially I tried FastCGI, but I found it to be unreliable 🙁 
After a bit of looking about on the net I came across SCGI (
http://www.mems-exchange.org/software/scgi/ ) and some code to use it to run rails. apps ( http://www.zedshaw.com/projects/scgi_rails/ ). 
Installing these pieces is pretty straight forward 
 
1. download and install the SCGI apache module 
2. install the cmdparse gem (
sudo gem install cmdparse
3. install the highline gem (
sudo gem install highline
4. install the SCGI rails runner 
5. configure your rails apps for SCGI by executing
scgi_ctrl config in each rails app root folder 
 
Make sure that each of your rails apps has a different port selected in the config/scgi.yaml file 
 
Next we need to update
the Apache config file /etc/httpd/httpd.conf 
 
LoadModule scgi_module libexec/httpd/mod_scgi.so 
AddModule mod_scgi.c 
 
<IfModule mod_scgi.c> 
  # matches locations with a dot following at least one more characters, that is, 
  # things like *,html, *.css, *.js, which should be delivered directly from 
  # the filesystem 
  <locationmatch \..+$> 
    # don’t handle those with SCGI 
    SCGIHandler Off 
  </locationmatch>  
</IfModule> 
 
Alias /app1 “/Library/WebServer/RailsApps/app1/public” 
SCGIMount /tbgmon 127.0.0.1:9999 
<directory “/Library/WebServer/RailsApps/app1/public”> 
  Options +FollowSymLinks 
  Order allow,deny 
  allow from all 
</directory> 
 
Alias /app2 “/Library/WebServer/RailsApps/app2/public” 
SCGIMount /app2 127.0.0.1:9998 
<Directory “/Library/WebServer/RailsApps/app2/public”> 
  Options +FollowSymLinks 
  Order allow,deny 
  Allow from all 
</Directory>
 
 
Now we start each of the SCGI server processes by running the
scgi_ctrl start command in each rails app root folder, bounce apache using sudo apachectrl graceful and the rails apps should be up and running from http://localhost/app1/ and http://localhost/app2/ 
 
That is only half of the story however. We need to have the SCGI server processes start when the machine boots. The way to do this under Mac OS X is to create a startup item. A startup item consists of a couple of files in a folder under /Library/StartupItems. One is a .plist file and the other is a shell script. 
 
Create a folder called SCGI under /Library/StartupItems and then create the file StartupParameters.plist with the following content 
 

  Description = “SCGI”; 
  Provides = (“SCGI”); 
  Uses = (“Web Server”); 
}
 
 
Next create a file called SCGI and paste in this text 
 
#!/bin/sh 
 
## 
# SCGI 
## 

. /etc/rc.common 
 
StartService () 

    echo “Starting SCGI servers” 
     
    pushd /Library/WebServer/RailsApps/app1/ > /dev/null ; /usr/bin/scgi_ctrl start ; popd > /dev/null 
    pushd /Library/WebServer/RailsApps/app2/ > /dev/null ; /usr/bin/scgi_ctrl start ; popd > /dev/null 

 
StopService () 

    echo “Stopping SCGI servers” 
    ps ax | grep scgi | grep ruby | awk ‘{print $1}’ | xargs kill 

 
RestartService () 

    StopService 
    StartService 

 
RunService “$1”
 
 
According to the SCGI rails runner docs there is an option to choose the root folder of the rails app, but I couldn’t get it to work. I suppose I should contact the author about it one of these days 😉 
 
Now with any luck the next time your machine reboots the SCGI servers should be started and Apache should forward requests on to your rails apps.