Posts tagged "plugins"

Today we are celebrating Devise’s birthday. But wait, if you have started watching Devise since the beginning you may be asking: has Devise already completed one year of life? Nope. Today we are completing exactly 4 months since Devise was released at Rails Summit Latin America 2009. And we are very proud and glad to say that we have just reached version 1.0! Yeah! Let’s celebrate and talk a bit about history.

The beginning

We decided to build Devise based on some requirements we had in a project last year. The majority of our projects usually require an admin interface to configure the application with some CRUD information. And in this specific project, we were needing two different roles in the same application, the admin itself with all its powers to manage the application, and the end users that should be signed in to do some stuff inside the application. Usually only one model would be required in this situation, with some “type” column or flag to determine if the user is an admin or not, right? Okay, but we didn’t like this approach that much. So we started looking at some of the possibilities:

  • Authlogic: a really great piece of code and functionality, but a bit messy by handling the session in a model. It also only handles the model part.
  • Clearance: full stack, Rails Engine, extra modules, everything we needed. However, packaged with a User model and without the ability to customize it.

Okay, we could pick one of these and with a bit of extra work we would achieve our requirements. But would we need to do it every time this situation happens? We said no. It’s not DRY enough. And we like DRY. So Devise was born.

The main objective of the first Devise version was to get up and running the entire sign in process, including password recovery and confirmation stuff. And everything should work with different roles, which mean you could easily plug and play an Admin, User, Account, or whichever role you needed, in your application, without much effort. And we had a deadline: Rails Summit. It took almost 1 month of work before Rails Summit. I still remember the days before the event, we putting a lot of effort to have Devise up and running, and the README being written during the event. So, we were ready there and presenting Devise to the world.

How it works

Devise was born with the intuit of handling different roles without effort, automatically, and it is achieved with Rails Engines. In addition, Devise is build in top of Warden, a great rack authentication framework. It allowed us to be flexible enough and add different strategies, hooks, and modules easily. In short, Devise:

  • Is Rack based;
  • Is a complete MVC solution based on Rails Engines;
  • Allows you to have multiple roles (or models/scopes) signed in at the same time;
  • Is based on a modularity concept: use just what you really need.

The road so far

Devise has started with the basic modules needed for that specific application:

  • Authenticatable: responsible for signing users in through a basic login form, handling password validation and authentication.
  • Confirmable: manages confirming users account.
  • Recoverable: handles password recovery.
  • Validatable: basic email and password validation.

Okay, everything we needed were there. Everything else was in a wish list, nicely called TODO. And we decided from the beginning to not add features to Devise until us or somebody else really needed them. But people asked, people needed new features. And they were always there to help, to fork and fix a bug, to comment. We started soon to add new features, the first was:

  • Rememberable: handles signing users in automatically from cookies.

After people were asking for easier ways to create their migrations, so we introduced a new module with Devise 0.2:

  • Migratable: hooks into ActiveRecord migrations to add helper methods for creating Devise colums. So you can do stuff like t.authenticatable, t.confirmable and so on.

To help people getting up and running faster, we created some generators. Now they are:

  • script/generate devise_install: create devise initializer file to enable some configs and copy default locale file.
  • script/generate devise MyModel: create a model with setup for Devise, routes and migration.
  • script/generate devise_views: copy all Devise views to your app/views folder, so you can change it as needed.

Devise 0.3 and 0.4 came soon after, with a lot of bug fixes in generators, I18n, initialization, some deprecations and a bunch of code refactored.

Contributions from community were coming more and more. The first big contribution came with the addition of encryptors. Nowadays Devise supports encrypting passwords with SHA1, SHA512, and BCrypt. It has also support for using the same encryptors as Authlogic, Clearance and Restful Authentication, to help you migrating from these solutions.

At this point we thought: okay, that should be enough. It wasn’t. People needed different ORMs, other than ActiveRecord. So we introduced support to MongoMapper and then we were reaching Devise 0.5.

We were receiving a lot of issues with functional tests, so we introduced some test helpers to help people with the sign in/out process in this kind of tests called Devise::TestHelper.

As applications grow, more roles may be needed. So we created the possibility to scope your views for each role/scope in your application. This way your user can have a different sign in view than the admin, for example. Reaching Devise 0.6, a lot of improvements on routes and DataMapper support were added.

We were full of nice ideas to add new features, and our TODO was bigger than we like. So we came up with:

  • Timeoutable: verify each request to timeout the user session after a certain period of inactivity, asking for credentials again.
  • Trackable: records how many times each user has signed in, last timestamps and ips.

Also the loading process and ORM support received a lot of work before launching Devise 0.7.

For Devise 0.8 we looked at tests for MongoMapper and the code got a great review. Also some work was done to get Devise up and running with latest version of Warden and its new features, such as serializers. We also extracted a new base module from Confirmable:

  • Activatable: allow setting up extra activation methods for your models.

We were receiving a lot of feedback from the community, and then we merged a cool new feature:

  • Lockable: lock accounts based on a number of invalid sign in attempts.

Following the same pattern from Rails in this commit we moved flash messages to :notice and :alert, and released Devise 0.9. Step by step the 1.0 version was coming.

What is new

Devise 1.0 introduces a lot of cool features. The community seems to be really appreciating Devise, and we’ve received another great contribution:

  • Token Authenticatable: validates authenticity of a user while signing in using an authentication token (also known as “single access token”).

In addition, we created the two most requested features for Devise:

  • Registerable: handles sign up users through a registration process, and also editing/updating user info and deleting user account.
  • HTTP Authenticatable: http basic authentication.

We also added the possibility to use Migratable while editing a table using change_table, among other fixes.

What comes next

We are preparing a new release of Devise fully compatible with Rails 3. It means Devise has now closed its development for new features in Rails 2.x. We are still going to maintain a 1.0 branch in github for bug fixes to keep everything up and running.

In the end

We would like to say thank you to everyone who has helped us achieve 1.0 version and who is using Devise, testing, creating issues, and giving all this feedback.

Also, for those who were at Rails Summit last year, we proposed something: get the biggest number of watchers on github as fast as possible! When we presented Devise, there were 7 watchers, and if I am right we were 4 of them. At the time of this writing we have 762 watchers. Yeah! I think I can take the risk and say we accomplished it. Thanks!

Let’s celebrate Devise 1.0, and look forward to see Devise and Rails 3. Enjoy!

Happy birthday Devise!

This weekend during Rails Bugmash I stumbled across some nice posts about Rails 3 generators which motivated me to share them and add some comments!

First, David Trasbo wrote a nice guide about how to make your first Rails 3 generator, it covers up all the basic steps including setting it up in a gem. He also puts the deserved attention into Thor::Actions, which contains most helpers you need in a generator, like copy_file, template, create_file, empty_directory and so on.

On another post, Ben Scofield talks about apply method, which is also in Thor::Actions, and how to use it to dry your application templates.

Wait… so Thor::Actions is used both in generators and in Rails application templates? Exactly, Rails’ new generators unifies both application templates and generators API into one. While Thor::Actions holds basic methods, all Rails specific methods like environment, rakefile, generator are in Rails::Generators::Actions. If you already wrote an application template, you will feel more at home when writing a Rails 3 generator.

Paul Barry talks how easy it’s to customize your scaffold to use Rspec, Haml and Factory Girl instead of Test::Unit, Erb and Fixtures. This all works because scaffold is just a meta generator which provides hooks for template engine, test framework, ORM and so forth. A good way to see the hooks system working is by running script/generate scaffold --help before and after Paul changes, so you can see exactly how generators options update depending on the configuration values you set. While I wrote Rspec generators used in the example, he implemented himself Haml and Factory Girl generators and they can all be used as example if you plan to build your own.

Finally, Zigzag Chen wrote about templates customization and how you can change your scaffold controller to use json instead of the xml format. New generators have source paths, so you can customize them simply by copying files to RAILS_ROOT/lib/templates.

Rails Bugmash was excellent to gather feedback and we also got some tickets on Lighthouse, mainly about how generators help can be improved for people starting with Rails. Many thanks to Rails Bridge and besides the posts linked above, there is a generator guide, which may help you get started and maybe write your own post as well. :)

A couple days ago DHH twitted that they were getting Basecamp running on Ruby on Rails 3.0.

This means Basecamp migrated from the first Rails release up to the edge one. So how come people say so frequently how hard is to update their applications from Rails 2.1 to Rails 2.2? And the answer is simple: plugins.

Every time you are adding a plugin to your application, you are inserting some hundreds or even thousands of lines of code in your application, without knowing what it does exactly. And sometimes this becomes technical debt, mostly noticeable when you have to update to a new Rails version. And why is that? Because a lot of plugins are monkey patching Rails, so whenever Rails changes its internal API between releases, the plugin breaks.

However, they are two simple actions you could do to improve your application maintainability, your ruby fu and also give a little back to the community.

The first one is easy: check the source code of the plugin you are installing. Does it needs to monkey patch Rails code? Or even worse, Ruby classes? If so, how much? If too much, turn it down. Search for simpler solutions or even start one from scratch with just what you need, it will take more time, but you will learn a lot through the process.

Another very compelling reason is that reading other people’s code is one of the best ways to learn. You will learn new things and probably see a few things which could be done better. And when it happens, write a patch!

Besides, whenever something is going wrong in your application, you will know better where to start searching and you will eventually help plugins authors to track bugs down. And, in the worst scenario, if you have to update the plugin after a Rails release on your own because the plugin creator is no longer interested, you will be more capable to do so.

Some people often choose plugin A because of features X, Y and Z. But whenever they have to add feature W, they are stuck, because the plugin code is a complete spaghetti. And all this time, they could have chosen plugin B, which just has feature X, but adding Y, Z and W would be quite easy. Reading the plugin’s source code is one way to ensure you are prioritizing code quality instead of features count.

And the second step, guess what, is easy too: run the plugin test suite. Really, it will take just a couple minutes. You definitely don’t want to use a plugin where the test suite fails (or which does not have a test suite at all). Imagine that for some reason you need to add features to a plugin, how you will ensure you did not break other thing while doing so? Or even worse, imagine you have to update the plugin for a new Rails release. How can you ensure the plugin works on 3.0 if you cannot even ensure it works on 2.3?!

Some already noted that I have patches applied in different plugins around GitHub. And this is the very reason: I check their code, send simple suggestions whenever it’s possible and most important of all, I choose well which plugins to use. So whenever I need to write a new feature because the application I’m working on needs it, I know it will be easy, since the plugin code is quite well written and test suite is green.

It’s really two small efforts, which gives everyone, including you, a lot back.

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 to much the other translations. You can add it to your app as easy as the Fast one:

  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 leading 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!

UPDATE: This post was an introduction to Devise and a couple of things changed since then. There is a more recent post which describes the same steps as below using generators and, for a more complete and always updated explanation, please check the README.

In Rails Summit Latin America 2009, we showed Devise in a lightning talk and today we are officially releasing it! Before we show you some code, we are going to explain what we want to achieve with Devise, starting with the most used authentication solution nowadays: Clearance and Authlogic.

Clearance

Clearance is a full stack authentication solution, implementing all Model, View and Controller layers using Rails Engines. It deals with account confirmation and password recovery. You just need to plug and play! However, you are required to use the model User and it does not allow you have add and/or customize different roles.

Authlogic

When comes to the Model, Authlogic is definitely the most complete solution out there. It handles several cryptography providers and many other goodies which are completely configurable. However, it’s not a full stack solution (it does not say how users should confirm their account or recover their password) and it has a little bit of controversy since it handles the session in a model. So here is the question, where the session could be handled then?

Here comes Warden!

Warden is a general rack authentication framework, developed by Daniel Neighman, which handles the session in a rack middleware. The main benefit from it is that you can share your authentication strategies with several apps, so if you are using Sinatra, Rails and some others middlewares at the same time, they all rely on the same rules!

Devise: strategies for authentication

After we fell in love with Warden and used it in some projects, we decided to create a full stack solution as Clearance, but flexible as Authlogic, on top of Warden. The solution is Devise, a Rails Engine which handles multiple roles, each one of them with different strategies. Devise currently comes with 5 strategies:

  • Authenticatable: responsible for encrypting password and validating authenticity of a user while signing in;
  • Confirmable: responsible for verifying whether an account is already confirmed to sign in, and to send emails with confirmation instructions;
  • Recoverable: takes care of reseting the user password and send reset instructions;
  • Rememberable: generates and clears a token to remember the user from a saved cookie;
  • Validatable: creates all needed validations for email and password. It’s totally optional, so you’re able to to customize validations by yourself.

The nice thing is: imagine that you are building an app which needs to handle invitations. You just need to create a Invitable strategy on Devise and never implement it again!

Show me the code!

In the README, you will find all the information you need to start using Devise in your projects, so here we are going to cover the main aspects of it. Let’s suppose you are creating an user model, which needs to be authenticated and recover his password. The first step is to create the columns using Devise migration helpers:

create_table :users do |t|
  # creates email, encrypted_password and password_salt
  t.authenticatable
 
  # creates reset_password_token
  t.recoverable
end

Then you need to declare inside your model which strategies you want to use:

class User < ActiveRecord::User
  # Authenticatable is always included
  devise :recoverable, :validatable
end

And create the routes:

ActionController::Routing::Routes.draw do |map|
  # Check for configuration params on README
  map.devise_for :users
end

The route will access your model and create only the routes for the strategies declared. That ensures that your user won’t access the confirmations controller inside Devise. Devise also adds a couple of helpers and filters to be used inside your controllers:

  # Inside your protected controller
  before_filter :authenticate_user!
 
  # Inside your controllers and views
  user_signed_in?
  current_user
  user_session

user_session is a hash scoped only to the user. So if you have two roles, they will have different session hashes and their data won’t conflict! This awesome feature come straights from Warden!

Devise also has I18n support and since it’s an engine, you can customize your views just by placing a copy of it in your application. A small application build as example is also available on Github!

What’s more to come?

We are planning to add several other strategies to Devise, including brute force protection, session timeouts and also other features, as generators. You can spy our TODO list whenever you want.

Our many thanks to

Carlos Antônio which worked on Devise and made it ready for prime time! Jonas Nicklas, which introduced us to Warden and Daniel Neighman for building and maintaining it!

We also want to thank Thoughtbot guys, which wrote several decisions and tips they took while developing Clearance which helped us while building Devise.

Finally, thanks to Fábio Akita for giving us the chance to release it at Rails Summit and Gregg Pollack for releasing Devise on Ruby 5!

First, what is Inherited Resources?

Inherited Resources is a gem/plugin that allows you to speed up development by making your controllers inherit all restful actions so you just have to focus on what is important. A Rails scaffold controller which responds to html, xml and json is as simple as:

1
2
3
class ProjectsController < InheritedResources::Base
  respond_to :html, :xml, :json
end

However all actions are still customizable! For example, you can change the behavior of the create action on success just doing:

1
2
3
4
5
6
7
8
9
class ProjectsController < InheritedResouces::Base
  respond_to :html, :xml, :json
 
  def create
    create! do |success, failure|
      success.html { redirect_to edit_project_url(@project) }
    end
  end
end

It also supports I18n (all flash messages are set with I18n), belongs to association (like a task belongs to project), nested belongs to (task belongs to project which belongs to company), polymorphic belongs to (comments belong to task or file or message) and optional belongs to (the same as previously, but you can request the resource with or without parents).

As you noticed, besides simplifying your controllers, InheritedResouces makes easy to reproduce your models behavior and relationship in controllers. And right now, it’s also scopes and responder fluent!

has_scope: named_scope twin brother

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
class ProjectsController < InheritedResources::Base
  has_scope :featured, :boolean => true
  has_scope :by_methodology
  has_scope :limit, :default => 10, :only => :index
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

Yay!

Responder

A couple weeks ago, we wrote about ActionController::Responder. But you don’t have to wait Rails 3 to be released to play with it, you can start now by using Inherited Resources.

Quick redirect

After using Inherited Resouces, I realized that most of the times I overwrite a create, update or destroy actions is to change the redirect destination. In our ProjectsController above, if we want to redirect to the edit page after create, we would have to do:

1
2
3
4
5
6
7
8
9
class ProjectsController < InheritedResouces::Base
  respond_to :html, :xml, :json
 
  def create
    create! do |success, failure|
      success.html { redirect_to edit_project_url(@project) }
    end
  end
end

It wouldn’t be cool if it have a shortcut? Now it has:

1
2
3
4
5
6
7
class ProjectsController < InheritedResouces::Base
  respond_to :html, :xml, :json
 
  def create
    create! { edit_project_url(@project) }
  end
end

That simple, just give the url as a proc and since the proc does not expect any parameters, it assumes that you want to overwrite the redirect url.

Finally some DSL?

Last weeks, there was a discussion on Boston.rb group about different resource controllers gems. Reading some of the feedback there, I’ve decided to stab a DSL to Inherited Resources. It will mainly remove the duplication when you have to give a block, the previous example above could be written as:

1
2
3
4
5
6
7
class ProjectsController < InheritedResouces::Base
  respond_to :html, :xml, :json
 
  create! do |success, failure|
    success.html { redirect_to edit_project_url(@project) }
  end
end

Or even in the compact form:

1
2
3
4
class ProjectsController < InheritedResouces::Base
  respond_to :html, :xml, :json
  create! { redirect_to edit_project_url(@project) }
end

Those changes were not applied yet, it depends mainly on you. If you like or not, let us know in the comments!