I wanted to do a refactoring that I noticed while working on my redmine_lock_users plugin. Redmine tracks the User status with a single integer field and provides some constants to access them. The problem with this is that every other class has to know and use those constants to change a status. By using self encapsulate field I was able to make the User class responsible for changing the status and all the caller has to do is to call the correct method.
Before
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class AccountController < ApplicationController
def activate
# ...
redirect_to(home_url) && return unless user.status == User::STATUS_REGISTERED
user.status = User::STATUS_ACTIVE
# ...
end
def register_automatically(user, &block)
# ...
user.status = User::STATUS_ACTIVE
user.last_login_on = Time.now
# ...
end
end |
class AccountController < ApplicationController
def activate
# ...
redirect_to(home_url) && return unless user.status == User::STATUS_REGISTERED
user.status = User::STATUS_ACTIVE
# ...
end
def register_automatically(user, &block)
# ...
user.status = User::STATUS_ACTIVE
user.last_login_on = Time.now
# ...
end
end
After
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class AccountController < ApplicationController
def activate
# ...
redirect_to(home_url) && return unless user.registered?
user.activate
# ...
end
def register_automatically(user, &block)
# ...
user.activate
user.last_login_on = Time.now
# ...
end
end |
class AccountController < ApplicationController
def activate
# ...
redirect_to(home_url) && return unless user.registered?
user.activate
# ...
end
def register_automatically(user, &block)
# ...
user.activate
user.last_login_on = Time.now
# ...
end
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
class User < Principal
def activate
self.status = STATUS_ACTIVE
end
def register
self.status = STATUS_REGISTERED
end
def lock
self.status = STATUS_LOCKED
end
def activate!
update_attribute(:status, STATUS_ACTIVE)
end
def register!
update_attribute(:status, STATUS_REGISTERED)
end
def lock!
update_attribute(:status, STATUS_LOCKED)
end
end |
class User < Principal
def activate
self.status = STATUS_ACTIVE
end
def register
self.status = STATUS_REGISTERED
end
def lock
self.status = STATUS_LOCKED
end
def activate!
update_attribute(:status, STATUS_ACTIVE)
end
def register!
update_attribute(:status, STATUS_REGISTERED)
end
def lock!
update_attribute(:status, STATUS_LOCKED)
end
end
Now the caller’s code (Controller) is working at a higher level when it wants to change a user status. This helps decouple both classes so I can now modify either one to add new behavior. For example, it would be trivial to add a notification when a user is activated or locked.
Reference commit