mardi 26 janvier 2016

Porting from Rails 3.2 to Rails 4.2 - Devise - registration controller bypasses validations

I have mostly ported my application from Rails 3.2 to Rails 4.2. (about 2 out of 700 tests are still failing).

In the previous Rails stack, I used:

  • Rails 3.2.18
  • Ruby 2.1.5
  • Devise 3.2.2
  • RSpec 2.13.1

Now I'm using

  • Rails 4.2.5
  • Ruby 2.2.4
  • Devise 3.5.3
  • RSpec 2.14.1

My user class looks like this:

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :confirmable , :validatable  

  attr_accessible :name, :email, :password, :password_confirmation, :identity_url, 
                  :remember_me, :terms

  validates :terms, acceptance: { accept: 'yes' }
end

My registrations controller looks like this:

class RegistrationsController < Devise::RegistrationsController
  def new
    @title = "Sign up"
    super
  end
end

I have an RSpec test for the registrations controller which looks like this:

describe "failure to accept terms" do
  before(:each) do
    @attr = { :name => "New User", :email => "user@example.com",
              :password => "foobar", :password_confirmation => "foobar", :terms => "no" }
  end

  it "should not create a user" do
    lambda do
      @request.env["devise.mapping"] = Devise.mappings[:user]

      post :create, :user => @attr
    end.should_not change(User, :count)
    #raise Exception,  User.last.inspect
  end
end

With the previous application stack, the test passed. With the new application stack it fails.

1) RegistrationsController POST 'create' failure to accept terms should not create a user
  Failure/Error: lambda do
     count should not have changed, but did change from 0 to 1

With the old stack or the new stack, if I try the following in the Rails console,

irb(main) > User.all.count
=> 0
irb(main) > @attr = { :name => "New User", :email => "user@example.com",                  :password => "foobar", :password_confirmation => "foobar", :terms => "no" }
irb(main) > u = User.create(@attr)
irb(main) User.all.count
=> 0
irb(main) u.errors.messages
=> {:terms=>["must be accepted"]} 

......the user is not created, and u.errors yields the validation error for the terms. This is what should happen.

When I uncomment the "raise Exception" line in the test, I get the following:

#<User id: 2, name: nil, email: "user@eexample.com", created_at: "2016-01-22 18:13:35", updated_at: "2016-01-22 18:13:35", encrypted_password: "$2a$04$oySRVGtQQrbKkp9hmvHlIuA8kdpEASMkhnQ4rDuDC9L...", salt: nil, admin: false, reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, confirmation_token: "_deYRJswq4yLLNrNNRAz", confirmed_at: nil, confirmation_sent_at: "2016-01-22 18:13:36", authentication_token: nil, unconfirmed_email: nil, terms: nil, identity_url: nil >

It looks like the user gets created, but key data such as the name, and terms are not assigned.

The long and the short? With Devise, user validations all ran with the Rails 3.2 stack, and did not run with the Rails 4.2 stack.

Is there a way to ensure that validations are run when using the Devise-based registrations controller?

Aucun commentaire:

Enregistrer un commentaire