Improve Rails Documentation 8

Posted by pratik
on Wednesday, March 19

This is almost a cross post from my email to rails-core mailing list :

Lately there had been many tiny doc patches at trac, which could easily escape our normal verification cycle. On top of that, we’re entering the whole new git-era of social development which eliminates the notion of “core” in a way.

Our aim is to make it really easy to get your doc patches in main repository. So to move forward, I’ve setup a git repository at GitHub : http://github.com/lifo/doc-rails/tree

I plan to give commit access to everyone who in the past have written a decent doc patch. Or anyone who is interested in writing one ( and can prove the quality of it by submitting at least one patch via whatever method ). And I’ll be syncing it with main Rails repository every week or so, after verifying all the changes.

So if you’re interested, you could email me directly or even easier is to catch me on IRC ( nick : lifo ). And once I add you to the doc-rails github project, you can commit directly to the repository without forking it ( and not bother about chasing anyone to pull your changes ).

Due to nature of this project/experiment, we’re gonna have to follow a strict set of guidelines for committers :

  • You are only allowed to change only docs and absolutely nothing else.
  • You should spell check your changes.
  • You shouldn’t add an entry to CHANGELOG. ( I will be adding changelog entries when syncing with main repo )
  • If you’re introducing a whole new style of doc writing, you should verify it with me first before you commit it.

Violation of any rule will result in lose of commit rights.

This is just a start. Moving forward, we could even do hackfest for writing docs and probably try to convince caboose doc fund holders to support this move in any way possible. But it all really depends on how things work out with doc-rails.

So anyone who has ever complained about quality of Rails API docs, now is your chance.

The project received a very positive response on the first day. We got whopping 8 patches !!

Now that you’re at it, you should follow Evan Weaver’s advise and throw some love all around ;-)

Single file Rails Application 30

Posted by pratik
on Saturday, February 16

UPDATE 1 : The inspiration for this article came from here ( it predates yo mama ). It has abso-fucking-lutely nothing to do with merb whatsoever. And “fuck you to your face” is NOT directed towards anything/anyone :)

Just for fun and profit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
require 'rubygems'
require 'thin'
require "action_controller"
require 'dispatcher'

# Rails pwned
ActionController::Base.session = { :session_key => "_myapp_session", :secret => "some secret phrase of at least 30 characters" }
ActionController::Routing.use_controllers! ['home']
ActionController::Dispatcher.unprepared = false
Dependencies.mechanism = :require

class ActionController::Dispatcher
  def prepare_application
  end
end

# And your routes
ActionController::Routing::Routes.draw do |map|
  map.root :controller => 'home'
  map.connect ':controller/:action/:id'
end

# Application code
class ::HomeController < ActionController::Base
  def index
    render :text => "fuck you to your face"
  end
  
  def hello
    render :text => params.inspect
  end
end

# Make Thin Happy
class LifoAdapter
  def call(env)
    rack_response = Rack::Response.new
    rack_request = Rack::Request.new(env)    
    cgi = Rack::Adapter::Rails::CGIWrapper.new(rack_request, rack_response)
    ActionController::Dispatcher.dispatch(cgi, ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, rack_response)    
    rack_response.finish
  end
end

# Run LifoAdapter
Thin::Server.start('0.0.0.0', 3000) do
  use Rack::CommonLogger
  run LifoAdapter.new
end

UPDATE 2

I just made a few more changes for funkification, which you can find at my github repository

With tinyrails, the “hello world” application looks like :

1
2
3
4
5
6
7
8
9
10
11
12
13
# thin -p 3000 -r mini.rb start

require 'tinyrails'

routes { root :controller => 'home' }

controller "home" do
  def index
    render :text => "Hello World"
  end
end

start

You can also use models/views with tinyrails, as demonstrated here

UPDATE 3 : Fabiano França changed the code to run it with webrick/mongrel. He also has a funky microrest framework. His pastie can be found here

A few tiny never/rarely seen before rails 2.0 features 2

Posted by pratik
on Saturday, December 15

Asset Caching

I had talked about this before in the past. Basically, rails allows you to merge your css and javascript files in a single file which is cachable by the browsers. Hence, there’ll only be just one request ( which would return 304 response from 2nd time onwards ) per page, which would result in faster loading time for your visitors.

I tend to put these lines in my layouts :

1
2
<%= javascript_include_tag :all, :cache => true %>
<%= stylesheet_link_tag :all, :cache => true %>

Migrations now accept command line attributes

So let’s say to add a string called “name” to my users table, now I’d just do :


script/generate migration AddNameToUser name:string

And to remove a column called “useless” from users table :


script/generate migration RemoveUselessFromUser useless:string

Please note that, when you generate a migration to remove columns, attribute type may seem trivial. But it is used to generate down migration, which would re-create those columns.

Better Exception Handling

In addition to what Ryan said, you can have inline exception handlers as well.

1
2
3
rescue_from ActiveRecord::RecordNotFound
  render :file => '/bad_record', :status => 404
end

Block can even take have an argument for exception object.

1
2
3
rescue_from  ActiveRecord::RecordInvalid do |exception|
  render :action => (exception.record.new_record? ? 'new' : 'edit')
end

The above snippet would greatly DRY up your controllers if you use save! and create! in your RESTful application.

Request Profiler

Rails now includes request profiler which uses ruby-prof and generates fancy pants graphs for you. You’ll need to supply an input file to use with request profiler, which would be in your usual integration test format. A sample input file for an application using restful_authentication plugin can look somewhat like :

1
2
lifo:freeonrails pratik$ cat perfscript 
post('/sessions', { :login => 'quentin', :password => 'test' })

And then roll it like :


lifo:freeonrails pratik$ script/performance/request perfscript

And the one liners

  • render partial collection now works with a collection of hash.

<%= render :partial => 'foo', :collection => [{ :name => 'world', :address => 'bar' }, { :name => 'food', :address => 'world' }] %>
  • ActiveRecord::Base#becomes to change record’s type

render :partial => @pet.becomes(Cat) # renders cats/cat instead of pets/pet
  • link_to(:back) for “Back” button using request.env[“HTTP_REFERER”] or ‘javascript:history.back()’ ( fallback )
  • error_messages_for accepts objects so that you can display error for local variable

<%= error_messages_for 'user', :object => @question.user  %>
  • Array#rand
1
2
3
[].rand       # => nil
['a'].rand    # => 'a'
[1,2,3].rand  # => 1 or 2 or 3
  • Hash#to_query

{ :user => {:name => "lifo"} }.to_query => "user%5Bname%5D=lifo"

This post is for covering smaller fixes/features which are not very easy to spot. For very exciting and rather major Rails 2.0 features, I’d recommend you check out :

Know your rails better 8

Posted by pratik
on Thursday, September 27

Burn/donate/throw away all your ruby/rails books

1
2
3
4
5
6
7
8
lifo:~/Rails pratik$ ruby ~/Rails/rails/railties/bin/rails foobar
lifo:~/Rails pratik$ cd foobar
lifo:~/Rails/foobar pratik$ svn co http://dev.rubyonrails.com/svn/rails/trunk vendor/rails
lifo:~/Rails/foobar pratik$ cd vendor/rails/
lifo:~/Rails/foobar/vendor/rails pratik$ find . | grep .rb$ | xargs perl -pi -e 's/^\s*?#.*?$//'
lifo:~/Rails/foobar/vendor/rails pratik$ cd ../../
lifo:~/Rails/foobar pratik$ rake doc:rails
lifo:~/Rails/foobar pratik$ open doc/api/index.html 

And you’ll know the difference in 15 days.

Have fun.

[WARNING] Don't trust strip_links()

Posted by pratik
on Wednesday, July 04

After coming across Ticket 8864 I tried to play around a bit more with link tags. And guess what, they’re more broken than I ever thought. And it’s not just rails, but firefox too.

For example consider the following html code
1
2
3
4
5
6
<html>
<head><title>Seriously, wtf !?</head>
<body>
  <href onMouseover="alert(document.location)">whatever
</body>
</html>

This actually work in Firefox. But it looks fine(blank) in Safari/IE ( No I don’t use Windows. I asked a friend to check it. )

Result ? Applications that depend on strip_links() for stripping link tags are open to XSS attacks.

I feel this is a critical issue in firefox and it’s not just related to rails. And in very special cases, it could be really risky.

I’ve submitted my modified version of strip_links() patch anyways.

Wait and watch.

[ANN] link_to_magic

Posted by pratik
on Monday, July 02

Sorry for the lame name. I was gonna name it link_to_sexy initially, but changed my mind at the last moment ;-)

This plugin is inspired from Josh Peek’s stringgable_shortcuts & Geoff Buesing’s patch

To install :

script/plugin install http://linktomagic.googlecode.com/svn/link_to_magic/

To use :

1.

<%= link_to @person %>

This is short for doing <%= link_to h(@person.name), @person %>. Here, a littile bit of ActiveRecord::Base.to_s magic is involved too. Check out this pastie to understand what/how it does this.

2.

<%= link_to_something @person %>

This is short for doing <%= link_to h(@person.something), @person %>.

Comments/suggestions welcome!

Look inside

Posted by pratik
on Sunday, July 01

“Don’t use the plugin you cannot write yourself. “

They are to save your time. Oh well, of course everyone is allowed an exception or two.

And I hate it when plugins do something like :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module Something::ActiveRecord
  module Base
    def self.included(base)
      base.class_eval do
        base.extend(ClassMethods)
      end
    end

    module ClassMethods
      def references_table_name(column_name, options)
        stuff
      end
    end
  end
end
ActiveRecord::Base.send(:include, Something::ActiveRecord::Base)

Instead of :

1
2
3
4
5
6
module Something::ActiveRecord::Base
  def references_table_name(column_name, options)
    stuff
  end
end
ActiveRecord::Base.send(:extend, Something::ActiveRecord::Base)

Makes me not wanna use it.

Let's start with wtf!?

Posted by pratik
on Saturday, June 30

UPDATE : Check Ticket 8818

Welcome to my new blog :) Now over to rails..

So you’ve been told about using cute shortcuts for enumerator like Post.find(:all).map(&:title) – you feel great using it, don’t you ?? And you laughed at those who didn’t understand how &:sym worked and continued to use .map ( |shit| shit.stupid } syntaxt! You were made feel geeky indirectly. I was there :-)

But those days are “over” and it’s time to go back home!

I’d let benchmark speak for me..

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
require 'benchmark'

class Symbol
  def to_proc
    Proc.new { |*args| args.shift.__send__(self, *args) }
  end
end

n = 10000

s = Struct.new :id
messages = []
n.times { messages << s.new(:id => rand(n)) }

Benchmark.bm do |x|  
  # Integer
  x.report { n.times { messages.map{|m| m.id} } }
  x.report { n.times { messages.map(&:id) } }
end

# $ ruby perform.rb 
#       user     system      total        real
#  33.280000   0.860000  34.140000 ( 34.912584)
# 191.940000   1.660000 193.600000 (197.168849)

Need I say anymore ? Wake up and smell the coffee.

Related ticket