-
Using Paperclip with Passenger
Posted on March 4th, 2010 No commentsThis is mainly a note to myself. File upload with Paperclip works with script/server but not when running Passenger. I have been lazy in finding a solution, so I just switch between script/server and Passenger, but I finally can’t stand it.
It happens because /opt/local/bin/identify is not in the path for the www user which is used to run Apache on Leopard. The solution is just to make it so in environment.rb (Make sure the path is correct for both the local dev and live prod hosts):
Paperclip.options[:command_path] = "/opt/local/bin"
-
Rails Rumble 2009
Posted on August 25th, 2009 No commentsI participated in last year’s Rails Rumble and decided to do it again this year. Our app this year is MovieTwitvia, a fun twitter movie trivia app. I don’t really have any new thoughts than last year. However, Andrew Ng, one of our team members have written up a post about his thoughts.
-
PayPal Recurring Billing with ActiveMerchant in Ruby on Rails
Posted on February 20th, 2009 42 commentsActiveMerchant is great and PayPal is easy to use. A lot of us already have a PayPal account for EBay. It works great in auctions where you pay once. However, ActiveMerchant currently does not support PayPal recurring billing. One requirement of a recent project is to be able to charge for a monthly or yearly subscription plan with PayPal. Therefore, I did some googling and found that Jon Baker has already extended ActiveMerchant to add this functionality using PayPal’s Name-Value Pair (NVP) API. However, as Cody Fauser pointed out, the NVP API was taken out from ActiveMerchant, so I had to implement that with PayPal’s SOAP API.
First, download this file and put it in vendor/plugins/active_merchant/lib/active_merchant/billing/gateways/.Use the GitHub from now because maintaining a separate file download is too troublesome. Alternatively, there’s a fork on GitHub at http://github.com/rayvinly/active_merchant/.In your controller, after a user selects one of your subscription plan, the form goes to the checkout action:
def checkout response = gateway.setup_agreement(:description => description, :return_url => return_url, :cancel_return_url => cancel_return_url) redirect_to gateway.redirect_url_for(response.token) end
This redirects the user to PayPal so he can login and read the description you provided. After he confirms, he is redirected back to your application’s return_url, which I set it to be the complete action below. If he cancels, he is redirected back to the cancel_return_url. You can set cancel_return_url to be the plan selection page where he can choose a different plan.
If he confirms, here’s the complete action:
def complete token = params[:token] response = gateway.create_profile(token, :description => description, :start_date => start_date, :frequency => frequency_in_months, :amount => amount_in_dollars, :auto_bill_outstanding => true) # Save this profile_id in your transactions table. This is used to cancel/modify the plan in the future. profile_id = response.params["profile_id"] if response.success? flash[:notice] = "Your PayPal account was successfully set up for the <strong>#{description}</strong> payment plan." redirect_to login_path else flash.now[:notice] = "There was a problem setting up your PayPal account for the <strong>#{description}</strong> payment plan" render cancel_url end end
I default the frequency to be in months and turn on auto_bill_outstanding because that is what I need, but you can look at the file you downloaded and the PayPal documentation to see what other options are available. In particular, read these two PDFs:
If the user wants to cancel the payment plan, a cancel action would look like:
def cancel response = gateway.cancel_profile(paypal_profile_id, :note => 'Payment plan was canceled by user') flash[:notice] = 'You have successfully canceled your membership' end
paypal_profile_id is the profile_id you saved in the complete action from above. Keeping this profile_id is very handy.
That’s it. Enjoy making money!
UPDATE 2009-02-04
I updated the extension to include a credit_card hash. You will probably capture the credit card details submitted by the user in a form as in params[:credit_card], but I will just create a hash to show as an example. To make recurring payment with a credit card, just pass nil for the token (this is required, because PayPal would use the token in preference to the credit card). Pass the credit_card hash as follows:
credit_card = Hash.new credit_card[:type] = 'Visa' credit_card[:number] = '1234567812345678' credit_card[:exp_month] = '07' credit_card[:exp_year] = '2016' credit_card[:cvv2] = '123' credit_card[:card_owner] = 'John Doe' response = gateway.create_profile(nil, :credit_card => credit_card, :description => description, :start_date => start_date, :frequency => frequency, :amount => amount, :auto_bill_outstanding => true)
However, I got the famous DPRP is disabled for this merchant error message when I tested it. I did a little googling but I haven’t found the cause. There may just be something that you have to turn on in your PayPal developer account. I also read that it works for newer accounts only. But since I don’t have a need for this, I didn’t look further. If you guys know, please let me know. I will try to update the extension as soon as possible to make it work with a credit card.
-
Sanitize your output in Ruby on Rails
Posted on October 30th, 2008 1 commentWe all know about the holy h() method that escapes your output when you do <%=h blah %>. But how many of us can claim we remember to use it where it’s appropriate during development 100% of the time? Can you swear you’ve never missed one? Moreover, it’s such a mental distraction to think logic and h() at the same time. And when you take over a Rails project in the middle, how can you ensure the previous developers use h()?
Here’s the rescue.
I don’t think I need to explain more. Just use it and you will find all those places where you should sanitize your output with h(), sanitize(), and untaint(), …etc.
-
RailsRumble 2008
Posted on October 19th, 2008 9 commentsWe just finished the Lyricist application for RailsRumble 2008 with 3 other Intridea folks. Here are some observations:
- Keep the idea small and achievable – There are only 48 hours, so you can’t build the next Google. And there’s pressure. Try to keep your idea small and make sure you can accomplish it. You have to deploy a finished product in order to have any chance of winning. So stop day dreaming about cool extra features because you won’t get that implemented.
- Prior planning is the key – We barely had any because we had decided on the idea the day before the rumble began. When the competition started, people don’t know who’s doing what and it was kinda a mess. Fortunately we had a campfire room where all conversation happen, so we can kind of iron out the issues. However, better preparation and team cohesiveness would have helped a great deal in communication.
- Deploy early – I’ve seen too many deployment problems came up before, so I took the initiative to make sure we could deploy as soon as the competition began. It helped tremendously because we never had to worry about if we could deploy before time expired. While you are fixing last minute bugs and the pressure, it would have been tough to set up a server and deploy flawlessly.
- A lot of scaffolding – I took full advantage of Rails scaffolding. There’s just no time to reinvent the wheels when all the restful model and controller methods are already available with just one command. You use plugins and gems for the same reason, right? So, don’t be stupid.
- Conflicts – The bigger your team, the more conflicts there would be when people check in and out. We were writing a new application, so people were editing the same files. Now, if you organize and assign work to people as in a regular project, conflicts don’t usually happen and even if they do occur, it is trivial to resolve. However, when you are rumbling, you will step on one another’s toes. I can guarantee you that.
- Forget about writing tests – Look, I am in support of agile and test-driven development, with one exception. That is, you are not participating in RailsRumble. There’s just no time for it. If you are a good enough programmer, you can build a small application with no tests. If you can’t, I don’t want to work with you. Writing tests for a new application starting from scratch in just 48 hours is simple not feasible. No bargain!
- No ticketing system like Unfuddle and Lighthouse – One team member had tried to use Unfuddle to create tickets to get ourselves more organized. While it was a sincere attempt, it simply didn’t work. There’s no time to accept a ticket, create a new ticket, … We pretty much abandoned it soon after we started.
- Nice to have a designer: – It is very nice if you have a designer on you team because it’s hard to wear two hats in 48 hours. Design work can draw your focus away from development.
Now that I’ve given you my insights for next year’s RailsRumble. As a token of appreciation, please vote for us!
UPDATE 2008/10/20
One more thought on RailsRumble the day after:
Numerous projects that I worked with before never deploy quickly, let alone in 48 hours. I think it’s refreshing and rewarding to have something built and deployed so quickly. It is true that we have to cut many features in order to deploy a first version, but lesser is better than never. I think many other projects can try to deploy early and often and just go through more iterations and get feedbacks from users and customers. The whole application doesn’t need to be finished. Even if you only have login and logout, you can still deploy. Add the next feature, deploy again. That way, you aren’t keeping the features to yourself. You can get feedback from users to see what improvements they are looking for and may even lead you to implement the real features that they truly want.
-
Capistrano Deployment Recipes
Posted on August 4th, 2008 1 commentDealistic was first deployed to Slicehost when we were testing it on staging. However, I only got the 256 slice and low memory is a big problem for Ruby and Mongrel. We’ve moved to Amazon EC2 when we launched. It is running rock solid and we don’t run out of memory again, at least for now
As a result of all these, I wrote two Capistrano recipes for deployment, for both Slicehost and EC2. We also use GitHub for version control. I think these deployment recipes may be helpful to others. So here they are:
We wrote some custom Capistrano tasks to copy over configuration files, symlink plugins, start/stop BackgrounDRb, and a custom maintenance page. But these things are optional. It should be simple to add/remove things as you see fit.
-
Dealistic is launched
Posted on July 29th, 2008 No comments
Andrew and I have been working on a new site Dealistic after our work at OnMyList.
We’ve also put up a screencast to show off our features (HUGE thanks to Sherry)
It lets you find deals by specifying a list of tags and it can notify you by email, RSS feed, and/or SMS when new deals appear that match your tags.
We made the site because we often need to find deals on things we want to buy but we spend way too much time looking for irrelevant deals on a lot of different sites. With Dealistic, what you get is what you want.
Never miss a deal because you don’t have time to find it! Just add a tag at Dealistic and we will let you know when a deal that you are looking for appears.
We also have a feedback tool that we hope you can give us suggestions to do better.
-
Ruby Performance Benchmarking
Posted on July 9th, 2008 No commentsCourtesy of igvita.com
require 'benchmark' n = 1000000 Benchmark.bm do |x| x.report('copy') { n.times do ; h = {}; h = h.merge({1 => 2}); end } x.report('no copy') { n.times do ; h = {}; h.merge!({1 => 2}); end } x.report('map(&:id)') do n.times do |i| h = {} h.map(&:object_id) end end x.report('map { |i| i.id }') do n.times do |i| h = {} h.map { |e| e.object_id } end end end
In Rails script/console or Ruby 1.9:
>> load '/Users/rlaw/Desktop/bm.rb' user system total real copy 4.000000 0.020000 4.020000 ( 4.081549) no copy 2.780000 0.010000 2.790000 ( 2.818923) map(&:id) 10.880000 0.040000 10.920000 ( 11.094024) map { |i| i.id } 2.060000 0.020000 2.080000 ( 2.178544) => []
-
Deploying your Rails applications with Phusion Passenger
Posted on June 11th, 2008 No commentsThere have been several methods to deploy an Ruby on Rails application. Until recently, the most popular is to run Apache and proxy balance to multiple Mongrel instances that are running simultaneously.
Passenger, developed by Phusion, is the new kid entering the Rails deployment market. We have been using the Apache PHP module for years and deploying a PHP applications is a snap. This has not been possible with Rails until Passenger. It is so easy too! You can still use Capistrano to automate deployment. I will show you how I get it to work on Ubuntu.
sudo gem install passenger passenger-install-apache2-module
Update: Phusion just released Passenger 2.0 RC 1. You can download this version and do
gem install passenger-1.9.0.geminstead. But I had an error compiling it on Mac OS X Leopard. hongli pointed me to use the version from GitHub that has the fix and it works like a charm. Thanks Phusion guys.To get it from GitHub:
git clone git://github.com/FooBarWidget/passenger.git
I create a separate
/etc/apache2/mods-available/passenger.loadand it contains the following:For 1.0.5:
LoadModule passenger_module /usr/local/lib/ruby/gems/1.8/gems/passenger-1.0.5/ext/apache2/mod_passenger.so RailsSpawnServer /usr/local/lib/ruby/gems/1.8/gems/passenger-1.0.5/bin/passenger-spawn-server RailsRuby /usr/local/bin/ruby
For the GitHub version (Of course the path will look different depending on where your git clone is):
LoadModule passenger_module /home/rlaw/downloads/passenger/ext/apache2/mod_passenger.so PassengerRoot /home/rlaw/downloads/passenger PassengerRuby /usr/local/bin/rubyI then tell Apache to load the Passenger module:
a2enmod passenger
Now, I create a virtual host configuration for one of my Rails app in
/etc/apache2/sites-available/dealistic:<VirtualHost *:80> ServerAdmin webmaster@dealistic.com ServerName dealistic.com DocumentRoot /home/deploy/apps/dealistic/current/public <Directory /home/deploy/apps/dealistic/current/public> Options FollowSymLinks AllowOverride None Order allow,deny Allow from all </Directory> LogLevel warn ErrorLog /var/log/apache2/dealistic/error.log CustomLog /var/log/apache2/dealistic/access.log combined </VirtualHost>
I then restart Apache:
sudo /etc/init.d/apache2 reload
When you need to restart your application because you have changed some code that Rails does not reload in production, just do:
touch /home/deploy/apps/dealistic/current/tmp/restart.txt
I have not tried their Ruby Enterprise Edition yet. They claim substantial memory and speed improvement at RailsConf 2008, so it will be interesting to see.
-
Back from RailsConf 2008
Posted on June 4th, 2008 No commentsPhotos posted to my flickr.



Recent Comments