ActiveMerchant and Authorize.Net

Posted by Brian in Rails, Howto, snacks (June 4th, 2007)

I’ve been working on payment processing with AuthorizeNet, following the documentation for the ActiveMerchant plugin, as well as an excellent book on the subject. However, I find that both sources really lack the true implementation details, so I figured I’d write it up here.

Step 1: Get a developer account.

Go get a developer account from Authorize.Net . They’ll ask you some questions and you’ll get an account in about 24 hours.

Step 2. Get your API login and transaction IDs.

This is really not documented well. ActiveMerchant’s docs all say to create a transaction with

   gateway = AuthorizeNetGateway.new({
       :login => "user",
       :password=>"password})

However, you don’t use the username and password for AuthorizeNet. You use a separate set of credentials..

1. Log into the Merchant Interface
2. Select Settings from the Main Menu
3. Click on API Login ID and Transaction Key in the Security section
4. Type in the answer to the secret question configured on setup
5. Click Submit

Then copy the credentials… you’ll need them later.

Step 3. Install ActiveMerchant

VIsit www.activemerchant.org for installation instructions.

Step 4. Add a configuration file

I suggest creating a file called “config.yml” in your config/ folder. It comes in handy for a lot of things. I’ll store the API login and transaction key in this file.

production:
  auth_net_user: asdfga
  auth_net_pass: 1234412355
development:
  auth_net_user: asdfga
  auth_net_pass: 1234412355
test:
  auth_net_user: asdfga
  auth_net_pass: 1234412355

Remember, that’s a yml file, so make sure you don’t use tabs, and be sure to get your spacing right.

Step 5. Reservation model

My particular application is a reservation system. Regular readers of my blog know I’m really into test-driven development and this is where I really found the docs lacking. Even the book I read, which pushes for TDD the whole way through, never once touched on how to test the Authorize.Net gateway.

I like unit tests a lot, and so rather than use the controller to do the payment processing, I use the model. I want to find a reservation that’s already been created, set the credit card details, and call a method called “process” that will return true if it worked and false if it doesn’t. The process method will set the status to 1 if it was successful.

 
def test_should_process_order_successfully
 
    r = Reservation.find 1
    r.status = 0  # want to make sure this has a "pending" status.
    r.step = "checkout"    # need to set this - validations for cc info run only if this is set
    r.customer_ip = '192.168.1.155'
    r.card_type = "Visa"
    r.card_number="4779139500118580"
    r.card_verification_value = "410"
    r.card_expiration_month = "10"
    r.card_expiration_year = "2008"
    r.billing_city = "Springfield"
    r.billing_state = "NT"
    r.billing_zip =" 54703"
    r.billing_address ="123 Fake Street"
    assert r.process
    assert_equal(1, r.status)
end

With that set, I can add the following code to my model.

#  id                     :integer(11)   not null, primary key
#  customer_email         :string(255)   
#  confirmation_number    :string(255)   
#  payment_transaction_id :string(255)   
#  created_at             :datetime      
#  confirmed_at           :datetime      
#  processed_at           :datetime      
#  cancelled_at           :datetime      
#  phone_number           :string(255)   
#  billing_address        :string(255)   
#  billing_city           :string(255)   
#  billing_state          :string(255)   
#  billing_zip            :string(255)   
#  user_id                :integer(11)   
#  status                 :integer(11)   default(0)
#  passengers             :integer(11)   
#  total_cost             :integer(10)   
#
class Reservation < ActiveRecord::Base
include ActiveMerchant::Billing
belongs_to :user
validates_presence_of :billing_address,
    :billing_city,
    :billing_state,
    :billing_zip,
    :customer_ip,
    :card_type,
    :card_verification_value, :card_number, :card_expiration_month, :card_expiration_year, 
    :if=> Proc.new{|record| record.step == "checkout"}
 
  # cc fields as accessors so we don't store anything bad.
  attr_accessor :card_type, :card_expiration_month, :card_expiration_year, :card_number, :card_verification_value, :step
 
  # Process the payment
  def process
    self.processed_at = Time.now
    begin
      process_payment
    rescue => e
      logger.error("reservation #{self.confirmation_number} failed with error message #{e} ")
      self.error_message = "#{e}"
      self.status = 7  #failed
    end
    save!
    self.status == 1
        
  end
    
  protected
 
    def process_payment
     
     # this forces the system to use the testing server, which is what all dev accounts use.
     ActiveMerchant::Billing::Base.mode = :test if RAILS_ENV != "production"
 
     # read api key and  transaction # from config file
    c = YAML::load(File.open("#{RAILS_ROOT}/config/config.yml")) 
    user = c[RAILS_ENV]['auth_net_user']
    pass = c[RAILS_ENV]['auth_net_pass']
 
     creditcard = ActiveMerchant::Billing::CreditCard.new(
       :first_name => self.user.first_name,
       :last_name => self.user.last_name,
       :number=> self.card_number,
       :verification_value =>card_verification_value,
       :type => self.card_type,
       :month => self.card_expiration_month,
       :year => self.card_expiration_year
     )
     
     if creditcard.valid?
         options = {:name => self.user.full_name,
            :email => self.user.email,
            :phone => self.phone_number,
            :ip => self.customer_ip,
        :card_code => self.card_verification_value,
             :order_id => self.confirmation_number,
        :description => "Conference reservation",
             :billing_address=>{
               :address1 => self.billing_address,
               :city => self.billing_city,
               :state => self.billing_state,
               :zip => self.billing_zip,
               :country => "US"}
             }
          
         }
          
     
                      
              gateway = AuthorizeNetGateway.new({:login => user, :password=>pass})
           
           
           response = gateway.purchase(self.total_cost_in_cents, creditcard, options)
 
           if response.success?
             self.status = 1
             self.confirmed_at = Time.now
             self.error_message = nil
           else
             self.status = 7
             self.error_message = response.message
           end
        else
          self.status = 7
 
         self.error_message = "Invalid credit card."
       end
 

  end
end
 
  

Run the unit test - it should pass without issue.

Now, you just need to make your controller take in the fields from a form. That should be pretty simple. Set up your form fields like

  <% form_for "reservation", @reservation, :url=>{:action=>"process_order"} do |f| %>
     <p>Card number: <%= f.text_field "card_number" %></p>
     ... other fields
    <%=submit_tag "Check out" %>
  <% end %>
 
 def process_order
   # get  id from session - no passing ids around in the url for me! 
   @reservation = Reservation.find(session[:reservation_id]
 
   @reservation.customer_ip = request.remote_ip
   @reservation.step = "checkout"   # for validation, remember?
        if @reservation.update_attributes(params[:reservation])
          if @reservation.process
            redirect_to :action=>"finished"
          else
            @reservation.errors.add_to_base @reservation.error_message
            render :action=>"checkout"    
          end
        else
          render :action=>"checkout"  
        end
 end

Step 6. Hooking it all up

You’re using a developer account, so you won’t actually see the transaction on the AuthorizeNet side of things unless you turn testing mode off. This part took me forever to figure out.

1. Log into the Merchant Interface
2. Select Account from the Main Menu
3. Click Test Mode
4. Press Turn OFF test

Now, re-run your unit test and then view the Reports page in the Merchant Interface. You will see a new transaction.

Testing without the Internet

If you’re not really into testing online, you can still get your test to pass. You can use 0 or 1 for the credit card number…. 0 means an invalid card, and 1 means a successful card. This comes in handy when doing a functional test later on.

Taking it Live

Change your details to use your permanent account’s transaction key and id. Then remove the :test mode stuff by running your app in production mode. Put your real gateway in test mode and then run through your app, using some fake credit cards from AuthorizeNet.

Mastercard: 5424000000000015
Visa: 4007000000027
Discover: 6011000000000012
American Express: 370000000000002

Once you’re absolutely sure that everything’s working, turn off the test mode on the production account, and you’re good to go!

Wrapping up

I hope that helps some of you. I spent a lot of time looking over the documentation and various examples out there. The developer account works a bit differently than the real account, so that was a major stumbling block.

Feedback is welcome, as always!

MySQL gem on OSX

Posted by Brian in Rails, Howto, snacks (June 1st, 2007)

UPDATED 12-05-2008: The instructions in this article were written for Tiger. With the release of Rails 2.21 this article’s been getting a lot more traffic and the instructions here needed to be updated. What you see here are instructions that should work for most installations of MySQL on the Mac.

When I got the Macbook Pro in March 2007, I immediately installed Ruby, Rails, Subversion, etc, using this tutorial from Hivelogic. http://hivelogic.com/narrative/articles/ruby-rails-mongrel-mysql-osx
They’ve done a good job of keeping it up to date, but one problem I noticed is that the MySQL gem instructions don’t work anymore. When the article was first written, it contained steps to remedy a minor installation problem. However, enough users reported that the problem no longer existed so it was removed.

Today, I encountered that problem again, and thought I’d share the solution. If you’re getting an error when you do

First, locate your installation of MySQL using

which mysql_config

You need three libraries:
include/mysql5
lib/mysql5
bin/mysql5_config

These should all be located within your mysql base folder.

For example, if MySQL is installed by Macports, the default location would be

/opt/local/lib/mysql5/

So you’d change the paths accordingly:

sudo gem install mysql -- --with-mysql-include=/opt/local/include/mysql5 --with-mysql-lib=/opt/local/lib/mysql5 --with-mysql-config=/opt/local/lib/mysql5/bin/mysql_config

This solution seems to get things rolling. Thanks much to crookshanks on IRC for the fix. Really, if you’re not participating in the IRC channels for Rails (#rubyonrails on irc.freenode.net) you’re missing out on some good discussions.

The rest of this article is most likely not relevant anymore.,/b>

You’ll need to do the following to fix it.

First, look at where the gem says it’s left its files.

  Gem files will remain installed in /usr/local/lib/ruby/gems/1.8/gems/mysql-2.7 for inspection.

So in my case, I’ll do

  cd /usr/local/lib/ruby/gems/1.8/gems/mysql-2.7

Then I’ll edit the file ‘mysql.c’ in that folder and add one line at the top of the file:

  #define ulong unsigned long

Then, I just run

  sudo make
  sudo make install

The original fix for this comes from
http://jlaine.net/2006/10/3/installing-ruby-mysql-driver-on-os-x but the instructions there are a little backwards. I hope this solution will help others having a similar problem.

Rails for Windows Shortcut available now!

Posted by Brian in News, Rails, Projects (May 14th, 2007)

Rails for Windows Shortcut

If you’re looking to get started with Ruby on Rails and you’re a Windows user, this book will walk you through setting up some of the tools you’ll need, as well as show you how connect to Microsoft SQL Server and set up Capistrano. Of course, this is targeted at people who are new to Ruby on Rails and come from the Windows platform.

Curt Hibbs wrote the first chapter, where he showcases how to use RadRails and InstantRails to create a quick and easy setup.

The book covers

  • InstantRails and RadRails
  • Installation with the One Click Ruby Installer
  • Installing RMagick
  • Working with MySQL and SQL Server
  • Setting up a simple Subversion repository on Windows
  • Using SQLite and scaffold_resource to rapidly prototype a simple application
  • Using Capistrano
    … and more.

So check it out, won’t you?

Why I’m using a Mac

Posted by Brian in News, Rails, Usability, web (May 9th, 2007)

I’m a Windows user. Anyone who reads this blog can pretty much figure that much out. I started this company in 1995, fixing computers and trying to put the “personal” in computer service.
Over the years, I’ve removed countless viruses, uninstalled lots of spyware, formatted hard drives, recovered files, and occasionally had to send a computer back to a customer as “unfixable” because
of some unknown hardware or software glitch. Windows is popular and well-known, and people who know it well can have some pretty good job security.

Shortly after I started this company, I shifted focus towards the Internet, developing web sites. I bucked the trend of my Mac-using
counterparts back then and did all of my design work on Windows. I even did video editing there. I embraced ASP, and when that got old, I started using PHP, but deployed on Windows.

When Ruby on Rails came along and I got involved in that community, I was determined more than ever to bring Rails to the Windows platform. I’m speaking about Rails on Windows at RailsConf 2007 this year, and I’ve just finished a book on
Rails for Windows users which will be published by O’Reilly.

But I started using a Mac for development this Spring and couldn’t be happier. Here’s why.

  1. Ruby runs faster.

    Ruby runs at least ten times faster on a Mac, which means my unit tests, Rake tasks, and anything else I do with Ruby take no time to run. On Windows, I pay at least a 15 second penalty just to start a task or a test. That basically means I either sit and wait for things to happen, or I just start neglecting my tests to save time. Not a good place to be if you’re trying to write good code.

  2. It’s Linux that runs Photoshop

    Many web-based languages like PHP, Python, and Ruby run extremely well on Linux. However, you can’t use industry-standard tools like Photoshop on Linux without a few glitches and a lot of work. I’ve done Photoshop on Wine and I am not impressed. On my Mac, I can use Flash, Photoshop, Illustrator, Dreamweaver, and anything else, because there are native supported ports of those programs for my system.

  3. I can run Windows apps too!

    I need Office, and I need to run IIS so I can support ASP, .Net, and other Microsoft-based technologies. My Macbook Pro has Windows XP installed as a second boot option, but I also run Windows XP on Parallels, a virtual machine that lets me use my Windows apps side-by-side with my Mac programs. Parallels can run pretty much any other operating system, so I also have Windows Server 2003 installed for testing.

    When I go to conferences, I only have to bring one computer.

  4. I can surf in peace

    No IE means no spyware. I typically use Firefox on Windows anyway, but the complete absense of IE on this machine makes me feel much safer.

  5. More time working, less time tweaking

    I don’t have to stop working in order to make something do what I want. The Mac’s OS gets out of your way and lets you work. It’s a little difficult to transistion from a PC to a Mac at first, but some of the built-in features are great. The Dashboard gives me quick access to GMail, my Wordpress blog, the weather, my Backpack account, and even a color-picker.

    When I got my Macbook, I was using it and actually being productive with it in only a few hours. I haven’t used a Mac since I was a kid.

  6. Textmate

    Windows users have e, but I have TextMate, and I don’t need anything else. TextMate is more than just a text-editor; it’s an IDE. I can integrate with Subversion, I can run Rails generator commands, I can run unit tests, and I can have Prototype and Script.aculo.us methods auto-complete while I type. I can validate HTML, preview in a browser, and then upload it back to my repository.

  7. I can use more advanced tools

    I do most of my deployment on shared hosts with Mongrel and mongrel_cluster. I can run these on my Mac without incident. I also use the excellent load-testing program httper, which does not run on Windows. There are countless other tools out there too.

    I also get to use QuickSilver, which means I can chain commands and navigate through my files and programs much faster.

  8. Apple has awesome support

    I used my new Macbook Pro for gaming one night just to try it out. My games ran flawlessly when I boot into Windows XP via Bootcamp. While I was playing, one of my keys came dislodged. I called up Apple, and within 10 minutes I had them sending me a new keyboard. That’s cool. Try getting that from another company. I’ve worked with tech support offices for the last 13 years, and I rarely get service like that. Good luck getting that from some of the larger PC manufacturers unless you have an enterprise support contract.

  9. I can zoom.

    OS X has a built-in zoom feature that I use to not only enlarge the screen when I need it, but also to inspect images for artifacts and imperfections.

So there you have it, a long-time Windows user who is using a Mac for software development. If you’re going to preach to others about “using the right tool for the job” then you owe it to yourself to see what a Mac can do for you.

If you have switched, I’d love to hear your story. If you’re thinking about getting one, let’s hear what’s holding you back from taking the plunge.

Updating Multiple Fields in Rails

Posted by Brian in Rails, snacks (April 23rd, 2007)

Just a quick one today…. I always have to look this one up.

Let’s say you have a guestbook and you want to approve multiple entries quickly. Rails has a built-in method for handling that, although it’s poorly documented.

Assuming your model “Entry” has an “approved” attribute that maps to a boolean field in the database, you might make a form like this:


<% form_tag :action=>"approve" do %>
  
  <% @entries.each do |@entry| %>
     <p>Posted at<%=@entry.created_at %> by
     <%=@entry.email %> </p>
 
     <p><%=h(@entry.body) %></p>
     <p>Approved? <%=check_box "@entry[]", "approved" %></p>
  <% end %>
  
  <%= submit_tag "Moderate Entries" %>
<% end %>

The key here is that you’re iterating over the items in the collection and using an instance variable to hold each one (@entry). Normally, a check_box helper looks like this:


   <%=check_box "entry", "approved" %>
 

If you use the check_box helper with an array as the first parameter, you can create an array of entries that can all be sent to the back-end.


  <%=check_box "entry[]", "approved" %>

Rails puts the primary key of the entry inside of the square-brackets, thus causing them to group nicely.

Your params hash will look like this:


{
"commit"=>"Moderate Selected Entries",
"action"=>"moderate",
  "entry"=>{
     "1"=>{"approved"=>"1"},
     "2"=>{"approved"=>"1"}
  },
  "controller"=>"guestbook"
}

That’s the hard part. The action that receives the POST request looks like this


  def moderate
     Entry.update(params[:entry].keys, params[:entry].values)
     flash[:notice] = "Successfully modified the approval flags for all records."
     redirect_to :action=>"index"
  end
 

Yeah, you read that right… no looping. The “update” class method on an ActiveRecord object can take either an ID or an array of IDs as the first parameter, and a hash of names and values or an array of hashes containing names and values for the second parameter. Since the form made the record ids as the keys in the hash, calling params[:entry].keys gives us the array of IDs we need for the first parameter. params[:entry].values gives us an array of the hashes we need for the second parameter.

Now, you can use this technique to do some simple mass-update pages if you needed to, but then it gets a little trickier.

I hope someone out there finds this useful.

Unit testing

Posted by Brian in Rails, snacks (April 3rd, 2007)

Rails developers typically do test-driven development, so they’re writing their unit tests before they write their business rules. For example, if I was to write a keyword search method, I’d write a unit test first.


 
  # Should find 2 because I have “red” in the test data in 2 records
  assert_equal(2, Document.find_by_keywords(“red”)  
 
  # should find 0 because that term isn’t in any of the records
  assert_equal(2, Document.find_by_keywords(“blue”)
 
  # should find 2 because the word “ninja” is found on one document
  # and ‘pirate’ is found in another.
  assert_equal(2, Document.find_by_keywords(“ninja pirate”)
 

The test that I wrote gives me a clear indication of the requirement I have to implement. When these tests (and more) all pass, I know that I have my search engine finished. I don’t need to continously try various examples manually to see if I am done. It takes a lot of the manual testing away, but it also gives me more confidence that my code does what I think it does.

The hardest part about testing is learning to do it first. It takes much longer to write tests after you already have a working application, and it feels pointless. (It’s really not, but it just feels that way when you’re doing it which can be really demotivating.)

Associations and caching

Posted by Brian in Rails, snacks (April 2nd, 2007)

Sometimes I just do dumb things when I write code. The way I look at it, every mistake I make is a chance to learn something new.

I’ve got a system with workshops, presenters, enrollments, and more. It’s a fairly complex system that has a lot of relationships. If you peek into my User model, you’ll see some things like this:


  class User < ActiveRecord::Base
    has_many :presenterships
    has_many :troubleshooterships
    has_many :enrollments  
    has_many :presentations, :through=>:presenterships, :source=>:workshop
    has_many :troubleshoots, :through=>:troubleshooterships, :source=>:workshop
    has_many :workshops, :through=>:enrollments
  end
 
  .…
  end

This post Turn finders into associations and get caching for free got me thinking about my code a bit so I decided to take a second look. When I did, I saw this method:


  #Returns all of the workshops for which this user is enrolled.
  def workshops_enrolled
    @workshops = Workshop.find :all, :include=>[:offering, :enrollments],
        :conditions=>["enrollments.user_id = ? and enrollments.withdrew = ?", self.id, false]
  end

I added this method because I wanted to make sure I only showed associations where the user did not withdraw. (I’m recording withdrawls from a workshop instead of removing the association between the user and the workshop.)

Darn it… that’s just not right. While that works, I lose the ability to cache, and it’s also exactly what an association is for. Refactored, it now looks like this:


    has_many :workshops_enrolled, :source=>:workshop, :include=>[:offering, :enrollments],
           :through => :enrollments, :conditions=>["enrollments.withdrew = ?", false]
 

Since it’s a has_many :through, it needs to have the :source option defined so Rails knows what the parent class is.

Fun stuff, this Rails.

Upgrading Ruby to 1.8.6 on OSX and Windows

Posted by Brian in Rails, snacks (March 24th, 2007)

Mac users

Assuming you’ve followed the Hivelogic article that walks you through a basic Ruby on Rails installation, you can use this code snippet to install Ruby 1.8.6.


cd /usr/local/src
curl -O  ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6.tar.gz
tar -zxvf ruby-1.8.6.tar.gz
cd ruby-1.8.6
./configure --prefix=/usr/local --enable-pthread --with-readline-dir=/usr/local
make
sudo make install
sudo make install-doc
cd ..
sudo gem install rails --include-dependencies

Windows users

Windows users only need to snag the latest version of Curt Hibbs’ One Click Ruby Installer which can be downloaded here.

The major advantage of moving to Ruby 1.8.6 and Rails 1.2.3 is that breakpointer works again.

Update: When I did this on my Macbook Pro, I had to recompile a few libraries like Ruby-DBI and Ruby-ODBC before I could connect to Microsoft SQL Server again.

Serializing ActiveRecord objects

Posted by Brian in Rails, snacks (March 19th, 2007)

One neat feature of Rails’ ActiveRecord objects is the #serialize method which will allow you to store an object in the database as YAML. This means, for example, you could have a User and a Profile. The Profile could be a hash containing a bunch of values that you want to manage, but that don’t necessarily need their own database table.


  class User < ActiveRecord::Base
  
    serialize :profile
  end
 
  u = User.find 1
  u.profile = {"url" => "http://www.rubyonrails.com", :nickname =>"Ninja master"}
  u.save
 
  u = User.find 1
  u.profile.class
  => Hash
 

The magic of the #serialize method takes the given object, serializes it to YAML, stores the YAML in the database, and then unserializes it when you retrieve the data.

This is all well and good, and I thought I would take advantage of this to help me easily cache some data. I have a system in which I have tasks, and a task belongs to a Service which contains the rate we charge for the task. Now, I really want to be able to store the service name and rate on the task when it’s assigned so that the task won’t be affected when I change my rates in the future.

“Aha!” I thought,”I can just use serialize and store the Service object right on the task!” I created a migration that added a service_data field to my database


./script/generate migration AddServiceDataToTasks


 
class AddServiceDataToTasks< ActiveRecord::Migration
  def self.up
    add_column :tasks, :service_data, :text
  end
 
  def self.down
    remove_column :tasks, :service_data
  end
end
 

I wrote a quick unit test which I knew would come in handy later.


   def test_saves_service_when_task_is_created
      @service = Service.find_by_name "Rails development"
      task = Task.create :name=>"Create user registration site", :esthours => 5, :service => @service
      t = Task.find task.id
      assert_not_nil t.service_data
      assert_kind_of Service, t.service_data
  
   end

Then I modified my Task model


  class Task < ActiveRecord::Base
    belongs_to :service
    serialize :service_data
 
    after_create  :sync_service_data!
  
    def sync_service_data!
       self.service_data = self.service
       self.save!
    end
  end

That seemed simple enough. However, when I tried it, I got a nasty surprise…


 
  t = Task.find 1
  t.service_data
  => nil
 

No matter what i tried, the service data always came back empty.

Running my unit test proved that something was definitely wrong, as I kept seeing “nil expected to not be nil”.

After searching and playing, I decided that #serialize was just not capable of serializing ActiveRecord objects. To get around this, I simply changed my code slightly. I knew that #serialize can handle Hashes so I stored just the attributes hash. Then I redefined #service_data “getter” method to create a new instance of Service from that hash.


  class Task < ActiveRecord::Base
    belongs_to :service
    serialize :service_data
 
    def sync_service_data!
       self.service_data = self.service.attributes
       self.save!
    end
 
    def service_data
      Service.new(self.attributes["service_data"]
    end
end

A quick run of the tests showed that I was now getting what I wanted.

Shortly after I discovered this solution, Jon Garvin offered a much cleaner solution…. don’t use Serialize. He found that Serialize does some strange magical things that often get in the way of our intended results. He proposed that I try

  class Task < ActiveRecord::Base
    belongs_to :service
 
    after_create  :sync_service_data!
  
    def sync_service_data!
       self.service_data = self.service
       self.save!
    end
 
    def service_data
     self[:service_data] ? Marshal.load(self[:service_data]) : nil
    end
 
    def service_data=(service)
      self[:service_data] = Marshal.dump(service)
    end
 
  end

This method simply creates a setter that manually marshals the data to the database column, and a getter that retrieves it again. This method works great, and I thank Jon for his quick solution!

RadRails dead?

Posted by Brian in News, Rails, Products (March 15th, 2007)

It looks like RadRails, the Eclipse-based IDE that has become quite popular, has shut down completely. The codebase is to be incorprated by Aptana for inclusion in their open-source web development IDE, but it’s not apparent when that will be. As of today, radrails.org is now offline meaning that getting a copy of the software is much harder.

Those missing the plugin repository should be using the one by Ben Curtis at www.agilewebdevelopment.com/plugins.

Don’t hesitate to use Eclipse for Rails if you need a good replacement, or use the article that started it all to build your own environment. My upcoming book will recommend that in place of RadRails and will also mention several other free and commercial Rails IDEs.

I look forward to Aptana working on this project, as I believe they have the ability to make RadRails work the way it should work. I never used RadRails, nor have I ever recommended it to any clients, friends, or coworkers, but I do wish the RadRails team the best of luck in their new endeavors.

« Previous PageNext Page »