ãã¤ã³ãã·ã¹ãã (4) -- ãµã¼ãã¹ãªãã¸ã§ã¯ã
2013/10/01
ååã¾ã§ã«ããã¤ã³ãã·ã¹ãã ãã®å®è£
ãé²ã¿ã¾ããããCustomer.authenticate
ã¡ã½ãããè¥å¤§åãã¦ãã¾ãããä»å¾ã®éçºã®ãã¨ãèãã¦ãä»åã¯ãªãã¡ã¯ã¿ãªã³ã°ã«ããã½ã¼ã¹ã³ã¼ãã®æ´çæ´é ãè¡ãã¾ãã
ãµã¼ãã¹ãªãã¸ã§ã¯ã
ç¾å¨ã® Customer.authenticate
ã¡ã½ããã®ã³ã¼ãã¯æ¬¡ã®éãã§ãï¼
def authenticate(username, password) customer = find_by_username(username) if customer.try(:password_digest) && BCrypt::Password.new(customer.password_digest) == password Time.zone = 'Tokyo' now = Time.current if now.hour < 5 time0 = now.yesterday.midnight.advance(hours: 5) time1 = now.midnight.advance(hours: 5) else time0 = now.midnight.advance(hours: 5) time1 = now.tomorrow.midnight.advance(hours: 5) end unless customer.rewards.where(created_at: time0...time1).exists? customer.rewards.create(points: 1) end customer else nil end end
ã¾ãæãã¤ãã®ã¯ã顧客ã«ãã°ã¤ã³ãã¤ã³ããçºè¡ãã¦ããé¨åããã©ã¤ãã¼ãã¡ã½ããã¨ãã¦æãåºããã¨ã§ãï¼
def authenticate(username, password) customer = find_by_username(username) if customer.try(:password_digest) && BCrypt::Password.new(customer.password_digest) == password grant_reward_to(customer) customer else nil end end private def grant_login_points_to(customer) Time.zone = 'Tokyo' now = Time.current if now.hour < 5 time0 = now.yesterday.midnight.advance(hours: 5) time1 = now.midnight.advance(hours: 5) else time0 = now.midnight.advance(hours: 5) time1 = now.tomorrow.midnight.advance(hours: 5) end unless customer.rewards.where(created_at: time0...time1).exists? customer.rewards.create(points: 1) end end
ãããããã£ã¨ããæ¹æ³ãããã¾ãããã¤ã³ãçºè¡å¦çãå°éã«æ
ãã¯ã©ã¹ RewardManager
ãæ°ãã«ä½ãã®ã§ãã
ã¾ããapp
ãã£ã¬ã¯ããªã®ä¸ã« services
ã¨ãããµããã£ã¬ã¯ããªãä½ãã¾ãã
$ mkdir app/services
ããã¦ãæ°è¦ãã¡ã¤ã« app/services/reward_manager.rb
ã次ã®ãããªå
容ã§ä½æãã¾ãã
class RewardManager attr_accessor :customer def initialize(customer) self.customer = customer end def grant_login_points Time.zone = 'Tokyo' now = Time.current if now.hour < 5 time0 = now.yesterday.midnight.advance(hours: 5) time1 = now.midnight.advance(hours: 5) else time0 = now.midnight.advance(hours: 5) time1 = now.tomorrow.midnight.advance(hours: 5) end unless customer.rewards.where(created_at: time0...time1).exists? customer.rewards.create(points: 1) end end end
ç¶ãã¦ãCustomer.authenticate
ã¡ã½ããã次ã®ããã«æ¸ãæãã¾ãï¼
def authenticate(username, password) customer = find_by_username(username) if customer.try(:password_digest) && BCrypt::Password.new(customer.password_digest) == password RewardManager.new(customer).grant_login_points customer else nil end end
æ¸ãæããçµãã£ããããã¹ããå®è¡ãã¦ã¨ã©ã¼ã失æãèµ·ããªããã¨ã確èªãã¾ãã
ãã¦ãRewardManager
ã®ãããªãç¹å®ã®ä»äºãå°éã«å¦çããã¯ã©ã¹ã®ã¤ã³ã¹ã¿ã³ã¹ããµã¼ãã¹ãªãã¸ã§ã¯ãã¨å¼ã³ã¾ãããã¡ã¤ã«ã¯ã©ãã«ç½®ãã¦ãããã®ã§ãããæ¬é£è¼ã§ã¯ app/services
ãã£ã¬ã¯ããªã«é
ç½®ãããã¨ã«ãã¾ãã
ä»åã¨æ¬¡åã®å 容ã®åºæ¬çãªã¢ã¤ãã¢ã¯ãCode Climate Blog ã® 7 Patterns to Refactor Fat ActiveRecord Models ã¨ããè¨äºããæåãã¦ãã¾ãã
ãµã¼ãã¹ãªãã¸ã§ã¯ãã使ç¨ããä¸ã§ã®ã³ãã¯ãå¦çãã¤ã³ã¹ã¿ã³ã¹ã¡ã½ããã¨ãã¦å®è£ ããã¨ãããã¨ã§ããããããã°ãã¤ã³ã¹ã¿ã³ã¹å¤æ°ãå±æ§ã¨ããå¼·åãªæ¦å¨ãæã«å ¥ãã¾ãã
ãã©ã¤ãã¼ããªã¯ã©ã¹ã¡ã½ããã¨ãã¦å¦çãåé¢ããã¨ãã«ã¯ããã¼ã«ã«å¤æ° customer
ãã¡ã½ããã®å¼æ°ã¨ãã¦æ¸¡ãå¿
è¦ãããã¾ããããã¾ã¯ã¾ã 1åã®å¼æ°ã§æ¸ãã§ãã¾ãããå°æ¥çã«ã¯ãã£ã¨å¤ãã®å¼æ°ãå¿
è¦ã«ãªãããããã¾ãããã¤ã³ã¹ã¿ã³ã¹å¤æ°ãå±æ§ãå©ç¨ã§ããã°ãå¼æ°ã®å¢å ã«æ©ã¾ãããã«æ¸ãã®ã§ãã
ãã¹ãã®æ´ç
Customer
ã¯ã©ã¹ãã RewardManager
ã¯ã©ã¹ã«ã³ã¼ãã移åããã®ã§ããã¹ããåããã¦å¤æ´ãã¦ããã¾ãããã
ç¾å¨ãspec/models/customer_spec.rb
ã® .authenticate
ã¡ã½ããã®ã¨ã°ã¶ã³ãã«ã°ã«ã¼ãã¯æ¬¡ã®ãããªå½¢ããã¦ãã¾ãï¼
describe Customer, '.authenticate' do let(:customer) { create(:customer, username: 'taro', password: 'correct_password') } specify 'ã¦ã¼ã¶ã¼åã¨ãã¹ã¯ã¼ãã«è©²å½ããCustomerãªãã¸ã§ã¯ããè¿ã' do result = Customer.authenticate(customer.username, 'correct_password') expect(result).to eq(customer) end specify '該å½ããã¦ã¼ã¶ã¼åãåå¨ããªãå ´åã¯nilãè¿ã' do result = Customer.authenticate('hanako', 'any_string') expect(result).to be_nil end specify 'ãã¹ã¯ã¼ããä¸è´ããªãå ´åã¯nilãè¿ã' do result = Customer.authenticate(customer.username, 'wrong_password') expect(result).to be_nil end specify 'ãã¹ã¯ã¼ãæªè¨å®ã®ã¦ã¼ã¶ã¼ãæ絶ãã' do customer.update_column(:password_digest, nil) result = Customer.authenticate(customer.username, '') expect(result).to be_nil end specify 'ãã°ã¤ã³ã«æåããã¨ãã¦ã¼ã¶ã¼ã®ä¿æãã¤ã³ãã1å¢ãã' do expect { Customer.authenticate(customer.username, 'correct_password') }.to change { customer.points }.by(1) end specify 'æ¥ä»å¤æ´æå»ãã¾ããã§2åãã°ã¤ã³ããã¨ãã¦ã¼ã¶ã¼ã®ä¿æãã¤ã³ãã2å¢ãã' do Time.zone = 'Tokyo' date_boundary = Time.zone.local(2013, 1, 1, 5, 0, 0) expect { Timecop.freeze(date_boundary.advance(seconds: -1)) Customer.authenticate(customer.username, 'correct_password') Timecop.freeze(date_boundary) Customer.authenticate(customer.username, 'correct_password') }.to change { customer.points }.by(2) end specify 'æ¥ä»å¤æ´æå»ãã¾ãããã«2åãã°ã¤ã³ãã¦ããã¦ã¼ã¶ã¼ã®ä¿æãã¤ã³ãã¯1ããå¢ããªã' do Time.zone = 'Tokyo' date_boundary = Time.zone.local(2013, 1, 1, 5, 0, 0) expect { Timecop.freeze(date_boundary) Customer.authenticate(customer.username, 'correct_password') Timecop.freeze(date_boundary.advance(hours: 24, seconds: -1)) Customer.authenticate(customer.username, 'correct_password') }.to change { customer.points }.by(1) end end
æ«å°¾ã®2ã¤ã®ã¨ã°ã¶ã³ãã«ã RewardManager
ã¯ã©ã¹ã®ãã¹ãã«ç§»åãã¾ãããã
ã¾ã spec/services
ãã£ã¬ã¯ããªãä½ãã¾ãã
$ mkdir spec/services
ããã¦ãæ°è¦ãã¡ã¤ã« spec/services/reward_manager_spec.rb
ã次ã®ãããªå
容ã§ä½æãã¾ãã
require 'spec_helper' describe RewardManager, '#grant_login_points' do let(:customer) { create(:customer) } specify 'æ¥ä»å¤æ´æå»ãã¾ããã§2åãã°ã¤ã³ããã¨ãã¦ã¼ã¶ã¼ã®ä¿æãã¤ã³ãã2å¢ãã' do Time.zone = 'Tokyo' date_boundary = Time.zone.local(2013, 1, 1, 5, 0, 0) expect { Timecop.freeze(date_boundary.advance(seconds: -1)) RewardManager.new(customer).grant_login_points Timecop.freeze(date_boundary) RewardManager.new(customer).grant_login_points }.to change { customer.points }.by(2) end specify 'æ¥ä»å¤æ´æå»ãã¾ãããã«2åãã°ã¤ã³ãã¦ããã¦ã¼ã¶ã¼ã®ä¿æãã¤ã³ãã¯1ããå¢ããªã' do Time.zone = 'Tokyo' date_boundary = Time.zone.local(2013, 1, 1, 5, 0, 0) expect { Timecop.freeze(date_boundary) RewardManager.new(customer).grant_login_points Timecop.freeze(date_boundary.advance(hours: 24, seconds: -1)) RewardManager.new(customer).grant_login_points }.to change { customer.points }.by(1) end end
ãã¤ã³ãã®ä»ä¸ã«é¢ããä»æ§ãã²ã¨ã¤ã«ã¾ã¨ã¾ããã¢ããªã±ã¼ã·ã§ã³å ¨ä½ã®è¦éããè¯ããªãã¾ãããã
次åã¯
次åãããµã¼ãã¹ãªãã¸ã§ã¯ããã¨ããèãæ¹ãç¨ãã¦ãè¨è¨ã®æ¹åãç¶ãã¾ããã§ã¯ãã¾ãã