Migration Naming Collisions

written by stonean on June 17th, 2008 @ 12:14 PM

In a very short amount of time, I realized that using a timestamp for the migration number was too cumbersome and I think it is a mistake that will hopefully be corrected in future versions of Rails.

That started me thinking about the conversion that would be necessary to move away from timestamped migrations and I didn't like what I was foreseeing. Instead of going through that headache, I decided to stick with the standard version number scheme, this post shows you how to do this.

So how do you solve the migration collision issue without this timestamp feature? This is actually easy, just create a file named "version" in your db/migration directory. If you are working on a team and are going to create a new migration (or more), just edit this file and put the highest number migration in your source and commit it.

This will prevent you from having to commit your migration and your team can be notified of the next version number they should use.

After all, as developers, we need to communicate when working on a project. If you don't, you are asking for trouble.

Nested Resources

written by stonean on June 6th, 2008 @ 11:16 AM

Nested resources sound nice and look cool on the url:

http://wickedcoolblog.com/posts/1/comments

In order for this to work, you have to define this relationship in your routes file as such:

  map.resources :posts do |posts|
    posts.resources :comments
  end

So what does this mean from a content structure? Does the comments controller reside in a posts directory? Is the comments controller namespaced with posts?

Fortunately neither of these constructs are required. Quite simply, when you call the above url you are getting the following parameters:

{"action"=>"index", "post_id"=>"1", "controller"=>"comments"} 

As you can see, you're still just accessing the comments controller and the only thing special about it is the post_id parameter. Your comments controller needs to process this parameter to ensure that all comments belong to the post_id given.

In the resource oriented construct of a REST (Representational Stage Transfer) design this doesn't quite match. With the above nested route definition, you won't be able to access the comments resource without going through the posts resource. This can be fixed with a slight addition to your routes file:

  map.resources :posts do |posts|
    posts.resources :comments
  end

  map.resources :comments

Notice that comments are defined twice. This now gives you the ability to access:

http://wickedcoolblog.com/posts/1/comments

and

http://wickedcoolblog.com/comments

Now we have an issue with our comments controller. If we try to access "/comments", we don't get the post_id passed but our previous code (with the nested resource) depended on it.

If you had designed your initial controller with a before filter, this change would be a lot easier. For example:

class CommentsController < ApplicationController
	before_filter :find_models, :only => :index
	before_filter :find_model_instance, 
                           :only => [:show, :edit, :update, :destroy]
...
  private
    def find_models
      @comments = Comment.find(:all, 
                        :conditions => ["comments.post_id = ?", params[:post_id]])
    end

    def find_model_instance
      @comment = Comment.find(params[:id], 
                       :conditions => ["comments.post_id = ?", params[:post_id]])
    end
end

To add the ability to access the comments resource without going through products, you need to modify this a bit:

class CommentsController < ApplicationController
	before_filter :find_models, :only => :index
	before_filter :find_model_instance, 
                           :only => [:show, :edit, :update, :destroy]
...
  private
    def find_models
      if params[:post_id]
        @comments = Comment.find(:all, 
                        :conditions => ["comments.post_id = ?", params[:post_id]])
      else
        @comments = Comment.find(:all)
      end
    end

    def find_model_instance
      if params[:post_id]
        @comment = Comment.find(params[:id], 
                       :conditions => ["comments.post_id = ?", params[:post_id]])
      else
        @comment = Comment.find(params[:id])
      end   
    end
end

**Note: This could be refactored to be more "DRY" and should have some security code added, but will serve for demonstration purposes.

There has been quite a lot of discussion on nested resources and issues with people not understanding when to use them. So, coming up soon is an article focused on what to look for when making a decision to use nested resources.

Nothing should be used all the time. In the case of nested resources, there only a few times they should be used and never more than one level deep.

depends_on

written by stonean on May 27th, 2008 @ 09:20 AM

For one of my projects I had the need for a polymorphic association in which one object required the existence of the other. I had written a specific version of this, but decided it could easily be abstracted. I didn't go with the built in ActiveRecord polymorphic features as I wanted to strip it down to the basics to see if it would work. Why? I would love to use this in DataMapper at some point.


module Stonean
  module DependsOn
    def self.included(base)
      base.extend Stonean::DependsOn::ClassMethods
    end

    module ClassMethods
      def depends_on(model_sym, options = {}) 
        has_one model_sym, 
                :foreign_key => "#{options[:as]}_id",
                :conditions => "#{options[:as]}_type = '#{self.name}'"

        validates_presence_of model_sym
        validates_associated model_sym

        define_save_method(model_sym, options[:as])
        before_save "save_#{model_sym}".to_sym

        options[:attrs].each{|attr| define_accessors(model_sym, attr)}
      end
      
      def define_save_method(model_sym, poly)
        define_method "save_#{model_sym}" do
          eval("self.#{model_sym}.#{poly}_type = self.class.name")
          eval("self.#{model_sym}.#{poly}_id = self.id")
          eval("self.#{model_sym}.save")
        end
      end

      def define_accessors(model_sym, attr)
        define_method attr do
          eval("self.#{model_sym} ? self.#{model_sym}.#{attr} : nil")
        end

        define_method "#{attr}=" do |val|
          model_defined = eval("self.#{model_sym}")

          unless model_defined
           eval("self.#{model_sym} = self.build_#{model_sym}")
          end

          eval("self.#{model_sym}.#{attr}= val")
        end
      end

    end
  end
end
ActiveRecord::Base.send :include, Stonean::DependsOn

Here's an example, but first a little information. Content is a model that all "presentable" objects in my cms depend on. It holds the name and url attributes so when you are calling message.name, you are really calling message.content.name.

class Message < ActiveRecord::Base
  depends_on :content, :attrs => [:name, :url], :as => :presentable
end

This means your form and views can use these methods and not worry about the underlying association. for example:

 text_field_tag "message[name]", value

Now you don't have to do anything special in your views or controller to build and save the depends_on object.

This example is very specific, but with a little modification, can be used to implement a class table inheritance architecture. I definitely plan on doing this soon.

So what are the drawbacks? The major one is the find method. As it's written now, you will make two calls to the database: one for the main object and one for the dependent object. That blows. I will be addressing this issue very soon.

I will be releasing this as a gem in the near future, but for now you can just copy the code above and add it into your config/initializers directory.

If you have any ideas or suggestions, I would love to hear them.

Continuous Integration and TeamCity

written by stonean on May 21st, 2008 @ 11:53 AM

In our role as a "Solutions Provider", it is important to provide reassurances that the code we are delivering is solid. One way of doing so is to utilize testing frameworks such as RSpec. Writing tests provide more functionality than proving code "should do X", writing tests helps developers understand the goal of the code they are writing. A positive side effect of this construct is that properly written tests will also let you know when other developers (or even the author) attempt to use the code incorrectly.

Testing frameworks aren't the panacea for all project issues, but when used properly, they are very effective. When working in a team environment, one developer may alter a piece of code or configuration setting that is unknowingly used elsewhere. While their local tests should catch the issue, not everyone remembers to run the tests before they commit. In order to prevent these sort of issues we decided to implement the practice of Continous Integration.

To facilitate the process we decided to evaluate TeamCity. TeamCity is a continuous integration system that utilizes a distributed agent model and supports multiple Java and .Net build runners as well as a Rake. Having this multi-platform/technology support means TeamCity will be able to handle all the technologies we work with and the distributed agent model allows us to run multiple project tests at once.

We have configured TeamCity for use with Ruby and .Net (Java setup coming soon) and are still in evaluation mode. We haven't really put it through the paces yet, but are pleased with the product and will continue forward.

More info on TeamCity coming soon...

Backing up your Rails MySQL DB via a Rake task

written by phil on May 21st, 2008 @ 08:56 AM

This article is the source of this code, but I’ve included some of the recommended modifications in the comments. This will back up a MySQL database (via mysqldump) into a directory of your choosing (or RAILS_ROOT/db by default), rolling automatically at 20 backups, and using your database.yml as the source of the login information (so you keep it DRY).

require 'find' 
  namespace :db do  desc "Backup the database to a file. Options: DIR=base_dir 
RAILS_ENV=production MAX=20"
    task :backup => [:environment] do
      datestamp = Time.now.strftime("%Y-%m-%d_%H-%M-%S")    
      base_path = ENV["DIR"] || "db"
      backup_base = File.join(base_path, 'backup')
      backup_folder = File.join(backup_base, datestamp)
      backup_file = File.join(backup_folder, "#{RAILS_ENV}_dump.sql.gz")    
      File.makedirs(backup_folder)    
      db_config = ActiveRecord::Base.configurations[RAILS_ENV]   
      sh "mysqldump -u #{db_config['username'].to_s} #{'-p' if db_config[
'password']}#{db_config['password'].to_s} --opt #{db_config['database']} | 
gzip -c > #{backup_file}"     
      dir = Dir.new(backup_base)
      all_backups = (dir.entries - ['.', '..']).sort.reverse
      puts "Created backup: #{backup_file}"     
      max_backups = ENV["MAX"] || 20
      unwanted_backups = all_backups[max_backups.to_i..-1] || []
      for unwanted_backup in unwanted_backups
      FileUtils.rm_rf(File.join(backup_base, unwanted_backup))
      puts "deleted #{unwanted_backup}"
    end
    puts "Deleted #{unwanted_backups.length} backups, #{all_backups.length - 
unwanted_backups.length} backups available"
  end
end

I created a cron entry like so to backup my mephisto database every day at 3am (EST):

0 3 * * * cd /srv/mephisto-0.8/ && /usr/local/bin/rake db:backup RAILS_ENV=production

Of course if your running on a VPS or hosted solution, your provider is likely doing their own backups, but if you’re not, this can come in handy.

Deploying Rails 2.0.2 on Tomcat 5.5.x with Warbler

written by mark on May 8th, 2008 @ 12:26 PM

After working with Rails for some time I wanted to determine how to deploy an application on Tomcat. I will discuss how to build a war file that can be used on Tomcat and show pitfalls I experienced along the way. Here are the technologies I am using for this deployment:

  • JRuby 1.1.1
  • Rails 2.0.2
  • Warbler 0.9.5
  • MySQL 5.0.4

To package up my Rails application I am using Warbler as indicated above. This is an alternative to Goldspike but allows a better packaging scheme and an easier configuration. Warble is actually a wrapper to Goldspike and includes these dependencies when you install the gem. You can read more about Warbler here.

I will assume you have Rails installed as a gem in JRuby. To make a standalone war file make sure you run this command to freeze Rails in your project:

$ jruby -S rail:freeze:gems

This will write the standard Rails gem information to your RAILS_ROOT/vendor/rails directory. Here is how you install Warbler from JRuby:

$ jruby -S gem install warble

After this is configured switch to the root of your Rails project and execute this command:

$ jruby -S warble

This will build an exploded war file in a temporary directory within your project. This path can be changed in the warble.rb file that gets installed. Now create a Warble configuration file by executing this command since we will need it (not sure why this is done after the fact):

$ jruby -S warble config

After generating a configuration file you should consider updating the JRuby jar file that comes with Warble since you will want the latest version packaged with your war file. If you do not do this Warble will always include the original version of the JRuby jar with your war file. Add the jruby-complete-1.1.1.jar file which can be obtained here) to your RAILS_HOME/lib directory. Grab the latest Goldspike jar file and place it in your RAILS_HOME/lib directory. Now add this code to the configuration:

config.java_libs.reject! {
|lib| lib =~ /jruby-complete|goldspike/
}


This allows you to externally package your own versions of JRuby and Goldspike and reject the verions of these jar files that come bundled in the gem directory ($JRUBY_HOME/lib/ruby/gems/1.8/gems/warbler-0.9.5/lib/warbler).

Also, you can delete the exploded directory and the war file by issuing this command:

$ jruby -S warble war:clean

From this point you just move the war file to your Tomcat webapps directory and start the server. This is great when everything works. However, I was lucky enough to run into some issues while making this happen.

The first issue occurred when I started Tomcat with the war file I built with Warble (remember that this is using Goldspike under the covers) and got this error message in the Tomcat logs:

“Could not load Rails. See the logs for more details.”

Yipee! So when I went to look in the Tomcat logs there was no additional information. Great! It turns out that the stack trace output gets swallowed on a Mac. This is fairly easy to fix (but should be patched by the Goldspike team) by modifying the source code for the goldspike-1.6.1.jar file to emit the full stack trace. Grab the latest Goldspike code from here:

svn checkout
svn://rubyforge.org/var/svn/jruby-extras/trunk/rails-integration


You will have to modify src/main/java/org/jruby/webapp/RailsFactory.java like this:


} catch (RaiseException e) {
//added this line so the full stack trace is shown
e.printStackTrace();

logRubyException("Failed to load Rails", e);
throw new ServletException(
"Could not load Rails. See the logs for more details.");
}

After you rebuild the Goldspike jar add it to your RAILS_ROOT/lib. Now re-warble your war file and put it on your Tomcat server. Now you should be able to find your error. In my case I was not making a connection to my database. I was clearly missing gems in my war file. Great!

This really is not too big of a deal. You can explain to Warbler what gems need to be packaged with your war file. Here is a snippet from my warble.rb file that shows how I included the missing gems:

# Gems to be packaged in the webapp. Note that Rails
#
gems are added to this list if vendor/rails is not
#
present, so be sure to include rails if you overwrite
# the value

config.gems = ["activerecord-jdbc-adapter", "jruby-openssl", "activerecord-jdbcmysql-adapter", "jdbc-mysql"]


Alright re-warble and... still no connectivity. Awesome! This time I was missing my MySQL jar file in my war file and the activerecord-jdbcmysql-adapter gem could not communicate with the implementation jar. To fix this copy your MySQL jar file to the RAILS_ROOT/lib directory in your Rails project.

One more re-warbling and more good news:

“Rails Error: No :secret given to the #protect_from_forgery call. Set that or use a session store capable of generating its own keys (Cookie Session Store)”.

This is a known bug with Goldspike and Rails 2.0. So edit your web.xml file and add the following:

<context-param>
<param-name>jruby.session_store</param-name>
<!-- This value really means let Rails take care
of session store -->
<param-value>db</param-value>
</context-param>

OK, please just one more re-warbling and deployment to Tomcat and a successful standalone war file has been created and deployed. *birds singing*

I would also suggest increasing the Java memory setting in the JAVA_OPTS of Tomcat to at least -Xmx512m to improve performance. Also keep in mind that Warble is configured to use the production environment for your Rails application so make the appropriate migrations before starting the application. You can make further modification to the Goldspike configuration within the warble.rb file to tweak the pool of Rails runtimes. Once I made these changes it was pretty transparent where I was running my Rails application.

I hope this saves other people time when running into issues. This was kind of a frustrating process since it should be a simple one line deployment. However, I was happy with the end results.

Writing Efficient Ruby Code

written by stonean on May 6th, 2008 @ 05:36 PM

Writing code is not typically atomic in nature. Even though a particular method may be, you have to think about the "big picture" in relation to the Module or Class and how it fits within your architecture. It's easy to lose focus on some of the finer details that could have a negative impact on the performance of your system.

These type of errors are usually unintentional and it's not that they aren't considered harmful, they just aren't considered. To discover some of the things you can do to write better code I recommend picking up a copy of "Writing Efficient Ruby Code" by Dr. Stefan Kaes.

The information value in relation to the cost of the book ($12.99) is very good and he does provide excerpts to entice you to buy. All in all, a nice job done.

Where does the code go?

written by stonean on May 5th, 2008 @ 06:09 PM

Over my time of using Rails I've struggled with the placement of code that does not explicitly belong to a controller, model or view. My Java background probably had a lot to do with my selection of the lib dir for all 'extra' code when I first started.

Then I learned about plugins and loved the auto require feature. No more requires in my environment.rb. Sweet, but I didn't feel everything qualified as a plugin, or at least to my definition of a plugin. So now I have some code in the plugin directory and some code in the lib dir without any rule on where to look for a particular type of code. Things are starting to get messy.

I wasn't stopping there. I decided to use helpers for their intent to house "view only" code. This cleaned up my lib directory some but now there are three places to look. You would think that would be enough. Oh no, there's more!

Rails 2.0 introduced config/initializers and I thought this was great, the answer to my dilemma of lib vs plugin. Code in the initializers dir is loaded automatically like the plugin and it wasn't "way out there" in vendor/plugins so it felt more like a part of the application. Initializers for everything!

...

Those of you who have been coding for a while realize that this is a bad idea. Nothing is for everything. So before I went on my mindless bulk move, I decided I needed to think about this some. This is what I have decided.

View code goes in the helper. That was easy.

Plugins should be reserved for generic functionality such as attachment_fu. For every project you write that needs file uploads you can use this same plugin. You don't have to alter the code on a per project basis. It's good to go. So, if you have multiple applications and you find yourself copying code over and over without modifications, it should probably be a plugin.

In one sense, I consider initializers to be plugins that may need some degree of customization. Project constants are something you use all the time, but they need to be specific for the project. Even though you may reuse a lot of the same constants, odds are some will be specific to the project. Don't separate out the ones that never change to a plugin. This leaves you with two places to look and will cause you headaches.

Another use for initializers is code that is used throughout your application, but it's not generic enough to be a plugin. A module that maintains your session is a perfect example.

This leaves the lib directory. This should be reserved for specialized functionality, something only a couple of controllers or models may use and would be "required" only where necessary. Specialized math or string methods come to mind.

Another, more common use of the lib directory would be to house modules that eliminate repetitive code. For example, say I have multiple models using the same find method like find_recent_posts_by_author. This could be applied to books, pages, comments, etc... I don't want to rewrite this find_recent_posts_by_author method in each of those models. So, I write it once in a module and include it in only the models that need that functionality.

Consider these guidelines, not strict rules.

You can also add your own directories and then add them to the Rails load path. A very common use of this would be the addition of a app/mailers. Rails mixes these into the app/models and I (among others) don't agree with this approach.

If you have some other constructs or disagree with any of the above, I'd love to hear your approach.

Mikey

written by stonean on May 5th, 2008 @ 05:58 PM

So, I have a site that synchronizes data with another server. It does this via after_create, after_update and after_delete triggers on some models. All of those triggers use the same method that returns a connection object which has various methods such as:

  # SyncServer::connection method
  module SyncServer
    def self.connection
     new_client.connection{|conn| yield conn }
    end
  end

  SyncServer::connection do |conn|
    conn.add_person(person_data)
    # or
    conn.update_person(person_data)
    # or
    conn.delete_person(person_id)
  end
  
  # The following is to demonstrate I could have
  # multiple types of data I'm syncing
  # and therefore multiple methods on the
  # conn object.

  SyncServer::connection do |conn|
    conn.add_other_data(other_data)
    conn.modify_other_data(other_data)
    conn.delete_data(other_id)
  end

While the RSpec tests were running, these triggers were being called which was junking up the SyncServer. This is not cool. In order to avoid this, I needed to be able to disable the synchronization. I definitely didn't want to do this in all my triggers.

Enter Mikey, he's going to replace the conn object I return:

#
# Because Mikey will eat anything
#
class Mikey
  def method_missing(method, *args)
    true
  end
end

Now the new conn method:

  module SyncServer
    def self.connection
     if sync?
      new_client.connection{|conn| yield conn }
     else
      yield Mikey.new
     end
    end
  end

The sync? method just checks if the class variable do_synchronization is true. I set this class variable to false if the RAILS_ENV == test. The result is my triggers don't break, the sync server isn't junked up and my tests pass. All good.