GoRuCo 2010 - James Golick - Scaling to Hundreds of Millions of Requests on Vimeo
Physical servers worked, EC2 did not.
The dangers of url_for in Rails applications
In a great post about named routes in Rails, path vs. url, Viget Labs ponders which variant is best used.<br />
<br />
Most often we use foo_path, which when used in Rails URL helpers will generate a relative path, where foo_url generates a full URL. In most cases the path makes most sense, but not always.
Exclude your staging site from Google with robots.txt and not shoot yourself in the foot
If you want to exclude your staging site from Google using robots.txt
without running the risk to forget deleting the file once you go live, name the file robots.exclude.txt
instead.
In your Apache Vhost config, rewrite requests for the staging server only:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^staging\.project\.com$
RewriteRule ^robots\.txt$ /robots.exclude.txt
Your robots.exclude.txt
looks like this:
# This file is returned for /robots.txt on staging servers
User-agent: *
Disallow: /
**Important ...
Debug Ruby code
This is an awesome gadget in your toolbox, even if your test coverage is great.
-
gem install ruby-debug
(Ruby 1.8) orgem install debugger
(Ruby 1.9) - Start your server with
script/server --debugger
- Set a breakpoint by invoking
debugger
anywhere in your code - Open your application in the browser and run the code path that crosses the breakpoint
- Once you reach the breakpoint, the page loading will seem to "hang".
- Switch to the shell you started the server with. That shell will be running an irb session where you can step thr...
Difference between respond_to/format and params[:format]
To return non-HTML responses (like XLS spreadsheets), we usually use the
respond_to do |format|
format.xls do
# send spreadsheet
end
end
This is often, but not always the same as checking for params[:format] == :xls
, so don't rely on this when e.g. one format checks for authorization and the other doesn't.
params[:format]
is only set when a user explicitly puts a .xls
at the end of the URL.
The format.xls
block also responds when the user's browser requests the application/excel
MIME type.
If Internet Explo...
Defining custom RSpec matchers
There are three ways to define your own RSpec matchers, with increasing complexibility and options:
1) Use RSpec::Matchers.define
RSpec::Matchers.define :be_a_multiple_of do |expected|
match do |actual|
actual % expected == 0
end
# optional
failure_message do |actual|
"expected that #{actual} would be a multiple of #{expected}"
end
# optional
failure_message_when_negated do |actual|
"expected that #{actual} would not be a multiple of #{expected}"
end
end
- This is automatically available i...
Setting expiry dates for images, JavaScript and CSS
When deploying Rails applications you might have noticed that JS and CSS are not cached by all browsers.
In order to force Apache to add expiry dates to its response, add the attached .htaccess
to the public directory. This will add a header such as Expires: Thu, 07 Oct 2010 07:21:45 GMT
to the httpd response.
Configuring Apache
Check that you have mod_expires
enabled. You need it for the attached .htaccess
to work:
sudo a2enmod expires
Configuring Nginx
You can add this:
Spec correct routing of custom URLs
When you roll custom URLs with hacks like routing-filter, you can put a spec like this into spec/routing/routing_spec.rb
:
How Rails and MySQL are handling time zones
When working with times and dates in Rails applications, you need to deal with the following problem:
- In Rails,
Time
objects have a time zone. You can get the zone name by doingtime_object.zone
. - This zone is considered when doing time calculations, e.g. 10 AM CEST minus 8 AM UTC is zero.
- A datetime in MySQL does not have a zone. It just stores the literal string "2010-05-01 12:00:00".
- That means that Rails must make assumptions about timestamps loaded from and written to MySQL.
Rails has two completely different modes ...
Change Paperclip secrets the hard way
So you screwed up and copied Paperclip secrets from one project to another. Here is a semi-automatic, painful way to migrate your existing attachment files to new locations.
You need to follow this step by step, do not just copy the whole thing into the console!
# 1. Get old paths by doing something like this on the console:
old_paths = ModelWithAttachment.all.collect { |m| [m.id, File.dirname(m.image.path(:original)).gsub(/original$/, '') ] if m.image.file? }.compact.uniq
# 2. Now change the Paperclip secret on the co...
Marry Capybara with SSL-enabled applications
Capybara does not play nice with sites that have some actions protected by SSL, some not. A popular way to implement this in Rails is using the ssl_requirement plugin by DHH, which redirects a requests from HTTP to HTTPS if the requested action requires SSL and vice versa.
Capybara follows the redirect, but seems to forget the changed protocol for the next request. The only hack-free workaround right now is to use URLs in lieu of paths everywhere (links, form actions).
For a hackful fi...
Faking and testing the network with WebMock
An alternative to this technique is using VCR. VCR allows you to record and replay real HTTP responses, saving you the effort to stub out request/response cycles in close details. If your tests do require close inspection of requests and responses, Webmock is still the way.
WebMock is an alternative to FakeWeb when testing code that uses the network. You sh...
Forward HTTP through an intermediary server (Local Port Forwarding)
This will tunnel HTTP requests to one given domain and port through an intermediary SSH server:
ssh -L 8080:targethost:80 tunnelhost
http://localhost:8080 will now connect you to http://targethost:80, tunnelling all data through tunnelhost
via SSH.
Note that the connection between tunnelhost and targethost will still be unencrypted in this example.
Submit a form with Prototype
For example, to send a form and populate a preview div with the response.
$('content_form').request({
parameters: { 'preview': "1" }, // overrides parameters
onComplete: function(transport){
$('previewContent').update(transport.responseText);
}
});
Rethinking Rails 3 Controllers and Routes | Free PeepCode Blog
The Rails router has been written and rewritten at least four times2, including a recent rewrite for the upcoming Rails 3. The syntax is now more concise.<br />
<br />
But never mind making it shorter! It’s time for a final rewrite: Let’s get rid of it altogether!
stefankroes's ancestry at master - GitHub
Ancestry is a gem/plugin that allows the records of a Ruby on Rails ActiveRecord model to be organised as a tree structure (or hierarchy). It uses a single, intuitively formatted database column, using a variation on the materialised path pattern. It exposes all the standard tree structure relations (ancestors, parent, root, children, siblings, descendants) and all of them can be fetched in a single sql query. Additional features are STI support, named_scopes, depth caching, depth constraints, easy migration from older plugins/gems, integrit...
Load all models into an Array
Dir.glob(File.join RAILS_ROOT, 'app', 'models', '*.rb').collect{ |path| path[/.+\/(.+).rb/,1] }.collect(&:camelize).collect(&:constantize)
Rails - Multi Language with Fast_Gettext
sudo gem install gettext --no-ri --no-rdoc
sudo gem install fast_gettext --no-ri --no-rdoc
-
script/plugin install git://github.com/grosser/gettext_i18n_rails.git
(didn't work as gem) - environment.rb: see code example at the bottom
-
if this is your first translation:
cp locale/app.pot locale/de/app.po
for every locale you want to use - use method "_" like
_('text')
in your rails code - run
rake gettext:find
to let GetText find all translations used - translate messages in 'locale/de/app.po' (leave msgstr blank and ms...
Automatically build sprites with Lemonade
How it works
See the lemonade descriptions.
Unfortunately, the gem has a few problems:
- it does not work with Sass2
- it always generates all sprites when the sass file changes, which is too slow for big projects
- it expects a folder structure quite different to our usual
All these problems are solved for us, in our own lemonade fork. This fork has since been merged to the original gem, maybe we can use t...
Freeze (vendor, unpack) a single Ruby gem with and without Bundler
When you need to patch an existing gem, one way is to "vendor" the gem by copying it into the vendor/gems
directory of your Rails project. You can then make any changes you require and Rails will use the vendored version of the gem after a server restart. Unfortunately you need to perform some additional steps to marry Rails and the copied gem. This notes describes what to do.
With Bundler
This is super-painful. If you just copy the gem to vendor/gems
, Rails will complain:
Unpacked gem foolib in vendor/gems has no s...
Clear a Solr index with acts_as_solr
ActsAsSolr::Post.execute(Solr::Request::Delete.new(:query => "#{Location.solr_configuration[:type_field]}:#{ModelClass}"))
ActsAsSolr::Post.execute(Solr::Request::Commit.new)
Fixing "A copy of Klass has been removed from the module tree but is still active"
This can happen during development when classes without automatic reloading are pointing to classes with automatic reloading. E.g. some class in lib
is calling Model.static_method
.
Workaround A
Stop referencing autoloaded classes from static files. If you can't, see workaround B and C.
Workaround B
Make sure the offending file (the one referencing the autoloaded class) is autoloaded, too. You may do this:
# config/application.rb
config.paths.add 'offending/file/parent/directory', eager_load: true
Workaroun...
Configuring Git with .gitconfig
Basic configuration
Please keep this config simple. It should be a starting point for new developers learning Git.
[user]
name = Your Name
email = your.name@domain.com
[branch]
sort = -committerdate
[color]
ui = auto
[color "branch"]
current = yellow reverse
local = yellow
remote = green
[color "diff"]
whitespace = white reverse
meta = blue reverse
frag = blue reverse
old = red
new = green
[color "status"]
added = green
changed = yellow
untracked = cyan
[interactive]
singlekey = true # Do not requir...
Slugs with FriendlyId
Gem to provide nice looking urls ("/blog/the-greatest-bug-i-never-fixed"). If you don't need anything too special (like i18n for the urls) it works as a drop-in-replacement. It basically overwrites #to_param
to return the slug, and .find
to search by the slug.
Make sure, everywhere you build paths, you use model_path(:id => model)
instead of model_path(:id => model.id)
. You also need to adapt all code using something like .find_by_id
. The regular .find
is fine.
See the github README for installation instructions.
Don't forget ...