26 Aug 2010, 8:44pm
ruby:
by

1 comment

Repost

This post is inspired by
http://pupeno.com/blog/really-resetting-the-database/#comment-1179
. But as my blog mostly serves as a reference for my future self, I’d like to reprint this little snippet of code here as well.

namespace :db do
  desc "Crush and burn the database"
  task :hard_reset => :environment do
    File.delete("db/schema.rb")
    Rake::Task["db:drop"].execute
    Rake::Task["db:create"].execute
    Rake::Task["db:migrate"].execute
    Rake::Task["db:seed"].execute
    if !Rails.env.test?
      Rake::Task["db:data"].execute
    end
  end

  desc "Generate sample data for developing"
  task :data => :environment do
    # Create the sample data in here
  end
end

TODO and Custom Annotations in Rails Applications

While writing software it’s common to leave comments for your future self. For instance, if you have written some code but realize that it should be refactored to be more efficient, you may place something along the lines of “TODO: change active record find method and replace w/ a custom sql select finder “. With rails, if you follow this convention, you can get a list of your annotations with a rake task.

rake notes:todo

which will print out the file where the the todo was found along with the line number and the comment…

app/controllers/application_controller.rb:
  * [  8] fix me

Rails defines several other annotation types for you

rake notes                                # Enumerate all annotations
rake notes:fixme                          # Enumerate all FIXME annotations
rake notes:optimize                       # Enumerate all OPTIMIZE annotations
rake notes:todo                           # Enumerate all TODO annotations

And you also may define your own

# SEAN: please rewrite this method to query only chunky bacon

you may find all instances of “SEAN” by running

rake notes:custom ANNOTATION=SEAN

Load All ActiveRecord::Base Model Classes in Rails Application

Here is a simple rake task which will instantiate all of your Active Record models, provided that they are located in the RAILS_ROOT/app/models directory. Interestingly, all plugin models are instantiated by default when you run the task, for instance, if you are using the Acts As Taggable On plugin, you have access to Tag, Tagging without having to include the plugin models directory path to the task.

namespace :load_ar do
    desc "load up all active record models"
    task :models => :environment do
      models = ActiveRecord::Base.send(:subclasses)
      Dir["#{RAILS_ROOT}/app/models/*"].each do |file|
         model = File.basename(file, ".*").classify
         models << model unless models.include?(model)
      end
   end
end

If your’re in the console, you can get all the load paths for your Active Record models with the following from the API.

Rails.configuration.load_paths.each do |path|
   p path
end

Rake DB Everything, Dump, Destroy, Create, Load

I’m a big fan of the yaml_db plugin. But I don’t like running rake db:data:load, only to find that my db columns mismatch my model attributes, thus aborting the data import task. To quickly add/remove columns/attributes from a model and rebuild the database with previous db info, I wrote this simple rake task. It saves model records as yaml in db/seandb.yml, and reloads them in the same task but with the db rebuilt. I nest the save method in begin/rescue so that if there are any conflicts the task will continue.

This biggest challenge was to get a list of all the active record models in the Rails app. This problem has been posted a lot and I didn’t find an easy solution. For now, I just look in the app/models directory and ‘classify’ and ‘constantize’ the file name. This will load the model so that I can iterate over all the active record subclasses and call the appropriate Model.find(:all) method. I could maybe do the same w/ all files in the Rails.configuration.load_paths, but my models are, at least for now, under app/models. Plugin models are loaded and available from the rake task if you require the :environment.

It’s as simple as running

rake db:everything
SAVEDB = "#{RAILS_ROOT}/db/seandb.yml"
namespace :db do
   task :everything => [:environment, :spit, :drop, :create, :migrate, :populate] do
     desc "spit out model records as yaml, rebuild the database and repopulate the db"
   end

   task :spit do
    Dir["#{RAILS_ROOT}/app/models/*"].each {|file| (File.basename(file,".*").classify.constantize)}
    File.open(SAVEDB, "w") do |f|
      ActiveRecord::Base.send(:subclasses).each do |model|
        begin
          model.find(:all).each do |record|
              f.write(record.to_yaml)
              print "\twrote #{record.class}\n"
          end
        rescue
        end
      end
    end
   end

   task :populate do
    File.open( SAVEDB ) do |yf|
      YAML.each_document( yf ) do |ydoc|
        begin
          m = ydoc.clone
          m.save
          p "...saved #{m.id}"
        rescue
        end
      end
    end
   end
end
11 Jul 2009, 11:56pm
Ruby on Rails:
by

4 comments

Use a Cron Job to Automate Sphinx Index Refresh from Rails Rake Task

If using Sphinx, you need to refresh indexes when you add new content to your database. This is fairly easy to do by hand

rake thinking_sphinx:index RAILS_ENV=production

But if you want to automate this and use a cron, remember to set the PATH, SHELL and RAILS_ENV variables for your job. The environment isn’t the same when you’re doing it by hand and your index will fail silently :(

You find your specific PATH and SHELL info like so

echo $PATH
echo $SHELL

To get into the cron and set your schedule

crontab -e
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
SHELL=/bin/bash
RAILS_ENV=production

# re-index production sphinx every 15 minutes
*/15 * * * * root cd /var/www/rails_app && /usr/local/bin/rake thinking_sphinx:index >> /dev/null 2>&1

More information available here

http://heimdull.blogspot.com/2009/05/journey-with-thinking-sphinx-and-crond.html

http://groups.google.com/group/thinking-sphinx/browse_thread/thread/5451458fae7d6124

Set Cron Job to Run Every Five Minutes for a Ruby on Rails Rake Task

First off you’ll need to edit your cron file. Normally, the cron files are kept under /etc/cron.daily or /etc/cron.hourly but we can just use the command line tool, crontab and pass it the -e flag, so that we can edit the file without any fuss.

sudo crontab -e

If this is the first cron you’re installing you should see a blank file or something that looks like this

# m h  dom mon dow   command

Essentially this is telling you the order of the arguments you need to specify. Each asterisk represents an interval of time. In this order they are

Minute, Hour, Day of Month, Month, Day of Week and then the path to your command. So to set up our cron to run once every five minutes we’ll write

*/5 * * * * /path/to/my/script

It’s important to note that it is */5 and not just 5. The interval for minute is 0 – 59, meaning that if you just enter a 5, you’ll run your cron job only once an hour but at the 5th minute of that hour. To specify that we want to run it every 5 minutes we need the */5.  Also, note that the cron will execute your command via the path. If you need an interpreter like ruby, rake or php, don’t forget to put that as a part of your command. For instance this will set a rake task to run every five minutes on a Ubuntu box.

*/5 * * * * cd /var/www/my_ror_application  && /usr/bin/rake RAILS_ENV=development db:migrate

You can see that my command uses cd, changing directories to my application. I then specify the full path to the rake program, /usr/bin/rake and give it arguments, including the environment and then of course, the task I want to execute. In this case I’m migrating the database. Which is obviously pointless. Maybe you’ll want to email forum news or send out activation emails.

For more information here is a great reference mkaz.com

Namespacing in Rails

With namespace routes in Rails you can easily create a prefix for select resources. For instance, if you have an admin area or an account dashboard you can give logged in users access to methods that are not otherwise available. To use namespaces define them in config/routes.rb. *Note: this is available for the latest release of Rails, at this time it is 2.3.0. I think it’s supported back until Rails 2.0, but haven’t tested it.

In your config/routes.rb file

map.namespace :dashboard do |dashboard|
    dashboard.resources :properties, :collection=>{:available => :get}
end

This namespace will create routes such as dashboard/properties, dashboard/properties/1, essentially all the CRUD paths as well as a collection method “available” dashboard/properties/available. These routes can be accessed in your views with methods such as new_dashboard_property_path, available_dashboard_properties_path  etc. If your property model has it’s own controller that isn’t namespaced, properties_controller.rb, remember to modify the property form_for method to tell it to use the dashboard namespace. The normal form_for(@property), method takes just your property object. Instead pass the dashboard symbol inside of an array  to form_for

<% form_for [:dashboard, @property] do |f| %><% end %>

You can easily see all of the available paths from the command line using rake routes. I use grep to filter the results for conveinence, because on a large application I don’t necessarily need to see all the routes if I’m working just within a single namespace. rake routes | grep dashboard