We have just released Devise 2.0. This version is not a big refactoring, nor contains stellar features, it is simply another step towards a very mature authentication library.
Over the years, we have learned from our own experience and from your feedback, how to better use Devise. We’ve made changes to improve security and also to make the library more flexible. All those changes were backwards compatible, forcing us to maintain different branches of logic in the same source code to accomodate those different scenarios. Devise 2.0 simply deprecates those old scenarios so we can clean up the code.
When you migrate to 2.0, you should get some warnings. The amount of warnings will depend on when you started using Devise. For recent applications, it should take 2 minutes to update (basically fixing up migrations and the locale file), older applications should be up to speed in 15-30 minutes. We have created a page with instructions to upgrade, be sure to read it for a smoother experience.
Finally, Devise 2.0 also includes:
- Support to the reconfirmable feature. When on, if the user changes his e-mail, he needs to confirm the new e-mail address before the e-mail is finally updated;
- We got rid of
t.database_authenticatableand friends in migrations in favor of explicit code; - Better support to engines. For example, we now support
config.parent_controllerwhich you can set to something different fromApplicationController. There is a good sample engine here; - Rails 3.2 support. The previous Devise version (v1.5) runs fine but with a few deprecation warnings, v2.0 gets rid of them;
The CHANGELOG is available here.
Thanks everyone that contributed to this awesome release and, if you have any issues, please let us know in the issues tracker. Here to a better future!
Tags: devise
Posted in English | No Comments »
We, Rails developers, have always worried about improving the performance of our test suites. Today I would like to share three quick tips we employ in our projects that can drastically speed up your test suite.
1. Reduce Devise.stretches
Add the following to your spec/test helper:
Devise.stretches = 1
Explanation: Devise uses bcrypt-ruby by default to encrypt your password. Bcrypt is one of the best choices for such job because, different from other hash libraries like MD5, SHA1, SHA2, it was designed to be slow. So if someone steals your database it will take a long time for them to crack each password in it.
That said, it is expected that Devise will also be slow during tests as many tests are generating and comparing passwords. For this reason, a very easy way to improve your test suite performance is to reduce the value in Devise.stretches, which represents the cost taken while generating a password with bcrypt. This will make your passwords less secure, but that is ok as long as it applies only to the test environment.
Latest Devise versions already set stretches to one on test environments in your initializer, but if you have an older application, this will yield a nice improvement!
2. Increase your log level
Add the following to your spec/test helper:
Rails.logger.level = 4
Explanation: Rails by default logs everything that is happening in your test environment to “log/test.log”. By increasing the logger level, you will be able to reduce the IO during your tests. The only downside of this approach is that, if a test is failing, you won’t have anything logged. In such cases, just comment the configuration option above and run your tests again.
3. Use shared connection with transactional fixtures
If you are using Capybara for javascript tests and Active Record, add the lines below to your spec/test helper and be sure you are running with transactional fixtures equals to true:
class ActiveRecord::Base mattr_accessor :shared_connection @@shared_connection = nil def self.connection @@shared_connection || retrieve_connection end end # Forces all threads to share the same connection. This works on # Capybara because it starts the web server in a thread. ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
Explanation: A long time ago, when Rails was still in 1.x branch, a new configuration option called use_transactional_fixtures was added to Rails. This feature is very simple: before each test Active Record will issue a begin transaction statement and issue a rollback after the test is executed. This is awesome because Active Record will ensure that no data will be left in our database by simply using transactions, which is really, really fast.
However, this approach may not work in all cases. Active Record connection pool works by creating a new connection to the database for each thread. And, by default, database connections do not share transactions state. This means that, if you create data inside a transaction in a thread (which has its own database connection), another thread cannot see the data created at all! This is usually not an issue, unless if you are using Capybara with Javascript tests.
When using Capybara with javascript tests, Capybara starts your Rails application inside a thread so the underlying browser (Selenium, Webkit, Celerity, etc) can access it. Since the test suite and the server are running in different threads, if our test suite is running inside a transaction, all the data created inside the test suite will no longer be available in the server. Alternatively, since the server is outside the transaction, data created by the server won’t be cleaned up. For this reason, many people turn off use_transactional_fixtures and use Database Cleaner to clean up their database after each test. However, this affects your test suite performance badly.
The patch above, however, provides a very simple solution to both problems. It forces Active Record to share the same connection between all threads. This is not a problem in your test suite because when the test thread is running, there is no request in the server thread. When the server thread is running, the test thread is waiting for a response from the server. So it is unlikely that both will use the connection at the same time. Therefore, with the patch above, you no longer need to use Database Cleaner (unless you are using another database like Mongo) and, more importantly, you must turn use_transactional_fixtures back to true, which will create a transaction wrapping both your test and server data, providing a great boost in your test suite performance.
Finally, if any part of your code is using threads to access the database and you need to test it, you can just set ActiveRecord::Base.shared_connection = nil during that specific test and everything should work great!
Conclusion
That’s it! I hope you have enjoyed those tips and, if they helped you boost your test suite performance, please let us know in the comments the time your test suite took to run before and after those changes! Also, please share any tips you may have as well!
Tags: capybara, devise, performance, tests
Posted in English | 15 Comments »
Last week I spoke at Silicon Valley Ruby Group about PlataformaTec’s open source tools, mainly Devise, Simple Form and Responders.
When talking about Devise, I’ve mentioned that, before creating Devise, we were alternating between using Authlogic or Clearance in our projects. However, we soon realized that we needed a solution that was as customizable as Authlogic (allowing us to choose behaviors and several configuration options) and as complete as Clearance (whole MVC stack). It is fun to remember this happened more than 2 years ago.
After the presentation, someone came to talk to me about Sorcery and said it would be nice if Devise provided the same kind of tooling, allowing someone to build their own controllers and views around Devise instead of using Devise built-in controllers and views. His proposal surprised me, because this approach is totally possible with Devise and it was one of our design goals since day one.
That said, we realized that we were probably not “advertising” the bare-bone, stripped-down aspect of Devise well enough. That’s why I am writing this blog post. Devise already makes it easy for you to customize your own views, using the generator rails g devise:views which copies the views to your application. But what if you want to roll out your own views AND controllers?
To show you how we can achieve that, let’s write some code! The first step is to create a Rails application:
rails new devise-only-model
Next, we will add Devise to the Gemfile:
gem "devise", "~> 1.4.6"
And run the installation generator:
bundle install && rails g devise:install
The installation generator is going to give you some extra instructions, so don’t forget to do that as well. Next, let’s generate our basic User model, but we will pass an extra parameter called --skip-routes:
rails g devise User --skip-routes
By passing this extra parameter, Devise is going to generate everything as usual, with a small difference on config/routes.rb:
devise_for :users, :skip => :all
This parameter tells Devise to not generate any route at all. You can check that by executing bundle exec rake routes. However, you may be wondering: why can’t we simply remove the devise_for call? If we remove the route, Devise wouldn’t actually know that you have added Devise configuration to the User model, as all models are lazy loaded. So we need the route to tell Devise it needs to setup the appropriate helpers for the user, like authenticate_user!.
With Devise configured, we are ready to create the controllers and views on our own. In this blog post, we are going to create the SessionsController as an example allowing us to sign in and sign out. First, let’s add our routes:
root :to => "sessions#new" post "/users/sign_in" => "sessions#create" delete "/users/sign_out" => "sessions#destroy"
Our SessionsController at app/controllers/sessions_controller looks like:
class SessionsController < ApplicationController # For security purposes, Devise just authenticates an user # from the params hash if we explicitly allow it to. That's # why we need to call the before filter below. before_filter :allow_params_authentication!, :only => :create def new @user = User.new(params[:user]) end def create # Since the authentication happens in the rack layer, # we need to tell Devise to call the action "sessions#new" # in case something goes bad. Feel free to change it. user = authenticate_user!(:recall => "sessions#new") flash[:notice] = "You are now signed in!" sign_in user redirect_to root_path end def destroy sign_out flash[:notice] = "You are now signed out!" redirect_to root_path end end
The controller implementation is quite straightforward. With the controller in hands, we just need to generate the view for the new action at app/views/sessions/new.html.erb:
<% if user_signed_in? %> You are signed in as <%= current_user.email %>. <%= link_to "Sign out", users_sign_out_path, :method => :delete %>. <% else %> <%= form_for @user, :url => users_sign_in_path do |f| %> <div><%= f.label :email %><br /> <%= f.email_field :email %></div> <div><%= f.label :password %><br /> <%= f.password_field :password %></div> <div><%= f.check_box :remember_me %> <%= f.label :remember_me %></div> <div><%= f.submit "Sign in" %></div> <% end %> <% end %>
The view shows a message if the user is signed in, otherwise it shows a sign in form. Now we are almost ready to check if it works. First, we need to run the migrations:
bundle exec rake db:migrate
Remove the index page:
rm public/index.html
And create a user in the database so we can sign in. We can do that in rails console:
User.create!(:email => "jose@example.com", :password => "123456")
Now, start the server and you are ready to sign in and sign out. You can also block user access in any controller by calling authenticate_user! in a before filter. Just remember that, if you add the filter to your application controller, remember to skip the filter on the sessions controller, otherwise you won’t be able to sign in in the first place.
You can now freely proceed to implement the other controllers and views in your application. Keep in mind that if you have devise :recoverable in your model, all the related methods like User.send_reset_password_instructions will already be available in your model, so you can use them straight away to implement your own reset password feature. Since Devise use all those methods internally, if you have any questions about implementing your own reset password feature, you can always take a look at Devise own controllers for some help.
I hope this post can help you to roll out your own controllers if this is the kind of feature you expect from Devise. Also, if you are worried about the overhead of using Devise even if you are not using its controllers, there is no need to worry at all. Devise does the smart thing and only loads the controllers you are actually using. Also, it lazily loads all behaviors, so if you are not using recoverable, no code related to recoverable will be loaded at all.
It is important to keep in mind that Devise was built by us to be flexible and capable of handling different requirements from different clients, so it is PlataformaTec’s priority to have it as flexible as possible! So, what would you like to see in “bare-bone, stripped-down Devise” in order to better use it in your applications?
Tags: authentication, devise, rails
Posted in English | 12 Comments »
Note: Devise 1.1.6 broke compatibility with Rails versions prior to 3.0.4, this has been fixed on Devise 1.1.7.
Devise 1.1.6 has just been released and it follows Rails 3.0.4 release. Rails 3.0.4 changes how CSRF works and adds a new method called handle_unverified_request that should be properly overridden by authentication frameworks. Devise 1.1.6 implements this method and others small security fixes.
If you have updated to Rails 3.0.4, you must update to Devise 1.1.6. Those using Devise 1.2.rc should use master for awhile, another RC is coming soon. For more information, check out the CHANGELOG.
Devise 1.0.10 was also released with the same fixes for Rails 2.3.11.
Tags: devise, security fix
Posted in English | Comments Off
This year is coming to an end and it was amazing for us at Plataforma Tecnologia. We are proud to share with you, faithful reader, our accomplishments in 2010, which weren’t few.
Open Source
The year has begun on fire. In February, José Valim made his way into the Rails Core team and has been doing a great work since then, including many contributions to the Rails 3 release.
We are also really proud with Devise. It got very mature, achieving the 1.0 version this February. Since then, Devise is becoming one of the best solutions for authentication in Rails and also one of the most watched repositories on GitHub.
In August, Devise 1.1 was released with Rails 3 support and a bunch of cool features. Recently, a lot of work is being done towards the 1.2 version, which includes full support to the awesome OmniAuth gem.
We also released SimpleForm this year. SimpleForm is our take on building forms in a simplified way lead by Carlos Antônio who recently did a great work on HTML 5 support.
Other gems were released, such as ShowFor, which is a DSL to simplify how you show your objects in views and also Responders, a collection of Rails 3 responders.
Book
Eariler this month, José Valim’s book entitled Crafting Rails Applications has been released by the highly acclaimed publisher Pragmatic Bookstore! The book covers internal aspects of Rails 3 and how you can bend it to your will. The reviews and buzz has been great so far, even though still in beta. Grab your copy now!
Events
This year was also very productive in terms of events. We’ve been to a lot of events, heck, George was even able to go to RailsConf, in Baltimore! Also, José Valim has spoken in various events, including Euruko 2010 (includes video), RubyConf Brazil 2010 (talk in portuguese) and OxenteRails 2010.
Carlos, Hugo and George did their share as well, speaking at various events, from smaller and user-group events to bigger ones such as OxenteRails, RS on Rails and QCon SP.
Company
The company itself is getting more mature and increasing. At January 2010, PlataformaTec was composed of 6 people, and up until December 2010, 5 other people joined the company (including myself)! We also have started playing with iOS development, something we believe to have a great future, expect future blog posts on the subject.
Great 2011!
Have a great New Year! We wish you all the best for year to come. We have high expectations for 2011, so stay tuned!
Tags: devise, dsl, euruko, rails, railsconf, responders, review, rubyconf, show_for, simple_form
Posted in English | 1 Comment »
One of the great gems released in the past few months was OmniAuth. It is very easy to use, it works without tons of configurations (unless configuring XML files is your thing) and there are already plenty of resources about it on the internet.
However, it is not easy to do acceptance tests with Omniauth as it depends on external services to work. So what should we do? When I face a scenario like this, I split the acceptance test in two parts: one before the external service and one after the external service response.
Testing the first one is trivial: you only have to ensure there is an <a> tag with href equals to “/auth/facebook” (or “/auth/#{insert_your_provider_here}” if you use another one). We don’t test any of the redirects done by OmniAuth internals, because it is already tested in gem’s tests, so we go to the next step: testing the OmniAuth callback.
Testing OmniAuth callbacks is in general cumbersome but for OAuth2 providers it is a bit easier as it uses Faraday internally to connect to the provider. With Faraday, we can configure a test adapter and stub calls to return what we want.
The OmniAuth strategy provides an entry point to the Faraday connection, but we don’t have an access to the strategy directly, so we need to store it globally. For a Facebook strategy, we can achieve it as below whenever configuring Omniauth middleware:
module OmniAuth mattr_accessor :facebook_strategy end middleware.use OmniAuth::Strategies::Facebook, "APP_ID", "APP_SECRET" do |strategy| OmniAuth.facebook_strategy = strategy end
Note you will need OmniAuth 0.2.0 (which currently is OmniAuth master) as previous versions don’t yield a block on initialization like above.
With access to the strategy, we do the acceptance test. First, we define the hashes we will return on the Faraday responses.
FACEBOOK_INFO = { :id =>; '12345', :link => 'http://facebook.com/plataformatec', :email => 'myemail@example.com', :first_name => 'Plataforma', :last_name => 'Tecnologia', :website => 'http://blog.plataformatec.com.br' } ACCESS_TOKEN = { :access_token => "nevergonnagiveyouup" }
Now, we will define the stubs. OAuth2 strategies do two requests: one to retrieve the access token and another to retrieve the user information. In this example, let’s stub the Facebook requests and assign these stubs to a new connection.
stubs = Faraday::Adapter::Test::Stubs.new do |b| b.post('/oauth/access_token') { [200, {}, ACCESS_TOKEN.to_json] } b.get('/me?access_token=nevergonnagiveyouup') { [200, {}, FACEBOOK_INFO.to_json] } end OmniAuth.facebook_strategy.client.connection = Faraday::Connection.new do |builder| builder.adapter :test, stubs end
For each provider the URLs may differ, so an idea is to do this on a TDD way (or you can browse through the OmniAuth source code and see the url that it requests):
- Assign the Faraday fake connection without stubs.
- Run your test
- See the test to raise an exception like “No stubbed request for DESIRED_URL”.
- Add the stubbed request with the response that you want.
- Repeat this process until the test pass
This is what we do on acceptance tests with OmniAuth: testing before and after the access to the external services.
Another approach is to do only one test by short-circuiting the provider authentication URLs. To do that on a Rails application, you can store the provider URL on a method like “OmniAuth.facebook_url” and stub the method to return the callback URL on your test. If you happen to be using Devise, the upcoming 1.2 version does the short-circuiting automatically for you, as you can see in Devise integration tests.
What about you? How do you stub OmniAuth requests and responses on your applications?
Tags: acceptance tests, devise, omniauth
Posted in English | 4 Comments »

All
English only
Em português apenas