Archive for December, 2009

Pratik lately is doing a great work refactoring ActiveRecord to make a full use of relations. Speaking in code language, this means that in Rails 3 you will be able to do:

  User.where(:name => "Jose").order("birthday")

And it will return a relation. The relation can be further manipulated and the query is only triggered when you call all, first, to_a or some Enumerator method.

Besides that, he’s also doing some crazy experiments, which will probably become a plugin later. While discussing with Pratik some ways to implement equality and inequality, I discovered a neat ruby trick. Open up an irb session and do:

MD7M9TSHSAJY
~2  #=> -3
~42 #=> -43

And this method is actually documented.

The nice thing though, is that you can define this method in other classes as well. In the querying scenario for example, we could add this behavior:

class Symbol
  def ~
    :"LOWER(#{self})"
  end
end

And now we could actually do:

User.where(~:email => "jose@plataformatec.com.br")
#=> SELECT * WHERE LOWER(email) = "jose@plataformatec.com.br"

Unary operators

Yehuda Katz later pointed to me that this can actually be done with any of the three unary operators in Ruby: +, – and ~.

So we could also do:

class String
  def +@
    upcase
  end
 
  def -@
    downcase
  end
end

And now:

+"jose" #=> "JOSE"
-"JOSE" #=> "jose"

You could even “go crazy” and append several unary operators:

+-+"jose" #=> "JOSE"

And you? Did you know such behavior in Ruby? Do you have any good use case for it?

A new I18n gem just got released and it comes with two new backends extensions: Fast and InterpolationCompiler.

First, what is a backend?

I18n.t, I18n.translate, I18n.l and I18n.localize methods are actually just wrappers to I18n.backend, which is actually who does all the heavy lifting. This means that you can change your backend to other stuff, as long as it respects the required API.

By default, I18n comes with the Simple backend, but others are available. For example, I18n has an ActiveRecord, which stores translations in the database. This is useful in cases someone needs to change translations through a web interface. To use it, you just need to do:

  I18n.backend = I18n::Backend::ActiveRecord

There are a couple other backends, like a backend which implements fallbacks, so if something cannot be found in a specified language, like german (:de), it can fallback to english (:en). You can check the whole list, but for this while, we are going to focus on the two new backends extensions.

Fast

Fast, means fast. And oh, boy, this one is fast. This extension flattens translations to speed up the look up. For example, the following hash { :a => { :b => { :c => :foo } } }, gets flattened to { :"a.b.c" => "foo" }, so instead of recursively looking into hashes, it looks just once. The obvious expense is that whenever you are storing translations, you need to flatten the translation hash, and it takes more time than usual.

In order to measure different backend implementations, I pushed some benchmark setup to the I18n repository. The current setup measures the storage time, the time it takes to translate a key (the depth of the key means how many nested hashes it takes), the time to translate a key falling back to the default key and the time translate a key (at depth 5) and interpolate. The results comparing the Simple backend without and with Fast extension are showed below:

Simple vs. Fast

In other words, a simple lookup using the Fast extension is 3 to 4 times faster than the Simple one. Besides, configuring your application to use it is very simple:

  I18n::Backend::Simple.send :include, I18n::Backend::Fast

Nice!

Interpolation compiler

The InterpolationCompiler is a backend extension which extracts all required interpolation keys from a string, leaving just the minimum required to runtime. Imagine the following string: "This is a custom blank message for {{model}}: {{attribute}}". This extension annotates the string so it knows that it needs to interpolate both model and attribute, and points exactly where the interpolation should happen. We can compare the Simple backend without and with the InterpolationCompiler below:

Simple vs. Interpol

The InterpolationCompiler just changes the time taken when we have interpolation keys, without affecting too much the other translations. You can add it to your app as easy as the Fast backend:

  I18n::Backend::Simple.send :include, I18n::Backend::InterpolationCompiler

Run, I18n, run!

But the best is still coming! Fast and InterpolationCompiler can actually be used together, to achieve unseen performance in I18n. The benchmark speaks for itself:

Simple vs. FastInterpol

While we speed up the performance in around four times in simple lookups, Fast and InterpolationCompiler improvements get combined whenever we need to use interpolation, becoming around six times faster!

As said previously, both extensions increase the time taken to store translations as side-effect. Such can be viewed below:

Store

The yaml hash used in for the benchmark, is relatively slow, but it shows how the time taken to store translations grows with such extensions. But remember, you are constantly storing translations only in development (before each request is processed). In production, the translations are stored at startup and that is it.

Using within Rails

You should be able to use such features today in Rails 2.3.5 and it will also be possible in Rails 3. You just need to install the I18n gem and configure it in your environment.

Why care?

All the times shown are in miliseconds. In other words, why care? If you are building a simple application, using just one language, those improvements likely won’t change anything. But in an application which relies on I18n, during a request/response lifecycle, I18n is invoked many times: error messages for models, flash messages, page titles, e-mail subjects, page content, date and time localization, pluralization rules and even in many of ActionView helpers. So in such cases, it’s worth to give such extensions a try.

Running benchmarks on your own

If you want to run benchmarks on your own, it’s quite simple. You just need to do:

git clone git://github.com/svenfuchs/i18n.git
cd i18n
ruby benchmark/run.rb

Credits

The possibility to have backends and such extensions is due to Sven Fuchs, which leads the I18n group quite well.

Many of the backends were added by I18n community, and the Fast and InterpolationCompiler were created by thedarkone.

Guys, I owe you a beer! ;)

Enjoy!

Inherited Resources always had a hate/love history with Rails Edge. Just after DHH posted about respond_with, it was already there in Inherited Resources. This initial implementation provided a nice test suite and several use cases for a improved Rails’ implementation, based in Responders, which encapsulates all the behavior in one class, and can be added, modified or updated.

After that, Inherited Resources was outdated and envy. It needed to be updated and it was: responders has been available in Inherited Resources for more than four months, and consequently in Rails 2.3.

Everything looked great until we started to develop a fresh Rails 3 application. The main purpose of this fresh application is to be a sample of Rails 3 features, including generators and responders. Based on that, it doesn’t make sense to use a tool like Inherited Resources, since it would abstract almost all controllers away and the application would no longer fit as an example.

So we were there, building an application based on scaffold, and as we saw duplicated code we started to realize Inherited Resources contains a lot of tools that could be used outside its context. And this is what is happening right now, two new gems are being launched: Responders and HasScope.

Responders

Responders is a repository of Rails 3 responders, mainly based on this post on Ruby on Rails weblog. And as a proof of concept, we wrote two Responders: FlashResponder and HttpCacheResponder.

FlashResponder uses I18n to automatically look up flash messages for you, even allowing you to set generic messages. In other words, your old create action:

1
2
3
4
5
  def create
    @post = Post.new(params[:post])
    flash[:notice] = "Post was successfully created" if @post.save
    respond_with(@post)
  end

Can now be written as:

1
2
3
4
5
  def create
    @post = Post.new(params[:post])
    @post.save
    respond_with(@post)
  end

Your locale just needs to have the following configuration:

  flash:
    actions:
      create:
        notice: "{resource_name} was successfully created"
      update:
        notice: "{resource_name} was successfully updated"
      destroy:
        notice: "{resource_name} was successfully destroyed"
        alert: "{resource_name} could not be destroyed"

If you want to change a message, let’s say, the success message when creating a post, there are several ways to achieve that. You can give :notice to respond_with or even update your I18n under the key: “flash.posts.create.notice”.

For us it came as a nice tool to provide I18n by default in our controllers and decouple messages from code.

The HttpCacheResponder automatically adds a Last-Modified header to API requests without any extra configuration. This allows clients to easily query the server if a resource changed and also replies with 304 (Not Modified) status.

As usual, the code for both implementations came from Inherited Resources. And since it contains a Rails 3.0 Responders shim, those responders can already be used in Inherited Resources and they are!

In other words, Inherited Resources code got simplified and such features can now be used by any Rails 3 application without a need to load all Inherited Resources stack. Besides, as more Responders appears, they can be added to Responders repository and be used in Inherited Resources easily.

HasScope

The other tool extracted from Inherited Resources is HasScope.

Let’s suppose that we have a ProjectsController and at some point you want to add some filters on the index action like showing just featured projects, selecting projects by methodology or even let the user choose how many projects he can see per page. The first thing to do? Add named scopes to your model:

1
2
3
4
5
class Project < ActiveRecord::Base
  named_scope :featured, :conditions => { :featured => true }
  named_scope :by_methodology, proc {|methodology| { :conditions => { :methodology => methodology } } }
  named_scope :limit, proc{|limit| :limit => limit.to_i }
end

The next step would be to add a lot of code in your controllers that check which named scopes you should call, based on the parameters sent right? Well, not anymore. Your controller can be as simple as:

1
2
3
4
5
6
7
8
9
class ProjectsController < ApplicationController
  has_scope :featured, :type => :boolean
  has_scope :by_methodology
  has_scope :limit, :default => 10, :only => :index
 
  def index
    @projects = apply_scopes(Project).all
  end
end

Then for each request:

/projects
#=> acts like a normal request, but returning only 10 projects

/projects?featured=true
#=> calls the featured named scope and bring 10 featured projects

/projects?featured=true&by_methodology=agile&limit=20
#=> brings 20 featured projects with methodology agile

If you configure your routes, you could even have pretty urls with it:

/projects/agile/featured
#=> brings 10 featured projects with methodology agile

All in all, you can now call has_scope in any controller and in case you are using it inside an Inherited Resources controller, everything gets handled automatically, so enjoy!

So Inherited Resources finally reaches 1.0

After this refactoring and a complete clean up of Inherited Resources issues, it finally reaches 1.0! When you install it, responders and has_scope gems should be installed as well. Responders is always loaded, since it’s a dependency, but if you want to use has_scope you will need to add it to your environment as well.

After you install the gem, the upgrade process in any application can be handled in three steps:

1) Add config.gem “has_scope” to your “config/environment.rb”.

2) Configure which flash keys are used by your application. At first, Inherited Resources used :notice and :error. Then we changed to :success and :failure, but just after this DHH established :notice and :alert as Rails default.

From 1.0 on, Inherited Resources will be using :notice and :alert, but it allows you to change it:

  InheritedResources.flash_keys = [ :success, :failure ]

3) Finally, you may need to do a final change in your application due to how responders work. The default way a resource tells a responder if it was created/updated/destroyed with success or not, is through errors. If the errors are empty, it assumes it succeeded, otherwise it failed.

This will be true in all create/update scenarios, but not in destroy. In other words, if you have a code with similar structure in your model (please don’t!):

  def before_destroy
    if some_condition_is_not_valid?
      false
    else
      true
    end
  end

It won’t work anymore. You need to add an error to your model to really invalidate it:

  def before_destroy
    if some_condition_is_not_valid?
      errors.add(fault_attribute, :invalid)
      false
    else
      true
    end
  end

Now you should be ready to go. Enjoy!

We have been working on an application that allows administrators to create accounts for their users. Each account will be accessible under a subdomain, so we needed to setup a subdomain environment inside our application, and also in our development machine. In addition, we must be able to let the users signed in among several subdomains, as a user can access other accounts when allowed.

After some research we decided to go with the subdomain-fu gem, which is great to give your application the ability of handling subdomains. Another great resource we have used is Ryan Bates’ screencast about the subject. But they did not solve our problem completely, so here we are going to document a few steps to help you get up and running easily with subdomains and sessions.

Setup a development environment

As we need to test all the subdomain stuff in our application while developing it, we are going to need some extra setup for our development environment. However, our local machine knows nothing about subdomains, so how do we do that? We need to tell our machine which subdomains we will be using, manually. You can do this by editing your hosts file, located at /etc/hosts, and configuring the subdomains you are goint to need:

127.0.0.1     localhost local.host test.local.host subdomain.local.host xxx.local.host

We are making explicit all domains and subdomains that will point to our local machine, under IP 127.0.0.1. By default localhost was already there, so we have just added the needed subdomains. When working with this subdomains I personally like to create a domain like my_app.local, and point subdomains to it like sub.my_app.local. There are some other ways to create this setup, but we would rather go with this due to readability and easy configuration.

To make sure everything is fine we need to clear our dns cache:

Under linux:

/etc/init.d/dns-clean start

Under OS X:

dscacheutil -flushcache

And that is it. Restart your application and try it out. Access it under the new domain or subdomain you have created, for instance local.host:3000, to see if everything is working fine.

You may be asking why we could not be using just subdomain.localhost instead of subdomain.local.host as subdomain configuration. And you are right, we could use it, and it should work fine to access subdomains. However, there are some “bumps in the road” while sharing sessions, so keep reading!

Installing subdomain-fu

Subdomain-fu is easy to install as any other gem:

gem install subdomain-fu

Configure it in your environment:

config.gem 'subdomain-fu', :version => '0.5.3'

Then we are going to need a config file to setup subdomain-fu, with basically the following code:

SubdomainFu.tld_sizes = {
  :development => 1, # local.host
  :test => 1,
  :production => 1 # my_app.com
}

This config file can be placed at config/initializers folder. Basically it tells subdomain-fu the sizes of the domain for each environment, i.e. 0 for localhost, 1 for foo.com, 2 for foo.bar.com.

The gem gives you some special powers through the current_subdomain method in your controllers, and also some adds to your routes like using the :subdomain option: root_url(:subdomain => 'foo') #=> foo.local.host.

Routing

Chances are you are going to need specific actions to be handled only under subdomains, but not in the root domain or a specific subdomain, like admin.foo.com. And subdomain-fu will help you here: you just need to setup your routes using the :subdomain condition, like the example below:

ActionController::Routing::Routes.draw do |map|
  map.with_options :conditions => { :subdomain => /^[A-Za-z0-9-]+$/ } do |app|
    app.resources :posts
    app.root :controller => 'posts'
  end
  # ... other routes
end

This will ensure your routes require a subdomain to be recognized.

Finally, everything is perfect, you are now able to test subdomains in your environment, create some filters to ensure the subdomain exists and your user has access to it, sessions work as expected, and so on, right? Nope. We are not ready yet. Sessions are our pain.

Sharing sessions between subdomains

Due to security issues, browsers do not allow sharing cookies using only .com, just under the complete domain like foo.com, and of course it is totally right. Could you imagine sharing sessions between gmail.com and hotmail.com, just because they are both .com? I could not. The same rule applies while trying to share sessions using localhost only. Browsers will not allow you sharing sessions between subdomains under localhost, and some weird issues may appear. We have had AuthenticityToken errors while trying to use localhost.

Anyway, we were smart enough to create our own subdomain configuration using local.host instead of localhost, remember? Our configuration actually simulates a full domain like the foo.com example instead of .com only. Think this way: localhost => com, local.host => foo.com.

We are going to use this setup now. To enable sharing sessions in your application you need to configure the :domain option in your session config hash, for each environment. Here is how to do it in development config:

config.action_controller.session = { :domain => '.local.host' }

Please note the dot prepended to the domain. It will enable sharing sessions between all subdomains in your application. Think about it as *.local.host, including local.host itself. By doing this, you are now able to sign a user in one subdomain, or even the root domain, and redirect it to any other subdomain, for instance. The session will be kept and the user will stay signed in as expected.

Do not forget to setup the production environment with the same config, pointing to the real domain of your application.

Testing

We are using cucumber in this application together with celerity/culerity, and at the beginning it was kind of pain to get it up and running. The first thing you must bear in mind is that you always have to setup the host you are testing. By default, cucumber uses host example.com. And that is okay for default Rails integration tests, except when we use “real browsers” tests like celerity or selenium. You have to set it up by yourself. Just create two steps like this:

Given /^I am visiting the root application$/ do
  host! 'local.host'
end
 
Given /^I am visiting the subdomain "([^\"]*)"$/ do |subdomain|
  host! "#{subdomain}.local.host"
end

And use then inside your features:

Given I am visiting the subdomain "my_sub"

That should do the trick. Make sure you use only subdomains you have configured in your hosts file, or you will get some weird errors =).

Mailers

We had some issues while creating mailers with links pointing to the subdomain. As our users has many subdomains, we don’t know where we should point the user inside the mailer, due to default lack of request context as we have in the controller. To solve this we could not use any class accessor, because they are not thread safe. So we decided to go with Thread.current. Just create a filter in your application controller:

before_filter :set_current_subdomain
protected
  def set_current_subdomain
    Thread.current[:current_subdomain] = current_subdomain
  end

Then create a new helper called MailHelper inside your app/helpers folder, adding a method to obtain the subdomain:

def current_subdomain
  Thread.current[:current_subdomain]
end

This MailHelper is a module provided by Rails which is included in all mailers. Now you are able to create links inside your mailers using the current_subdomain method, just like you do in your controllers:

link_to "Go to application", root_url(:subdomain => current_subdomain)

What about Devise?

Devise has been doing a great work while authenticating a user under a specific subdomain. There are two cases to be handled: the first one is when your User model has a subdomain attribute and you want the authentication process take into account this subdomain with the current_subdomain. First of all you need to update devise call inside your user model to add the :authentication_keys option:

devise :all, :authentication_keys => [:email, :subdomain]

This will tell devise to find the user based on both subdomain and email. Then you have to add the subdomain to your sign in form as a hidden field, so Devise will be able to get this information easily from params while authenticating the user:

f.hidden_field :subdomain, :value => current_subdomain

The second case happens when your subdomain data is inside another model associatied with the user, let’s say a user has many accesses. In addition to what we have done in the first case, we must override a class method from Devise to add our own condition for finding the user:

def self.find_for_authentication(conditions={})
  conditions[:accesses] = { :subdomain => conditions.delete(:subdomain) }
  find(:first, :conditions => conditions, :joins => :accesses)
end

Devise is now totally capable of handling authentication based on subdomains. Remember: Devise is managing authentication, so it will not be able to do anything after the user signs in. Be sure to also add filters to your controllers to ensure a user will never access a subdomain it has no access.

Here we go!

A few steps are needed to get our development machine up and running to create an application using subdomains, but they are key steps to ensure you are not going to have problems while starting.

What about you? Have you ever developed an application using subdomains? Have you run through any of these issues, or maybe another you want to share? Do you have any tip?