New-formula-starburst

jQuery and Rails trick - Multiple submit buttons for a single form

0

Say you have a HTML form with two buttons that you each want to submit to different RESTful actions. For example, an email form with a ‘Send’ and ‘Delete’ button, which should each POST to different actions.

With some intelligent conventions, and a few lines of jQuery, we can accomplish that nicely. Here’s a simplified example.

the RHTML View

<% form_for @message, :url => '', :html => { :id => 'message' } do |f| -%>
<%= f.text_field 'subject' %>
<%= f.text_field 'body' %>
<% end -%>
<button type="button" name="send">Send</button>
<button type="button" name="save">Save as Draft</button>

jQuery

  $(document).ready(function(){
    $("button").click(function() {
      $("form#message").attr('action', '/message/' + $(this).attr('name'));
      $("form#message").submit();
    });
  });

This will enable all the buttons on the page so that when clicked, the button will submit to /message/name where name is the name attribute on the button tag.

How-To Update Ubuntu Servers to Close Ruby Vulnerabilities

4

It was announced the other day that some arbitrary code execution vulnerabilities were discovered in almost all production versions of Ruby out in the wild. I’m not sure how vulnerable your typical Ruby on Rails application servers would be, but I’m taking no chances. I run this blog, and all my other production sites on Ubuntu. Updating to the latest patched version of ruby was easy:

$ sudo apt-get install build-essential libssl-dev libreadline5-dev zlib1g-dev
$ wget ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p22.tar.gz
$ tar zxvf ruby-1.8.7-p22.tar.gz
$ cd ruby-1.8.7-p22
$ ./configure --prefix=/usr/local --with-openssl-dir=/usr --with-readline-dir=/usr --with-zlib-dir=/usr
$ make
$ sudo make install

And you’re done. The only sorta tricky part there is the ./configure command, which requires those options to tell the compiler to enable Readline and OpenSSL support which are most often needed in a Ruby on Rails environment. To check and make sure it’s working, type these commands and verify that the output looks like this:

$ which ruby
/usr/local/bin/ruby
$ ruby --version
ruby 1.8.7 (2008-06-20 patchlevel 22) [i686-linux]
$ ruby -ropenssl -rzlib -rreadline -e "puts :success"
success

Now, run your tests, restart mongrels, and you’re safe. Phew.

Trouble with Ruby 1.8.7 and Rails

2
I went to download a fresh copy of Ruby the other day, and noticed that they quietly released 1.8.7 and are promoting it as the recommended install now. I haven’t heard much about its compatibility with Rails, but I was curious about the performance enhancements backported from 1.9. So, I downloaded it … and …. bam!
\ FAILSAFE /!\  Thu Jun 12 21:50:31 -0700 2008
  Status: 500 Internal Server Error
  wrong number of arguments (2 for 1)
    /usr/local/lib/ruby/1.8/cgi/session.rb:267:in `respond_to?'
    /usr/local/lib/ruby/1.8/cgi/session.rb:267:in `initialize_without_cgi_reader'
    /usr/local/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/cgi_ext/session.rb:39:in `initialize'
    /usr/local/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/cgi_process.rb:130:in `new'
    /usr/local/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/cgi_process.rb:130:in `session'
........
A little Googling, and I discover that there is a subsequent patchlevel that addresses this problem. I downloaded 1.8.7-p17 and it seems to get past this one. To compile and install on my Mac:
tar zxvf ruby-1.8.7-p17.tar.gz
cd ruby-1.8.7-p17
./configure --enable-shared --enable-pthread CFLAGS=-D_XOPEN_SOURCE=1
make
sudo make install

So far that seems to work!

Globalize plugin for Rails 2.1

10

Tonight at the Pivotal office I showed a few people the updates and modifications I’ve made to the globalize plugin for Rails.

My main motivation was fixing Globalize to work with Rails 2.1. They changed the way rails views are selected and rendered, and the date_helper api, both which broke the plugin. I forked globalize on github and my fork now works with Rails 2.1.

UPDATED June 14: Thanks to tips from jodosha and David Ramalho, I’ve made a few updates to the branch that fix a few things.

Get the plugin for Rails 2.1.0
script/plugin install git://github.com/heythisisnate/globalize.git
Globalize offers a variety of ways to translate and internationalize your Rails application. I’m using it primarily on my biodiesel stations locator application to translate arbitrary strings:
>> "Biodiesel Stations".t
=> "Biodiesel Stations"

>> Locale.set 'zh-tw'
>> "Biodiesel Stations".t
=> "生質柴油"

In addition to string translations, Globalize does a lot more, including date & time localization, currency, and number formatting differences. It handles pluralization supremely. The original team did a great job, and I’m happy to contribute my changes for Rails 2.1.

I’ve hacked on a few additional features that I previewed tonight … they’re not quite ready for prime time yet. I’ll definitely publish them here when they are.

Rails rake tasks to sync your remote database to your local development environment

9

So, you’re managing or developing a Ruby on Rails application that you deploy regularly using Capistrano (as any sane Rails developer should), and you want a really easy way to sync up the database on your remote production server with the development environment you have running on your local machine. This is really useful for debugging your app, especially if you have a lot of user-generated content. It’s also just really helpful for design and development if your local environment looks exactly the same as your live environment.

Well, I know it’s not that hard to log in to your remote database, export the whole database, copy it back to your machine, and load it into your development environment. But after a few times doing this, you realize there’s got to be a better way.

Since Capistrano gives us so much flexibility to do pretty much anything on our remote machine, there is an easy way. Here are a few tasks that you can freely copy and paste into your application that will automate all this:

  1. Connect to your production database server
  2. Dump your production MySQL database (sorry, this only works for MySQL right now!)
  3. Download the MySQL dump file to your local machine
  4. Replace the contents of your local development environment with the data and structure from your live production environment

Usage

rake db:production_data_refresh

Yep! That’s all there is to it. It uses the database connection information that you have already set up in your config/database.yml file, so no passwords are ever transmitted. It also uses SSH and SFTP to do all the remote communication and data transfer, so everything is nice and secure.

It is highly recommended that you set up public key authentication so you don’t have to log in with your username and password every time Capistrano wants to connect to your remote host.

Get your copy and paste finger ready … the code is right below the fold

Add these tasks to your lib/tasks/my_app.rake file:

namespace :db do
  desc "Dump the current database to a MySQL file" 
  task :database_dump do
    load 'config/environment.rb'
    abcs = ActiveRecord::Base.configurations
    case abcs[RAILS_ENV]["adapter"]
    when 'mysql'
      ActiveRecord::Base.establish_connection(abcs[RAILS_ENV])
      File.open("db/#{RAILS_ENV}_data.sql", "w+") do |f|
        if abcs[RAILS_ENV]["password"].blank?
          f << `mysqldump -h #{abcs[RAILS_ENV]["host"]} -u #{abcs[RAILS_ENV]["username"]} #{abcs[RAILS_ENV]["database"]}`
        else
          f << `mysqldump -h #{abcs[RAILS_ENV]["host"]} -u #{abcs[RAILS_ENV]["username"]} -p#{abcs[RAILS_ENV]["password"]} #{abcs[RAILS_ENV]["database"]}`
        end
      end
    else
      raise "Task not supported by '#{abcs[RAILS_ENV]['adapter']}'" 
    end
  end

  desc "Refreshes your local development environment to the current production database" 
  task :production_data_refresh do
    `rake remote:exec ACTION=remote_db_runner --trace`
    `rake db:production_data_load --trace`
  end 

  desc "Loads the production data downloaded into db/production_data.sql into your local development database" 
  task :production_data_load do
    load 'config/environment.rb'
    abcs = ActiveRecord::Base.configurations
    case abcs[RAILS_ENV]["adapter"]
    when 'mysql'
      ActiveRecord::Base.establish_connection(abcs[RAILS_ENV])
      if abcs[RAILS_ENV]["password"].blank?
        `mysql -h #{abcs[RAILS_ENV]["host"]} -u #{abcs[RAILS_ENV]["username"]} #{abcs[RAILS_ENV]["database"]} < db/production_data.sql`
      else
        `mysql -h #{abcs[RAILS_ENV]["host"]} -u #{abcs[RAILS_ENV]["username"]} -p#{abcs[RAILS_ENV]["password"]} #{abcs[RAILS_ENV]["database"]} < db/production_data.sql`
      end
    else
      raise "Task not supported by '#{abcs[RAILS_ENV]['adapter']}'" 
    end
  end

end

Now, add these tasks to your config/deploy.rb file:

desc 'Dumps the production database to db/production_data.sql on the remote server'
task :remote_db_dump, :roles => :db, :only => { :primary => true } do
  run "cd #{deploy_to}/#{current_dir} && " +
    "#{rake} RAILS_ENV=#{rails_env} db:database_dump --trace" 
end

desc 'Downloads db/production_data.sql from the remote production environment to your local machine'
task :remote_db_download, :roles => :db, :only => { :primary => true } do  
  execute_on_servers(options) do |servers|
    self.sessions[servers.first].sftp.connect do |tsftp|
      tsftp.get_file "#{deploy_to}/#{current_dir}/db/production_data.sql", "db/production_data.sql" 
    end
  end
end

desc 'Cleans up data dump file'
task :remote_db_cleanup, :roles => :db, :only => { :primary => true } do  
  delete "#{deploy_to}/#{current_dir}/db/production_data.sql" 
end 

desc 'Dumps, downloads and then cleans up the production data dump'
task :remote_db_runner do
  remote_db_dump
  remote_db_download
  remote_db_cleanup
end

Enjoy! Please let me know if anything doesn’t work the way you think it should.

Search the Ruby on Rails API

1

I was just sent the link to RoRAPI. It’s a painfully simple but really useful search engine for the Ruby on Rails API, powered by Google Co-op.

Thanks to Brad Gessler for putting it together.

Older posts: 1 2