Using Rack middleware to parse JSON

In attempting to AJAX-ize the site, I had the desire to handle JSON as if it were form post data. Queue a Rack middleware solution. rack-contrib contains a bunch of common middleware extensions, one being the horribly named PostBodyContentTypeParser. To get this working I added:

1
require 'rack/contrib'

with all of the rest of the required files.

Added:

1
use Rack::PostBodyContentTypeParser

to my application class

And went about over testing it like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def test_json_creates_params_hash
  params_hash={"user"=>{"username"=>"testuser","email"=>"test@test.com","password"=>"pass1","password_confirmation"=>"pass1"}}
  post '/test_json', params_hash
  assert !last_request.params.blank?
  assert_equal params_hash, last_request.params
  assert last_response.ok?
  json_string="{\"user\":{\"password_confirmation\":\"pass1\",\"username\":\"testuser\",\"password\":\"pass1\",\"email\":\"test@test.com\"}}"
  post '/test_json', JSON(json_string)
  assert !last_request.params.blank?
  assert_equal params_hash, last_request.params
  assert last_response.ok?
  post '/test_json', json_string, "CONTENT_TYPE"=>"application/json"
  assert_equal last_request.env["CONTENT_TYPE"], "application/json"
  assert !last_request.params.blank?
  assert_equal params_hash, last_request.params
  assert last_response.ok?
end
Posted: March 30th, 2010 | Author: jay | Filed under: Code | Tags: , , , , , , , | No Comments »

Rack::Test and request / response objects

Rack::Test uses last_response and last_request objects instead of Rack’s typical request and response objects. This is probably normally fine, but when you are testing functionality that requires accessing the Rack’s normal objects, they aren’t there. I found (in the comments section of this post) that you can fix this by overriding them in your test_helper.rb:

1
2
3
4
5
6
7
8
9
10
11
12
module Test::Unit
  class TestCase
    include Rack::Test::Methods
    ...
 
    def request(*args)
      args.empty? ? last_request : rack_test_session.request(*args)
    end
 
    ...
  end
end
Posted: March 26th, 2010 | Author: jay | Filed under: Code | Tags: , , , , , , , , , | No Comments »

Including common routines in test_helper.rb

I should have done this earlier. To do a number of tests, I have to repeat the same actions like create a user, log a user in, etc. I was putting these actions at the top of each test file, but have wised up and moved them to the test_helper.rb file. Here’s how that looks now:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
module Test::Unit
  class TestCase
    ...
 
    def create_user(user_hash={})
      post '/user/signup', {:user=>{:username=>"testuser",:email=>"test@test.com",:password=>"pass1",:password_confirmation=>"pass1"}.merge(user_hash)}
    end
 
    def login(user_hash={})
      post "/user/login", :user=>{:username_or_email=>'testuser',:password=>'pass1'}.merge(user_hash)
    end
 
  end
end
Posted: March 24th, 2010 | Author: jay | Filed under: Code | Tags: , , , , | 1 Comment »

AWS S3 using AWS/S3 Ruby gem

working on storing files to Amazon’s S3 web service. Here’s what I’ve come up with so far:

1
2
3
4
5
6
7
8
9
10
11
12
require 'aws/s3'
def aws_connect
  @aws_connect ||= AWS::S3::Base.establish_connection!(
    :access_key_id=>AWS_KEY,
    :secret_access_key=>AWS_SECRET
  )
end
 
def aws_upload(file,bucket=AWS_BUCKET)
  aws_connect
  AWS::S3::S3Object.store(file,open(file),bucket)
end

then a:

1
aws_upload('test.txt')

Will upload the the file to the Amazon bucket. Pretty simple.

Posted: March 22nd, 2010 | Author: jay | Filed under: Code | Tags: , , , , , , , , | No Comments »

OAuth summarized

Application Scope

1
2
# create the consumer...
consumer ||= OAuth::Consumer.new(KEY, SECRET, {:site => SITE, :authorize_path => PATH })

Session Scope

1
2
3
4
5
# create the request token...
rt=consumer.get_request_token({ :oauth_callback => OAUTH_CALLBACK_URL })
# save the request token and secret in the session...
session[:r_token]=rt.token
session[:r_secret]=rt.secret

User Scope (Model)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# use session values to create the request token...
rt=OAuth::RequestToken.new(consumer, session[:r_token], session[:r_secret])
# grab the user data from the OAuth provider...
access_token=rt.get_access_token({:oauth_verifier=>params[:oauth_verifier]})
oauth_user_json=access_token.get(VERIFY_PATH).body
oauth_user=JSON.parse(oauth_user_json)
# create or find the the user (using twitter.com for the email address - could use some work)... 
u=TwitterUser.first_or_create(:email=>"#{oauth_user['screen_name']}@twitter.com")
u.username=oauth_user['screen_name']
u.save!
u.oauth_tokens.all.destroy
u.oauth_tokens.new(:user_access_token=>access_token.to_yaml)
u.save!
# set the session user for future use...
session[:user]=u.id
...
# and when you need access to the OAuth provider again, use the access_token stored in the User model
u=User.first(:id=>session[:user])
access_token=YAML::load(u.oauth_tokens.first.user_access_token)
verify=access_token.get(OAUTH_PROVIDERS["https://twitter.com"][:verify_path]).body
Posted: March 17th, 2010 | Author: jay | Filed under: Code | Tags: , , , , , , , , , | No Comments »

Haml and Google SMTP for email

I first thought that I would have to use ERB to render non-HTML-like templates. Not true. Haml let you do a :plain filter which is pretty much the same as using ERB templates.

Here’s a simple example haml template for email:

1
2
3
4
5
6
:plain
  Welcome #{@user.username} to Fund-A-Stache! 
 
  click the following link to activate your account:
 
  #{activation_link(@user)}

I’m also using Google SMTP for email. That way I can send email from my home (which blocks SMTP traffic). This may change, but just so I can remember why I’m doing this, here’s the Pony call:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Pony.mail(
  :to=>@user.email, 
  :from=>'user@example.org', 
  :subject=>'Welcome', 
  :body=>(haml :registration_email, :layout=>false),
  :content_type=>'text/html',
  :via=>:smtp,
  :smtp=>{
    :host=>'smtp.gmail.com',
    :port=>'587',
    :tls=>true,
    :user=>'user@example.org',
    :password=>'secret',
    :auth=>:plain, # :plain, :login, :cram_md5, no auth by default
    :domain=>"example.org" # the HELO domain provided by the client to the server
  }
)
Posted: March 13th, 2010 | Author: jay | Filed under: Code | Tags: , , , , , , | No Comments »

Taking a pass on URLs that aren’t supposed to exist (in Sinatra)

This is simple, but I’m dumping it here anyway… I’d like to use the Twitter model of account access: http://example.com/USERNAME

So, if the user exists, if should display that user’s page. If the user doesn’t exist (or the user is deactivated) then this route will pass, which in this case, passes to the 404 error page. Here’s how I’m dealing with that in my routes:

1
2
3
4
5
    get '/:username' do
      @user=User.first(:username=>params[:username],:activated=>true)
      pass unless @user
      haml :user_page
    end

Note:This should be low on the chain of routes so that users with names or actual routes can’t be rendered as user pages. Example, a user with a username of “login” should not interfere with the application function of “login”. I might look further into protecting this beyond it’s position in the URL parsing chain.

Posted: March 13th, 2010 | Author: jay | Filed under: Code | Tags: , , , , , | No Comments »

Setting a domain name (env['HTTP_HOST']) to use in Rack::Test

This may not be the best way to do this, but this is what I used at the top of my test file so that a helper method has a value for Rack’s env['HTTP_HOST']:

1
2
3
4
5
6
7
class FundastacheUserTest < Test::Unit::TestCase
  ...
  def env
    last_request.env['HTTP_HOST']="example.org"
    last_request.env
  end
  ...

The test tests to see that using the activation link (that a user gets in an email) activates the user. It looks something like this:

1
2
3
4
5
6
7
8
9
10
11
12
  def test_using_activation_link_should_activate_account
    create_user
    user=User.first
    path=activation_link(user)
    path=~/http\:\/\/example.org(.*)/
    get $1
    follow_redirect!
    assert last_response.ok?
    assert last_response.body.include?('Account activated!')
    user=User.first
    assert user.activated
  end

and the helper method looks something like this:

1
2
3
4
5
6
7
8
9
10
 
module FundAStache
  module Helpers    
    ...
    def activation_link(user)
      "http://#{env['HTTP_HOST']}/user/activate/#{user.activation_token}"
    end
    ...
  end
end
Posted: March 13th, 2010 | Author: jay | Filed under: Code | Tags: , , , , , | No Comments »

Trying out Pony for email

Email is going to be used to activate an account, and I’m leaning towards using the Pony gem to simplify the creations and sending.

Here’s how simple Pony is:

1
Pony.mail(:to => 'test@example.com', :from=>'test@example.com', :subject=>'spam', :body=>(erb :registration_email))

and here’s how you can test it with the pony-test gem:

1
2
3
4
5
6
7
8
9
10
  def test_valid_new_user_signup_should_create_email
    count=all_email.count
    create_user
    assert_equal count+1, all_email.count
  end
 
  def test_signup_email_should_contain_activation_link
    create_user
    assert_match /http\:\/\//, current_email.body
  end

Don’t forget to nclude the Pony test helpers in your test class…

1
include Pony::TestHelpers
Posted: March 12th, 2010 | Author: jay | Filed under: Code | Tags: , , , , | No Comments »

Using haml for view templates, ERB for email templates…

and I’m not sure how I feel about this. Maybe I should use Mustache for tempting because this whole thing is for moustaches…

Posted: March 10th, 2010 | Author: jay | Filed under: Code | Tags: , , , , , | No Comments »