Apr 24

It’s been now over a week since we moved to Sydney and everything is just great. We’re still house hunting but I got a feeling we’ll have a home soon. :)

In the meantime, this morning I got a feature request on github to allow AppConstants to interpret YAML files with embedded code like this:

development: &default
  max_upload_in_bytes:  <%= 1.megabyte %>

I haven’t needed it myself but thought it would be a nice addition so my latest commit does exactly that. Let me know if you find any issues.

Tagged with:
Feb 28

Back in January I announced a small but useful plugin called AppConstants, that basically provides a central place where you can store environment specific constants. And since I started using Rails 3 in the past week, I thought I’d make it Rails 3 compatible.

The code is really simple and - as I expected - the upgrade process was quite straight forward.

I’m not gonna write a guide here on how to upgrade your plugins to Rails 3 - there is plenty about that around the web - but instead, just show the steps I went through to upgrade mine. Similar plugins might have a similar upgrade path.

- Generators

My plugin makes use of a simple generator that copies its default constants file and initializer to Rails.root/config and Rails.root/config/initializers, respectively. In Rails 2.x it was located under Rails.root/vendor/plugins/app_constants/generators/app_constants and it was defined like so:

class AppConstantsGenerator < Rails::Generator::Base
  def manifest
    record do |m|
      m.directory('config')
      m.file('constants.yml', 'config/constants.yml')
      m.directory('config/initializers')
      m.file('load_app_constants.rb', 'config/initializers/load_app_constants.rb')
    end
  end
end

In Rails 3, the generators had to be moved to Rails.root/vendor/plugins/app_constants/lib/generators. Notice the root directory app_constants under generators has been removed as well. And the code was changed to this:

class AppConstantsGenerator < Rails::Generators::Base
  def self.source_root
    @source_root ||= File.expand_path('../templates', __FILE__)
  end  
 
  def copy_config_files
    copy_file('constants.yml', 'config/constants.yml')
    copy_file('load_app_constants.rb', 'config/initializers/load_app_constants.rb')
  end
end

We had three simple changes here:

- The generator now extends from Rails::Generators::Base: This class uses the Thor infrastructure to handle generators. - more info here.

- I had to implement the source_root class method, which basically tells your generator where to find your template files.

- The manifest method is now called copy_config_files - or anything you want.

The way this works is that, once you invoke the generator, Thor will sequentially call all instance methods in your generator class - or the only instance method in the example above. If your generator does a lot, it will allow for a better organization of your tasks.

And that’s it! I did change a couple of other things but that had to be changed anyway and are not related to the migration.

For Rails 2.3.x users, you’ll find a 2.3.x branch on github that should work for you.

Cheers

Tagged with:
Jan 23

It’s funny how every Rails application I - and possibly you - work on ends up needing some sort of per-environment global constants.

Examples may include the application url - It might be used in account activation emails and thus should be different between the development and production environments.

Or perhaps your application depends on external services that, depending on the environment, are available in different URIs.

There are a couple solutions out there but my needs were simple and straightforward, thus I developed a small rails plugin that is the simplest thing that could possibly work: AppConstants.

It’s been useful for my current project and I hope it can be useful to someone else too ;)

Tagged with:
Jan 13

In one of my Rails projects I’m using Sphinx to provide full-text search capabilities. To integrate both worlds I chose Thinking Sphinx, which is just great and so far has met all of my expectations.

Also, as I previously mentioned, I’m using RVM to manage my ruby installations on both my development and production machines and this setup is what motivated this post.

I use Monit to monitor the services running on my production server - nginx, mysql, php - and as of the first deploy of this application, it only made sense to also monitor Sphinx.

In order to create an initialization script, I would need at least a way to start and stop sphinx from the command line, which, using Thinking Sphinx, can be done using these rake tasks:

$ rake thinking_sphinx:stop
$ rake thinking_sphinx:start

It’s worth mentioning now that I don’t run sphinx as root. I run it with the same user my rails application uses. For the purpose of this post, let’s call it deploy.

When I tried using my script I got errors such as these:

Missing the Rails 2.3.5 gem. Please `gem install -v=2.3.5 rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.

After some digging around I found that the GEM_HOME environment variable for my deploy user wasn’t being set correctly - something to do with rvm, but not quite sure - and to fix this, well, I just had to set it, leaving the final working version of my script somewhat like this - simplified :

#! /bin/sh
 
### BEGIN INIT INFO
### END INIT INFO
 
set_path="cd /your/rails/app/root; export GEM_HOME=/path/to/your/gems; RAILS_ENV=production;"
 
case "$1" in
  start)
        echo -n "Starting sphinx: "
                su - deploy -c "$set_path rake ts:start" >> /var/log/sphinx.log 2>&1
        echo "done."
        ;;
  stop)
        echo -n "Stopping sphinx: "
                su - deploy -c "$set_path rake ts:stop" >> /var/log/sphinx.log 2>&1
        echo "done."
        ;;
      *)
            N=/etc/init.d/sphinx
            echo "Usage: $N {start|stop}" >&2
            exit 1
            ;;
    esac
 
    exit 0

There are 2 things happening here. First, regardless of the user I’m running this init script as, I drop privileges in order to execute the rake task with my deploy user. Second, I set the GEM_HOME environment variable to stop getting the ‘gem not found’ errors.

After that, monit was able not only to monitor my sphinx instance, but also (re)start/stop it with the correct user.

I’m no Linux wizard so if you wanna suggest improvements to this script, feel free to do so!

Tagged with:
Sep 03

Rails Summit 2009

I’ll be speaking at this year’s Rails Summit Latin America in Sao Paulo, Brazil. It will be a good opportunity to meet some amazing people and visit friends back home! :)

Overall I’ll be spending 12 days in Brazil, with 2 of them dedicated to the conference. The other 10 I’ll be in Rio de Janeiro visiting my family and friends. I strongly advise you to spend some time in Rio too, if at all possible. It’s an amazing city and you can contact me if you have any questions.

Back to the conference, my session is called JRuby in the enterprise world: Using Rails with legacy code, and will be given in the form of a tutorial. I will walk you through some problems we had while making this kind of integration at my company, focusing mostly on dependency management.

At the end I hope you’ll have a good understanding of what JRuby is capable of in a legacy environment.

If you’re planning to attend and would like to hear anything specific about JRuby, please let me know, I can try and squeeze in.

C u there!

Tagged with:
Aug 25

Update: The service is now down while we move it from the VPS provided by Rails Rumble to our own. I’ll let you know once it’s up.

Last weekend Philip, Pedro and myself got together for this year’s Rails Rumble.

We haven’t had really decided what to do until a few days before the competition, but I had this really simple idea and decided to go with it. Seems people liked it, given a few positive comments we received.

So, after 48 hours - which were not used to work full-time in the application - The Bird Watcher was born.

The Bird Watcher is a simple way to show the world what’s going on on Twitter for any topic you define.  Go ahead and take a look at the website to see a live example.

We’re planning to keep the service up after the competition is over and we have some nice features lined up to go live on the next release.

In short, it was an interesting weekend and showed me that this team works really well together.

Cheers

Tagged with:
Jul 01

The motivation for this post came from a couple of messages I’ve seen on the jruby’s google group and because I think it’s pretty cool to share how we tackled this problem.

- A little bit of context

We, as a vast amount of people out there, have legacy Java code. A lot. In our case this legacy is pretty much crucial to our business. We can’t just trash it and start from scratch. Bad idea.

On the other hand we do have new features to be built on top of it. But we wanted an easier way to develop this new stuff and decided for a JRuby on Rails solution, using it as a front-end to our existing services.

- What we decided to do

Our final rails project would make use of a specially created jar file containing our Java application. This Jar would also contain a public interface of the services we’d have to interact with from rails.

As any Java application, ours depend on a number of external jar files that correspond to the various framewoks we usually have in place. e.g.: Hibernate, Spring, apache-commons …

Which means we need to make our app’s jar and all it’s dependencies available in the JRuby classpath in order to use it.

Given we’re using warbler to package our application as a war file, we just need to place all jars needed into our rails app’s lib folder. Warbler then takes care of copying any jar files located in there into the war.

- The problem

So we needed a smart way to include all these dependencies into the project, and copy/paste isn’t an option.

In the Java world we use Maven to manage our projects dependencies - and you should too. Because of that our approach involved turning our rails application into a Maven aware project.

Basically we needed a pom file that would declaratively list our java project as a dependency. From there on, Maven knows what the dependencies are and downloads them to your local repository.

Which leaves us with one more task. We need to put all these dependencies into our lib folder after maven has downloaded them.

Below you’ll find the pom.xml file that we use to achieve this with inline comments explaining each bit:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
 
  <groupId>com.company</groupId>
  <!-- notice how we specify the packaging to be a war,
          that way, maven knows where to copy the jar files -->
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <artifactId>railsApp</artifactId>
  <name>railsApp</name>
    <dependencies>
        <dependency>
            <groupId>com.company</groupId>
            <artifactId>java-legacy-app</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
    <build>
        <finalName>railsApp</finalName>
        <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <executions>
          <execution>
            <!-- This tasks only creates a basic structure expected by maven,
                    so it can do its work -->
            <id>create-mock-web-descriptor</id>
            <phase>compile</phase>
            <configuration>
              <executable>/bin/sh</executable>
              <workingDirectory>.</workingDirectory>
              <arguments>
                <argument>-c</argument>
                <argument>
                    mkdir -p src/main/webapp/WEB-INF
                    touch    src/main/webapp/WEB-INF/web.xml
                </argument>
              </arguments>
            </configuration>
            <goals>
              <goal>exec</goal>
            </goals>
          </execution>
          <execution>
            <!-- Now in the package phase we copy the jar files
                    that maven put into the fake web app to our rails' lib folder -->
            <id>copy-needed-jars-into-lib</id>
            <phase>package</phase>
            <configuration>
              <executable>/bin/sh</executable>
              <workingDirectory>.</workingDirectory>
              <arguments>
                <argument>-c</argument>
                <argument>
                    rm -f lib/*.jar
                    cp target/railsApp/WEB-INF/lib/*.jar lib
                    rm -rf target/railsApp*
                    rm -rf src
                </argument>
              </arguments>
            </configuration>
            <goals>
              <goal>exec</goal>
            </goals>
          </execution>
          <execution>
           <!-- Here we optionally create the final war file containing our rails app using warbler,
                     doing a small cleanup of the files and folders maven created  -->
            <id>create-final-war</id>
            <phase>package</phase>
            <configuration>
              <executable>/bin/sh</executable>
              <workingDirectory>.</workingDirectory>
              <arguments>
                <argument>-c</argument>
                <argument>
                   rm -rf *.war tmp/war
                   jruby -S warble &amp;&amp; \
                   mv *.war target/railsApp.war
                </argument>
              </arguments>
            </configuration>
            <goals>
              <goal>exec</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
     </plugins>
    </build>
</project>

Now from the command line we can just run mvn package and we’re good to go.

Maven will start to package the application as a war file. Since it’s not a Java application we create the empty web.xml file in the compile phase, to fool maven.

After it has copied all the dependencies into WEB-INF/lib the next packaging goals will make sure we copy them to our rails’ lib folder, also creating the final war file, ready for deployment.

Note that once done, you can use a simple code snippet similar to this one as an initializer and load all dependencies:

Dir.entries("#{RAILS_ROOT}/lib").sort.each do |entry|
  if entry =~ /.jar$/
    require entry
  end
end

Then we can just use script/console, script/server and so on, as we normally would.

Sorry for the long post, I tried to pack in as much as I could and I certainly hope it’s useful to someone. Any doubts, comments and etc… just drop me a line. :)

Tagged with:
May 16

As you probably know, since rails 2.1 you can write test methods in the following format:

test "hotel should return its permalink" do
  #your test code here
end

Which is great, as the test name becomes much more clear. But you can’t simply run this test easily from the command line. You’d have to run something like:

$ ruby your_test_file.rb -n test_hotel_should_return_its_permalink

It annoys me. And it’s not practical either to make the test fail just so you can get the test’s real name.
I wanted to be able to just copy and paste the readable name in the console and have Test::Unit do the conversion and run it for me, like this:

$ ruby your_test_file.rb -n "hotel should return its permalink"

So I created readable_test_names_runner. It’s a tiny rails plugin that adds this feature for you.

Enjoy.

Tagged with:
May 05

The rcov_plugin project is a rails plugin for rcov that adds some useful rake tasks to your application.  And since I’m currently working in a JRuby project it made sense to use this plugin.

The thing is, among other stuff, an rcov report from a JRuby project includes some files that shouldn’t be there at all, plus you also need to change the way you call rcov as such. Thus, I thought I’d contribute these changes to the plugin and my pull request was approved this morning - just install the latest version and you should be good to go.

It was useful for us here, hope it might be useful for you too.

Enjoy :)

Tagged with:
Apr 10

As many of you know the new language supported at GAE now is Java, as officially announced on their blog. As a Ruby/Rails developer you might not be interested on it but here is a reason you should be: JRuby.

It was only a matter of time until we saw some people deploying JRuby on Rails apps on GAE, like Ola Bini’s mini blog app. Guess that was the first one really, as he was beta testing the service in secret. Google App Engine imposes a few catches to any java application deployed there and any JRuby app wouldn’t be different. For instance, your Java API access is limited to these classes - called JRE Class whitelist.

As you can see on his blog, you don’t need active record and in fact shouldn’t even be loading that on your app.

I felt compelled to try it and the timing was perfect. I am currently developing a JRuby on Rails app at the company I work for and it was a perfect fit, since we are not using ActiveRecord. The reason is that we get the data we need from other sources, such as web services and even text files.

Ola Bini’s tips were crucial here. He provides a small script you can use to prepare the jars you’re sending to your app. Another important piece was the Google App Engine SDK for Java. It ships with a server that emulates GAE’s behaviour locally so you’re less likely to have problems once you deploy it.

I did have a problem though with the number of files uploaded to my appspot. It’s currently limited to 1000 - a thousand - and a Rails app can easily exceed this limit. So before deploying, remove anything that is not crucial: activerecord - you should’ve done it already - , all tests directories - including the ones inside gems your app needs in order to work, fixtures and etc.

After that it was rewarding seeing a custom JRuby On Rails application working perfectly on GAE. And as much as I’d like to, I can’t really share the URL since it’s a private app but I encourage people to try it. I believe GAE will ultimately help the community improve JRuby even more.

And as a last tip, this time thanks to Fabio Akita, is this snippet. You should redirect your log so you can debug your app form GAE’s dashboard.

Have fun!

Tagged with:
preload preload preload