I am using devise and have overridden the registrations controller to allow a user to be "soft-deleted" following the instructions here: devise/wiki/How-to:-Soft-delete-a-user.
I've put some puts
commands through my code to follow the test and my rspec result looks like this:
10:00:30 - INFO - Running: spec/controllers/users/registrations_controller_spec.rb
..
> BEFORE: id:2, deleted_at:
> -- model: id:2, deleted_at:2016-12-08 15:00:35 UTC
> -- controller: id:2, deleted_at:2016-12-08 15:00:35 UTC
> AFTER: id:2, deleted_at:
F..
Failures:
1) Users::RegistrationsController GET #destroy sets 'deleted_at' date for user
Failure/Error: expect(user.deleted_at).to_not be_nil
expected: not nil
got: nil
# ./spec/controllers/users/registrations_controller_spec.rb:44:in `block (3 levels) in <top (required)>'
Finished in 0.37438 seconds (files took 3.7 seconds to load)
5 examples, 1 failure
As the puts
show, my user starts out with the deleted_at
field set to null. The model sets deleted_at
to the current time and the controller confirms that the date is set, but by the time I get to my expect()
statement in my test user.deleted_at
is back to nil
. This appears to be a problem with my test because the application functions properly.
/spec/controllers/users/registrations_controller_spec.rb
require 'rails_helper'
require 'factory_girl_rails'
RSpec.describe Users::RegistrationsController, type: :controller do
include Devise::Test::ControllerHelpers
describe "GET #destroy" do
it "sets 'deleted_at' date for user" do
request.env["devise.mapping"] = Devise.mappings[:user]
# sign-in user
user = FactoryGirl.create(:user_for_account_update)
sign_in(user, scope: :user) # note: does not verify correct password
# soft-delete user
puts "BEFORE: id:#{user.id}, deleted_at:#{user.deleted_at}"
delete :destroy, {:id => user.id}
puts "AFTER: id:#{user.id}, deleted_at:#{user.deleted_at}"
expect(user.deleted_at).to_not be_nil
end
end
end
/spec/factories/user.rb
require 'ffaker'
FactoryGirl.define do
factory :user do |u|
@pass = "password"
name FFaker::Name.name
email { |me| "#{name.to_s.gsub(/\s/,'.')}_#{rand(1000).to_s}@testing.com" }
password @pass
factory :user_for_account_update do
password_confirmation @pass
confirmed_at Date.today
end
end
end
/app/models/user.rb
...
# instead of deleting, indicate the user requested a delete & timestamp it
def soft_delete
update_attribute(:deleted_at, Time.current)
puts " -- model: id:#{id}, deleted_at:#{deleted_at.to_s}"
end
...
/app/controllers/users/registrations_controller.rb
# This class overrides devise's registration controller. All
# other devise actions remain (I believe) handled as usual by
# devise. I think it is the route that does that by specifying
# this controller specifically for the purpose of registrations
#
# see also: http://stackoverflow.com/questions/3546289
class Users::RegistrationsController < Devise::RegistrationsController
before_filter :configure_permitted_parameters, if: :devise_controller?
# SOFT DELETE /resource
# Follows devise guide: https://github.com/plataformatec/devise/wiki/How-to:-Soft-delete-a-user-when-user-deletes-account
def destroy
resource.soft_delete
Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
set_flash_message :notice, :destroyed if is_flashing_format?
yield resource if block_given?
respond_with_navigational(resource){ redirect_to after_sign_out_path_for(resource_name) }
puts " -- controller: id:#{resource.id}, deleted_at:#{resource.deleted_at}"
end
protected
# we have to explicitly permit params in overridden controllers like this
# see https://github.com/plataformatec/devise#strong-parameters
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up) do |u|
u.permit(:name, :email, :password, :password_confirmation)
end
devise_parameter_sanitizer.permit(:account_update) do |u|
u.permit(:name, :email, :password, :password_confirmation, :current_password)
end
end
end