June 16, 2010, 1:44 pm
Jonathan Briggs, who runs The Market Quarter wrote a few months back on getting up and going with our Shopify app for recommendations. He reported back today after analyzing the first few months of data:
What astounded me was how many of my customers (not just visitors) clicked on recommendations. Indeed the ExpressRex referrer is responsible for a full third (33%) of my revenue in the last quarter and has a 36% conversion rate.
You can read the full post in his blog.
June 7, 2010, 3:24 pm
From over at the Shopify blog:
Eric Houtkooper of www.PupLife.com helps customers find and discover other products they may want. He has increased his customers’ average order size by recommending products as they browse the store and go through checkout. He suggests you do the same…
More there.
June 5, 2010, 9:50 pm
So, the Ruby world has a nifty thinger for syncing up databases over the interwebs. It’s called Taps, from the superheroes over at Heroku. It’s great — you just run a little Sinatra-based server and then give the database URLs and it handles all of the plumbing.
But, you see, I was none-too-keen on having another long-running Ruby process, not to mention an open port with production database data lumbering around on it, so I thought I’d let you guys in on a little hack we produced internally to let you get all of the fun of taps, but without the taps server.
Basically it starts up the taps server on the remote server, tunnels the transfer over SSH, then sends a ctrl-c to the server to kill it’s done. It’s pull-only very intentionally — I want to push from a development database to a production database about like I want a hole in my head.
#!/usr/bin/env ruby
require 'rubygems'
require 'active_support/secure_random'
require 'net/ssh'
SSH_USER = '[sshuser]'
SSH_HOST = '[dbhost]'
LOCAL_DB = 'mysql://[dbuser]:[dbpass]@localhost/[dbname]'
REMOTE_DB = 'mysql://[dbuser]:[dbpass]@localhost/[dbname]'
TAPS_USER = ActiveSupport::SecureRandom.hex(16)
TAPS_PASS = ActiveSupport::SecureRandom.hex(16)
URL = "http://#{TAPS_USER}:#{TAPS_PASS}@localhost:5000"
Net::SSH.start(SSH_HOST, SSH_USER, :compression => true) do |ssh|
ssh.forward.local(5000, 'localhost', 5000)
ready = false
channel = ssh.open_channel do |c|
c.request_pty
c.on_data { |c, data| ready = true if data =~ /port=5000/ }
c.exec("taps server #{REMOTE_DB} #{TAPS_USER} #{TAPS_PASS}")
end
finished = false
Thread.new do
sleep 0.1 until ready
system "taps pull #{LOCAL_DB} #{URL}"
finished = true
end
ssh.loop(0.1) do
channel.send_data(Net::SSH::Connection::Term::VINTR) if finished
!finished
end
end |
#!/usr/bin/env ruby
require 'rubygems'
require 'active_support/secure_random'
require 'net/ssh'
SSH_USER = '[sshuser]'
SSH_HOST = '[dbhost]'
LOCAL_DB = 'mysql://[dbuser]:[dbpass]@localhost/[dbname]'
REMOTE_DB = 'mysql://[dbuser]:[dbpass]@localhost/[dbname]'
TAPS_USER = ActiveSupport::SecureRandom.hex(16)
TAPS_PASS = ActiveSupport::SecureRandom.hex(16)
URL = "http://#{TAPS_USER}:#{TAPS_PASS}@localhost:5000"
Net::SSH.start(SSH_HOST, SSH_USER, :compression => true) do |ssh|
ssh.forward.local(5000, 'localhost', 5000)
ready = false
channel = ssh.open_channel do |c|
c.request_pty
c.on_data { |c, data| ready = true if data =~ /port=5000/ }
c.exec("taps server #{REMOTE_DB} #{TAPS_USER} #{TAPS_PASS}")
end
finished = false
Thread.new do
sleep 0.1 until ready
system "taps pull #{LOCAL_DB} #{URL}"
finished = true
end
ssh.loop(0.1) do
channel.send_data(Net::SSH::Connection::Term::VINTR) if finished
!finished
end
end
Substitute in the right values in the constants up at the top and you’ve got a nifty way to securely use taps without leaving a server running.