{"id":1312,"date":"2010-08-19T16:48:54","date_gmt":"2010-08-19T19:48:54","guid":{"rendered":"http:\/\/blog.plataformatec.com.br\/?p=1312"},"modified":"2010-08-19T19:04:39","modified_gmt":"2010-08-19T22:04:39","slug":"devise-1-1-is-out-and-ready-to-rock-with-rails-3","status":"publish","type":"post","link":"https:\/\/blog.plataformatec.com.br\/2010\/08\/devise-1-1-is-out-and-ready-to-rock-with-rails-3\/","title":{"rendered":"Devise 1.1 is out and ready to rock with Rails 3"},"content":{"rendered":"
A couple weeks ago we finally released Devise 1.1<\/a> which is fully-compatible with Rails 3! Not only that, we’ve been working with Rails 3 since the first betas and several features were added along the way! Let’s take a look at those, some architectural changes and see how Devise 1.1 and Rails 3 will change how you handle authentication.<\/p>\n A common complaint in Devise 1.0 (for Rails 2.3) was, in order to know which message to show to the user when sign in failed, we had to pass a parameter in the URL as in However, since Rails 3 moved several responsibilities to the Rack layer, including flash messages, we can easily access flash messages from any Rack application, allowing us to remove the parameter from the URL! Even more, Rails 3 provides small, fast, bare bone controllers through The lockable<\/strong> module in Devise also went through a major overhaul. Previously, it already supported Even more, there is a new option called :lock_strategy, that allows you to specify whether the lock happens only manually or after an amount of invalid sign in attempts.<\/p>\n In Devise 2.3, you may remember that we had a module called And that is what happened in Devise 1.1. Now both database and token authentication work through HTTP with no extra work and the http authenticatable module was deprecated. Besides, if you are creating a new strategy on your own, you get both authentication through parameters (form) and HTTP with no extra work!<\/p>\n We built Devise to be a full stack solution with customization in mind. In Devise 1.1, the customization abilities from Devise were taken to the next level. Now the Talking about Devise’s internal controller, Devise 1.1 namespaced all controllers classes, so now we have Another limitation removed from Devise in this new version is related to URLs customizations. In prior versions, Devise used the URL to retrieve which scope is being accessed. That said, if you were accessing “\/users\/sign_in”, Devise had to inspect this URL and find the “\/users” bit to specify the current scope is “users”. The same happened to “\/admin\/sign_in”.<\/p>\n This had a huge impact in URL customization, because if you wanted to have an URL like “\/some_prefix\/users\/sign_in”, you had to tell Devise you were appending a prefix. Things could get even uglier if you wanted to prepend dynamic prefixes like “\/:locale”.<\/p>\n In Devise 1.1, we use the new contraints API and Rack capabilities from the new router to specify which scope to use. So, instead of inspecting the URL, Devise retrieves the user from the request’s env hash as For all the routes generated by Of course, since this is rather a common pattern, we encapsulated it in a nice API:<\/p>\n You can simply give a block to All the routes specified in the block have higher priority than the ones generated by The last feature we want to discuss is also a routing customization, but we decided to leave it up for last because it shows all the potential coming with Rails 3 and Devise 1.1.<\/p>\n In Devise 1.1, we added the ability to require authentication for a given url in the router, besides the existing before filters in controllers. This allow us to easily require authentication for third party rack application without a need to hack into them. Kisko Labs posted<\/a> an interesting case where you can use Devise to require authentication to a Resque application in very few lines of code:<\/p>\n Devise simply uses the constraints API discussed above, allowing the request to continue only if the user is already authenticated. Otherwise, it redirects the admin to the sign page managed by Devise inside your Rails application. Indeed, when you have Rack, Rails 3 and Devise 1.1 playing along, great things can be accomplished quite easily!<\/p>\n There are several other features, bug fixes and deprecations included in this release, we invite you to check the CHANGELOG<\/a> and take a look at them!<\/p>\n And we are happy to say this is not all, there is much more to come in Devise 1.2, including OAuth2 support which is already added in the master branch. Enjoy!<\/p>\n","protected":false},"excerpt":{"rendered":" A couple weeks ago we finally released Devise 1.1 which is fully-compatible with Rails 3! Not only that, we’ve been working with Rails 3 since the first betas and several features were added along the way! Let’s take a look at those, some architectural changes and see how Devise 1.1 and Rails 3 will change … \u00bb<\/a><\/p>\n","protected":false},"author":4,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[1],"tags":[37,36,115],"aioseo_notices":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/1312"}],"collection":[{"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/comments?post=1312"}],"version-history":[{"count":8,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/1312\/revisions"}],"predecessor-version":[{"id":1325,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/1312\/revisions\/1325"}],"wp:attachment":[{"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/media?parent=1312"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/categories?post=1312"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/tags?post=1312"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}Pretty URLs with Metal<\/h3>\n
\/users\/sign_in?unauthenticated=true<\/code> while one would expect us to simply use flash messages. This happened because the redirection was done not from inside a controller, but a Rack application set up in Warden<\/a> (a Rack authentication framework Devise relies on) and we could not access flash messages from it.<\/p>\n
ActionController::Metal<\/code>, which we used in Devise to clean and speed up the code considerably.<\/p>\n
Locking goodness<\/h3>\n
:unlock_strategy<\/code> as option, allowing you to specify if the user could be automatically unlocked after a time period, through an e-mail token or both. Now, it also supports
:none<\/code> as option, meaning that all unlocking should be done manually.<\/p>\n
HTTP Authentication on by default<\/h3>\n
:http_authenticable<\/code> along with
:database_authenticatable<\/code> and
:token_authenticatable<\/code>. While all three worked great, it was confusing that all HTTP authentication features were built on top of the database authentication and it was not possible to do HTTP authentication using a token unless we created a forth module called
:http_token_authenticatable<\/code>. We quickly noticed this could be improved by providing a better design and better abstract Devise authentication strategies.<\/p>\n
Routing customizations<\/h3>\n
devise_for<\/code> method in routes accepts to extra options:
:skip<\/code> and
:controllers<\/code>. The first one allows you to skip the routes generation for a given controller\/module in case you want to define them on your own, while the second allows you to change the router to point to a given controller in your application, like
Users::ConfirmationsController<\/code> instead of Devise’s internal controller.<\/p>\n
Devise::ConfirmationsController<\/code> instead of
ConfirmationsController<\/code>.<\/p>\n
request.env[\"devise.mapping\"]<\/code>.<\/p>\n
devise_for<\/code>, Devise automatically sets this value in the env hash. However, if you are creating your own routes, you need to set it manually using the constraints API:<\/p>\n
\r\nconstraints lambda { |r| r.env[\"devise.mapping\"] = Devise.mappings[:user] } do\r\n # Add a custom sign in route for user sign in\r\n get \"\/sign_in\", :to => \"devise\/sessions\"\r\nend\r\n<\/pre>\n
\r\ndevise_scope :user do\r\n # Add a custom sign in route for user sign in\r\n get \"\/sign_in\", :to => \"devise\/sessions\"\r\nend\r\n<\/pre>\n
devise_for<\/code> as well and get the same result:<\/p>\n
\r\ndevise_for :users do\r\n # Add a custom sign in route for user sign in\r\n get \"\/sign_in\", :to => \"devise\/sessions\"\r\nend\r\n<\/pre>\n
devise_for<\/code>.<\/p>\n
Awesomeness pack<\/h3>\n
\r\nauthenticate :admin do\r\n mount Resque::Server.new, :at => \"\/resque\"\r\nend\r\n<\/pre>\n