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:
~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?
Tags: operators, ruby, unary
Posted in English | View Comments
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:
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:
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:
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:
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!
Tags: i18n, performance, plugins, rails
Posted in English | View Comments
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!
Tags: inherited_resources, plugins, rails, responders, respond_with
Posted in English | View Comments
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?
Tags: rails, session, subdomain
Posted in English | View Comments
Well, we are in business for almost one year and we are happy to say that quite a lot of applications were already delivered. In each one of them, we were definitely learning and moving toward the Plataforma way of doing things.
So I want to talk the way we treat Rails controllers at Plataforma. With love, of course, but we are going to go deeper than that, specifically in three steps:
1) Using InheritedResources to dry up controllers
2) Splitting your controllers by scope with nested controllers
3) Creating acts_as_* and filters to contain common logic and configuration among controllers
Step 1: Using InheritedResources to dry up controllers
InheritedResources is a tool that allows drying up your controllers, by removing the common logic and taking care of stuff like relationships.
For instance, imagine that you have an Article model which belongs to user. If you want to show all the articles for an specific user, your routes definition and controller are just the following:
# config/routes.rb map.resources :users do |u| u.resources :articles end # app/controllers/articles_controller.rb class ArticlesController < InheritedResources::Base belongs_to :users end
It supports nested and/or polymorphic relationships, I18n and other stuff like named scopes.
Almost all of our controllers inherit from InheritedResources::Base and the first step is as simple as that.
Step 2: Splitting your controllers by scope with nested controllers
Sometime ago, Matt Jankowski from Thoughtbot wrote an excellent blog post on how they deal with scoped controllers, like in the scenario above where we want to show all the articles which belongs to an specific user.
Matt tell us that instead of having an ArticlesController, we should have a Users::ArticlesController, so ArticlesController is available if you want to show all the articles in the application.
Since we read this post, we started to use this setup on our applications as well. However, InheritedResources does not play nice with it by default and let’s check why. Our ArticlesController should be renamed to Users::ArticlesController and be rewritten as:
class Users::ArticlesController < InheritedResources::Base belongs_to :users end
The problem is, according to the namespace Users, InheritedResources appends to all named routes the prefix “users”. But since Articles belongs to :user, it also appends “user”. So the resource_url method will actually call “users_user_article_url”, which is not defined. The fix is simple:
class Users::ArticlesController < InheritedResources::Base defaults :route_prefix => nil belongs_to :users end
Matt’s post contains a lot of tips about using nested controllers and it’s a must-read.
Step 3: Creating acts_as_* and filters to contain common logic and configuration among controllers
As your application grow, you will start to notice that your controllers will have a lot of configuration values and methods for specific scopes. Let’s consider that in our application an user can only see his articles and we are going to retrieve the user from session. So instead of having a route “/users/:user_id/articles/:id” like above, we should just have “/articles/:id” and our controller will be similar to:
class Users::ArticlesController < InheritedResources::Base before_filter :find_user_from_session layout "users" defaults :route_prefix => nil protected # Get the articles scoped to the current user def begin_of_association_chain @current_user end # Simple method to retrieve an user from session def find_user_from_session @current_user ||= User.find(session[:user_id]) end end
With time, we will notice that several controllers use this same pattern, and we need to refactor it. Our first thought would be move part of the logic to ApplicationController, but our ApplicationController will only grow and grow as you add roles (like Admin) to your application.
A better approach would be to move this specific logic to a controller named Users::ApplicationController inside “app/controllers/users/application_controller.rb”:
class Users::ApplicationController < ApplicationController before_filter :find_user_from_session layout "users" protected def begin_of_association_chain @current_user end def find_user_from_session @current_user ||= User.find(session[:user_id]) end end
Now we can inherit from it and get InheritedResources methods by calling inherit_resources in our controller:
class Users::ArticlesController < Users::ApplicationController inherit_resources # the same as inheriting from InheritedResources::Base defaults :route_prefix => nil end
But we are not very happy with this pattern, because we still need to call defaults and set some configuration values (which can be quite a few depending on your application).
What we do instead is create some macros inside a module called Filters. So we create a file at “app/controllers/users/filters.rb” with the following:
module Users::Filters def acts_as_user(options={}) before_filter :find_user_from_session layout "users" defaults options.reverse_merge(:route_prefix => nil) include ControllerMethods end module ControllerMethods protected def begin_of_association_chain @current_user end def find_user_from_session @current_user ||= User.find(session[:user_id]) end end end
And extend this module in our ApplicationController:
class ApplicationController < ActionController::Base extend Users::Filters end
And we can use it simply as:
class Users::ArticlesController < InheritedResources::Base acts_as_user end
The main advantage here is that we have more control of our controller configuration through a single interface. If we need to configure a singleton controller or ensure that most controllers have pagination, we can simply do:
module Users::Filters def acts_as_user(options={}) before_filter :find_user_from_session layout "users" has_scope :paginate, :only => :index unless options.delete(:paginate) == false defaults options.reverse_merge(:route_prefix => nil) include ControllerMethods end
And invoke it as:
acts_as_user :paginate => false acts_as_user :singleton => true acts_as_user :paginate => false, :singleton => true
Wrapping up
As you add more roles to your application, you create more filter. Remember that the important here is to keep your code DRY and is NOT reduce the lines of code. So just place inside those acts_as_* helpers configuration which is common to almost all (if not all) controllers. There is some convention over configuration here, so be sure that the whole team working in the project agrees with them as well. In other words: use it with caution, because we certainly do.
This pattern holds almost all controllers in the last applications we built and we are quite happy with it. Be sure to grab our blog feed (see our sidebar), because we will continue writing about the Plataforma way in next posts!
Tags: filters, inherited_resources, the plataforma way
Posted in English | View Comments

All
English only
Em português apenas



