Flowdock

Notes posted to Ruby on Rails

RSS feed
January 27, 2010
1 thank

Alternative hostname generation method

Instead of using a random number to generate the hostname for the single asset, I prefer using source.hash.modulo, so that a given file is always served from the same host. This makes the content more cacheable by browsers and proxies.

ActionController::Base.asset_host = Proc.new { |source|
  "http://assets#{ source.hash.modulo(9) }.example.com"
}

I didn’t benchmark how long it takes, but String#hash should be reasonably fast.

January 26, 2010 - (>= v2.3.2)
1 thank

is now a subclass of Hash that preserves order (or _is_ a Hash if running Ruby 1.9 or greater)

You might not realize it preserves order because it delegates inspect to its super-class, Hash, which doesn’t preserve order. But you will see that order is preserved if you iterate or use the keys or values methods:

>> names = ['Amy Irving', 'Jane Doe', 'John Doe', 'John Updike', 'Susan Anthony']
>> ordered = names.group_by { |name| name.split.first }
=> #<OrderedHash {"John"=>["John Doe", "John Updike"], "Amy"=>["Amy Irving"], "Susan"=>["Susan Anthony"], "Jane"=>["Jane Doe"]}>

>> ordered.keys
=> ["Amy", "Jane", "John", "Susan"]

>> ordered.each { |first, full| puts first; full.each { |name| puts "  "+name } }
Amy
  Amy Irving
Jane
  Jane Doe
John
  John Doe
  John Updike
Susan
  Susan Anthony
January 26, 2010 - (>= v2.3.2)
2 thanks

returns an ActiveSupport::OrderedHash

Returns an ActiveSupport::OrderedHash, which is a subclass of Hash that preserves order. If you’re running Ruby 1.9, it is simply an alias for Hash. Surprisingly, you might not realize that OrderedHash is preserving order since it delegates its inspect method to Hash. More at ActiveSupport::OrderedHash.

January 21, 2010
3 thanks

W3CDTF Format

Here is the formatted string for the W3CDTF datetime format (http://www.w3.org/TR/NOTE-datetime). It has a semicolon in the timezone part, therefore you cannot use ‘%z’:

Time::DATE_FORMATS[:w3cdtf] = lambda { |time| time.strftime("%Y-%m-%dT%H:%M:%S#{time.formatted_offset}") }
January 20, 2010
4 thanks

Using html text instead of default response

If you have a string containing html and want to assert_select against it, as the doc states you have to pass in an element (HTML::Node) as the first argument. You can do something like this:

doc = HTML::Document.new('<p><span>example</span></p>')
assert_select doc.root, 'span'
January 20, 2010
1 thank

Escape brackets in selector

If you need to escape brackets in a selector, this is the way to do it:

assert_select "input[type=hidden][name='user[role_ids][]']"
January 20, 2010
3 thanks
January 18, 2010
1 thank

Undeprecated version

The undeprecated version of this function is here: ActionView::Helpers::PrototypeHelper#link_to_remote

January 16, 2010 - (>= v2.2.1)
7 thanks

Pretty way to test for current environment

You can check your current Rails environment using nice methods such as:

Rails.env.development?
Rails.env.test?
Rails.env.production?
Rails.env.your_custom_environment?
January 15, 2010
2 thanks

Use this in controllers

Sometimes you’re gonna need this in controllers. Just put this in the controller:

include ActionView::Helpers::NumberHelper
January 14, 2010
0 thanks

:find takes more keys than written

The documentation says that the :find keywords “may include the :conditions, :joins, :include, :offset, :limit, and :readonly options”. Note that this does not mean that only those options are supported. :sort also works like it should, for example.

January 14, 2010
0 thanks

Will this method get rid of existing data?

Will this method get rid of existing data?

January 11, 2010 - (>= v2.2.1)
2 thanks

Default fallback

You can specifly :default option which is useful when the translation is not found. For example:

t(:this_translation_doesnt_exist, :default => 'Ooops!')
# => Ooops!

Or even any number of “fallbacks” - the first not nil is returned:

t(:missing, :default => [:missing_too, :existing, 'Sad panda'])
# => :existing translation

Good introduction to Rails I18n is http://guides.rubyonrails.org/i18n.html

January 11, 2010
1 thank
January 8, 2010
1 thank

Status Codes

Full detail: http://en.wikipedia.org/wiki/List_of_HTTP_status_codes

  • 100 - Continue

  • 101 - Switching Protocols

  • 200 - OK

  • 201 - Created

  • 202 - Accepted

  • 203 - Non-Authoritative Information

  • 204 - No Content

  • 205 - Reset Content

  • 206 - Partial Content

  • 300 - Multiple Choices

  • 301 - Moved Permanently

  • 302 - Found

  • 303 - See Other

  • 304 - Not Modified

  • 305 - Use Proxy

  • 306 - No Longer Used

  • 307 - Temporary Redirect

  • 400 - Bad Request

  • 401 - Not Authorised

  • 402 - Payment Required

  • 403 - Forbidden

  • 404 - Not Found

  • 405 - Method Not Allowed

  • 406 - Not Acceptable

  • 407 - Proxy Authentication Required

  • 408 - Request Timeout

  • 409 - Conflict

  • 410 - Gone

  • 411 - Length Required

  • 412 - Precondition Failed

  • 413 - Request Entity Too Large

  • 414 - Request URI Too Long

  • 415 - Unsupported Media Type

  • 416 - Requested Range Not Satisfiable

  • 417 - Expectation Failed

  • 500 - Internal Server Error

  • 501 - Not Implemented

  • 502 - Bad Gateway

  • 503 - Service Unavailable

  • 504 - Gateway Timeout

  • 505 - HTTP Version Not Supported

January 6, 2010
6 thanks

Doesn't return nil if the object you try from isn't nil.

Note that this doesn’t prevent a NoMethodError if you attempt to call a method that doesn’t exist on a valid object.

a = Article.new

a.try(:author) #=> #<Author ...>

nil.try(:doesnt_exist) #=> nil

a.try(:doesnt_exist) #=> NoMethodError: undefined method `doesnt_exist' for #<Article:0x106c7d5d8>

This is on Ruby 1.8.7 patchlevel 174

January 6, 2010
0 thanks

Alternative:

without using at

[:a, :b, :c].try(:[], 1)
December 28, 2009
2 thanks

Attribute names are Strings, not Symbols

Another possible gotcha – the returned hash keys are of type String, not Symbol:

user.attributes["login"] # => "joe"
user.attributes[:login] # => nil
December 23, 2009 - (<= v2.3.2)
0 thanks

Compare dates

You can check a date resides between two dates.

Date.today.between?(Date.yesterday, Date.tomorrow)

will return true

Date.yesterday.between?(Date.today, Date.tomorrow)

will return false

December 21, 2009
0 thanks

expire_page outside controller and sweepers

If you want to expire cached pages from scripts or console just use class-method expire_page. But don’t forget about difference between instance and class method. In class-method you pass page url, not a hash of action/controller:

ActionController::Base.expire_page your_page_url
December 21, 2009 - (>= v2.0.0)
0 thanks

Expire cache from console or whatever...

I know only one possible method:

ApplicationController.new.expire_fragment(:your_fragment)

December 18, 2009
4 thanks

Version Ranges

To specify a version range, use array syntax like this:

config.gem 'paperclip', :version => ['>= 2.3.1.1', '< 3.0']

The example will, of course, match any version 2.3.1.1 or newer up until (not including) 3.0 or later.

December 16, 2009
0 thanks

path

send_file always uses the absolute path /www/somewebsite/public/downloads/file

December 13, 2009
1 thank

yijisoo

create generates the object and saves. new only generates the object.

e.g.

o = Object.new(:foo => 'bar')
o.save

is the same as

o = Object.create(:foo => 'bar')
December 13, 2009
0 thanks

What's difference between create and new?

What’s difference between create and new?

December 3, 2009 - (>= v2.2.1)
1 thank

Capturing blocks after >2.2

After 2.2, you can omit the do …end block and simply use the &block variable directly:

concat(content_tag(:div, :class => "wrapped_content") do
  capture(&block)
end, block.binding)

becomes simply:

concat(content_tag(:div, capture(&block), :class => "wrapped_content"))
December 2, 2009
2 thanks

IE GOTCHA - multiple javascript_include_tags with cache => true

If you have multiple lines of javascript_include_tag ‘jsfile’, :cache => true, IE does not load them all (though it seems Firefox and Safari do). And the error won’t show up until you’re in production (since that’s only when caching kicks in.)

You should include them all on one line:

javascript_include_tag 'file1.js', 'file2.js', 'file3.js', :cache => 'myfiles'
November 30, 2009
2 thanks

Clearing out previous values from content_for

By default, content_for :thing appends whatever you put in your block to the previous value of :thing. In some cases, you’d like to clear out :thing rather than append to it.

I just posted a way to do this on my blog: http://stevechanin.blogspot.com/2009/11/clearing-out-content-in-contentfor.html

I add a new method set_content_for that works just like content_for, but clears out :thing first. It doesn’t touch how content_for works, so it shouldn’t cause any problems anywhere else in your app.

November 30, 2009
0 thanks

You can specify the format as well

You can also specify the format (in case you need to redirect a request coming in one format to another format):

redirect_to :action => 'show', :format => 'html'