SlideShare a Scribd company logo
1 of 62
Download to read offline
Rails Antipatterns 
Hong
 ChulJu
Speaker 
Hong ChulJu 
• http://blog.fegs.kr 
• https://github.com/FeGs 
• Rails Newbie 
• SW Maestro 5th
RAILS ANTIPATTERN 
mainly about code refactoring
Index 
• Monolithic Controllers 
• Fat Controller 
• PHPitis 
• Voyeuristic Models 
• Spaghetti SQL 
• Fat Model 
• Duplicate Code Duplication 
• Fixture Blues 
• Messy Migration
Monolithic Controllers 
• User Authentication 
class UsersController  ApplicationController 
def action 
operation = params[:operation] 
# ... 
end 
end
Monolithic Controllers 
• Our projects 
resources :users, only: [] do 
collection do 
get 'show' 
get 'sign_in', to: 'users#sign_in' 
get 'sign_up', to: 'users#new' 
post 'sign_up', to: 'users#create' 
get 'email_sent', to: 'users#email_sent' 
get 'verify/:code', to: 'users#verify' 
end 
end 
powerful user
Monolithic Controllers 
• Our projects 
class UsersController  ApplicationController 
def new 
end 
def create 
end 
def show 
end 
?? 
def sign_in 
end 
def sign_out 
end 
def email_sent 
end 
def verify 
end 
end
• UsersController#new 
• UsersController#create 
• UsersController#verify 
• UsersController#show 
• UsersController#sign_in 
• UsersController#sign_out 
• UsersController#email_sent 
• - 
break apart controllers 
ActivationsController 
[:new, :create, :show] 
SessionsController 
[:new, :destroy]
Fat Controller 
class RailsController  ApplicationController 
def create 
# ... 
# transaction, association 
# service logic, etc 
# Suppose that this method contains 100+ lines of code. 
end 
end
Fat Controller 
class RailsController  ApplicationController 
def create 
active record callback, 
build object 
# ... 
# transaction, association 
# service logic, etc 
# Suppose that this method contains 100+ lines of code. 
end 
end 
service objects, lib
Controller + lib 
class ReservationsController  ApplicationController 
def create 
reservation = Reservation.new 
ticket = Ticket.new 
# ticket code generation 
# ... 
ticket.code = # ... 
reservation.transaction do 
ticket.save! 
reservation.ticket = ticket 
reservation.save! 
end 
end 
end 
1) to lib?
Controller + lib 
class TicketsController  ApplicationController 
def create 
ticket = Ticket.new 
code_generator = CodeGenerator.new 
ticket.code = code_generator.generate 
# ... 
end 
end 
ticket need to be coupling with code 
may miss it?
Model + lib 
class Ticket  ActiveRecord::Base 
# has a code column 
before_save :generate_code 
private 
def generate_code 
active record callback 
code_generator = CodeGenerator.new 
self.code ||= code_generator.generate 
end 
end 
# TicketsController#create 
ticket = Ticket.create! 
profit!
internal transaction 
class ReservationsController  ApplicationController 
def create 
reservation = Reservation.new 
reservation.transaction do 
reservation.ticket = Ticket.create! 
reservation.save! 
end 
end 
end 
2) Remove transaction
internal transaction 
class ReservationsController  ApplicationController 
def create 
reservation = Reservation.new 
reservation.ticket.build 
reservation.save! 
end 
end association
Service Object 
class ReservationsController  ApplicationController 
def create 
result = CreateReservationService.new.execute 
end 
end 
ServiceObject
Service Object 
https://github.com/gitlabhq/gitlabhq/tree/master/app/services
PHPitis 
• Do you know PHP? 
% if current_user  
(current_user == @post.user || 
@post.editors.include?(current_user))  
@post.editable?  
@post.user.active? % 
%= link_to 'Edit this post', edit_post_url(@post) % 
% end %
Useful accessors to model 
• Post#editable_by? (not a helper method) 
% if @post.editable_by?(current_user) % 
%= link_to 'Edit this post', edit_post_url(@post) % 
% end %
Useful accessors to model 
• Our project 
module Admin::UsersHelper 
def pretty_phone_number(phone_number) 
return  unless phone_number 
# prettify logic 
prettified 
end 
def pretty_rails # ... 
end 
%= pretty_phone_number(user.phone_number) %
Useful accessors to model 
• Decorate a user 
class User  ActiveRecord::Base 
# recommend to use draper 
def display_phone_number 
return  unless phone_number 
# prettify logic 
prettified 
end 
end 
%= user.display_phone_number %
content_for? 
• named yield block 
html 
head 
%= yield :head % 
/head 
body 
%= yield % 
/body 
/html 
% content_for :head do % 
titleA simple page/title 
% end % 
pHello, Rails!/p
Extract into Custom Helpers 
• Markup Helpers 
def rss_link(project = nil) 
link_to Subscribe to these #{project.name if project} alerts., 
alerts_rss_url(project), :class = feed_link 
end 
div class=feed 
%= rss_link(@project) % 
/div
Extract into Custom Helpers 
• Our project 
def nav_link_to (text, link) 
active = active if current_page?(link) 
content_tag :li, class: active do 
link_to text, link 
end 
end 
ul class=nav nav-pills nav-stacked col-md-3 pull-left 
%= nav_link_to Unread, notifications_path % 
%= nav_link_to All Notifications, notifications_all_path % 
/ul
Voyeuristic Models 
• Situation 
class Invoice  ActiveRecord::Base 
belongs_to :customer 
end 
class Customer  ActiveRecord::Base 
has_one :address 
has_many :invoice 
end 
class Address  ActiveRecord::Base 
belongs_to :customer 
end 
%= @invoice.customer.address.city %
Voyeuristic Models 
• Law of Demeter 
• No method chaining (Down coupling) 
• Basic refactoring of OOP (why getter, setter?) 
• Not only for rails
Voyeuristic Models 
• General way 
class Invoice  ActiveRecord::Base 
# ... 
def customer_city 
customer.city 
end 
end 
class Customer  ActiveRecord::Base 
# ... 
def city 
address.city 
end 
end 
%= @invoice.customer_city %
Voyeuristic Models 
class Customer  ActiveRecord::Base 
def city 
address.city 
end 
def street 
address.street 
end 
def state 
address.state 
end 
# many fields below 
end 
??
Voyeuristic Models 
• Refactoring using delegate (Rails way) 
class Customer  ActiveRecord::Base 
# ... 
delegate :street, :city, :state, to: :address 
end 
class Invoice  ActiveRecord::Base 
# ... 
delegate :city, to: :customer, prefix: true 
end 
%= @invoice.customer_city %
Voyeuristic Models 
• Furthermore 
• http://blog.revathskumar.com/2013/08/rails-use- 
delegates-to-avoid-long-method-chains. 
html 
• http://simonecarletti.com/blog/2009/12/inside-ruby- 
on-rails-delegate/ 
• http://blog.aliencube.org/ko/2013/12/06/law-of-demeter- 
explained/
Spaghetti SQL 
class RemoteProcess  ActiveRecord::Base 
def self.find_top_running_processes(limit = 5) 
find(:all, 
:conditions = state = 'Running', 
:order = percent_cpu desc, 
:limit = limit) 
end 
end 
Reusability?
Spaghetti SQL 
class RemoteProcess  ActiveRecord::Base 
scope :running, where(:state = 'Running') 
scope :system, where(:owner = ['root', 'mysql']) scope :sorted, 
order(percent_cpu desc) 
scope :top, lambda {|l| limit(l) } 
end 
RemoteProcess.running.sorted.top(5) 
RemoteProcess.running.system.sorted.top(5) 
Reusability!
Spaghetti SQL 
class RemoteProcess  ActiveRecord::Base 
scope :running, where(:state = 'Running') 
scope :system, where(:owner = ['root', 'mysql']) scope :sorted, 
order(percent_cpu desc) 
scope :top, lambda {|l| limit(l) } 
# Shortcut 
def self.find_top_running_processes(limit = 5) 
running.sorted.top(limit) 
end 
end
Scope vs Class method 
• Almost same, but scopes are always chainable 
class Post  ActiveRecord::Base 
def self.status(status) 
where(status: status) if status.present? 
end 
def self.recent 
limit(10) 
end 
end 
Post.status('active').recent 
Post.status('').recent 
Post.status(nil).recent 
nil
Scope vs Class method 
• Almost same, but scopes are always chainable 
class Post  ActiveRecord::Base 
scope :status, - status { where(status: status) if 
status.present? } 
scope :recent, limit(10) 
end 
Post.status('active').recent 
Post.status('').recent 
Post.status(nil).recent 
just ignored
Spaghetti SQL 
• Further reading 
• http://blog.plataformatec.com.br/2013/02/ 
active-record-scopes-vs-class-methods/
Fat Model 
• Use extend, include module 
• example: too many scope, finder, etc.
Fat Model 
• ledermann/unread 
module Unread 
module Readable 
module Scopes 
def join_read_marks(user) 
# ... 
end 
def unread_by(user) 
# ... 
end 
# ... 
end 
end 
end 
class SomeReadable  ActiveRecord::Base 
# ... 
extend Unread::Readable::Scopes 
end
Fat Model 
• Do you prefer composition to inheritance?
Fat Model 
• Further Reading 
• http://blog.codeclimate.com/blog/ 
2012/10/17/7-ways-to-decompose-fat-activerecord- 
models/
Duplicate Code Duplication 
• Basic of refactoring 
• Extract into modules 
• included, extended 
• using metaprogramming
Extract into modules 
class Car  ActiveRecord::Base 
validates :direction, :presence = true 
validates :speed, :presence = true 
def turn(new_direction) 
self.direction = new_direction 
end 
def brake 
self.speed = 0 
end 
def accelerate 
self.speed = [speed + 10, 100].min 
end 
# Other, car-related activities... 
end 
class Bicycle  ActiveRecord::Base 
validates :direction, :presence = true 
validates :speed, :presence = true 
def turn(new_direction) 
self.direction = new_direction 
end 
def brake 
self.speed = 0 
end 
def accelerate 
self.speed = [speed + 1, 20].min 
end 
end
Extract into modules 
module Drivable 
extend ActiveSupport::Concern 
included do 
validates :direction, :presence = true 
validates :speed, :presence = true 
end 
def turn(new_direction) 
self.direction = new_direction 
end 
def brake 
self.speed = 0 
end 
def accelerate 
self.speed = [speed + acceleration, top_speed].min 
end 
end
Write a your gem! (plugin) 
ex) https://github.com/FeGs/read_activity 
module Drivable 
extend ActiveSupport::Concern 
included do 
validates :direction, :presence = true 
validates :speed, :presence = true 
end 
def turn(new_direction) 
self.direction = new_direction 
end 
def brake 
self.speed = 0 
end 
def accelerate 
self.speed = [speed + acceleration, top_speed].min 
end 
end 
‘drivable’ gem
Write a your gem! (plugin) 
module DrivableGem 
def self.included(base) 
base.extend(Module) 
end 
module Module 
def act_as_drivable 
include Drivable 
end 
end 
end 
ActiveRecord::Base.send(:include, DrivableGem)
Write a your gem! (plugin) 
class Car  ActiveRecord::Base 
act_as_drivable 
end
How about Metaprogramming? 
class Purchase  ActiveRecord::Base 
validates :status, presence: true, 
inclusion: { in: %w(in_progress submitted ...) } 
# Status Finders 
scope :all_in_progress, where(status: in_progress) 
# ... 
# Status 
def in_progress? 
status == in_progress 
end 
# ... 
end
How about Metaprogramming? 
class Purchase  ActiveRecord::Base 
STATUSES = %w(in_progress submitted ...) 
validates :status, presence: true, 
inclusion: { in: STATUSES } 
STATUSES.each do |status_name| 
scope all_#{status_name}, where(status: status_name) 
define_method #{status_name}? do 
status == status_name 
end 
end 
end 
How to improve reusability?
How about Metaprogramming? 
class ActiveRecord::Base 
def self.has_statuses(*status_names) 
validates :status, presence: true, 
inclusion: { in: status_names } 
status_names.each do |status_name| 
scope all_#{status_name}, where(status: status_name) 
define_method #{status_name}? do 
status == status_name 
end 
end 
end 
end 
Use extension! 
class Purchase  ActiveRecord::Base 
has_statuses :in_progress, :submitted, # ... 
end
Fixture Blues 
• Rails fixture has many problems: 
• No validation 
• Not following model lifecycle 
• No context 
• …
Make Use of Factories 
• Rails fixture has many problems: 
• No validation 
• Not following model lifecycle 
• No context 
• …
Make Use of Factories 
module Factory 
class  self 
def create_published_post 
post = Post.create!({ 
body: lorem ipsum, 
title: published post title, 
published: true 
}) 
end 
def create_unpublished_post 
# ... 
end 
end 
end
Make Use of Factories: 
FactoryGirl 
Factory.sequence :title do |n| 
Title #{n} 
end 
Factory.define :post do |post| 
post.body lorem ipsum 
post.title { Factory.next(:title) } 
post.association :author, :factory = :user 
post.published true 
end 
Factory(:post) 
Factory(:post, :published = false)
Make Use of Factories 
• Rails fixture has many problems: 
• No validation 
• Not following model lifecycle 
• No context 
• …
Refactor into Contexts 
context A dog do 
setup do 
@dog = Dog.new 
end 
should bark when sent #talk do 
assert_equal bark, @dog.talk 
end 
context with fleas do 
setup do 
@dog.fleas  Flea.new 
@dog.fleas  Flea.new 
end 
should scratch when idle do 
@dog.idle! 
assert @dog.scratching? 
end
Refactor into Contexts: 
rspec 
• context is alias of describe 
describe #bark do 
before(:each) do 
@dog = Dog.new 
end 
context sick dog do 
before(:each) do 
@dog.status = :sick 
end 
# ... 
end 
end
Messy Migrations 
• You should ensure that your migrations never 
irreconcilably messy. 
• Never Modify the up Method on a Committed 
Migration : obviously 
• Always Provide a down Method in Migrations
Never Use External Code in a Migration 
class AddJobsCountToUser  ActiveRecord::Migration 
def self.up 
add_column :users, :jobs_count, :integer, :default = 0 
Users.all.each do |user| 
user.jobs_count = user.jobs.size 
user.save 
end 
end 
If No User, No Job? 
def self.down 
remove_column :users, :jobs_count 
end 
end
Never Use External Code in a Migration 
class AddJobsCountToUser  ActiveRecord::Migration 
def self.up 
add_column :users, :jobs_count, :integer, :default = 0 
update(-SQL) 
UPDATE users SET jobs_count = ( 
SELECT count(*) FROM jobs 
WHERE jobs.user_id = users.id 
) 
SQL 
end 
def self.down 
remove_column :users, :jobs_count 
end 
end 
No dependancy
Never Use External Code in a Migration 
class AddJobsCountToUser  ActiveRecord::Migration 
class Job  ActiveRecord::Base 
end 
class User  ActiveRecord::Base 
has_many :jobs 
end 
def self.up 
add_column :users, :jobs_count, :integer, :default = 0 
User.reset_column_information 
Users.all.each do |user| 
Provide definition internally 
Alternative to raw SQL 
user.jobs_count = user.jobs.size 
user.save 
end 
end 
# ... 
end
Never Use External Code in a Migration 
• Further Reading 
• http://railsguides.net/change-data-in-migrations- 
like-a-boss/ 
• https://github.com/ajvargo/data-migrate 
• https://github.com/ka8725/migration_data

More Related Content

What's hot

Rails engines in large apps
Rails engines in large appsRails engines in large apps
Rails engines in large appsEnrico Teotti
 
RESTful API Design & Implementation with CodeIgniter PHP Framework
RESTful API Design & Implementation with CodeIgniter PHP FrameworkRESTful API Design & Implementation with CodeIgniter PHP Framework
RESTful API Design & Implementation with CodeIgniter PHP FrameworkBo-Yi Wu
 
Outside-in Development with Cucumber and Rspec
Outside-in Development with Cucumber and RspecOutside-in Development with Cucumber and Rspec
Outside-in Development with Cucumber and RspecJoseph Wilk
 
Enabling agile devliery through enabling BDD in PHP projects
Enabling agile devliery through enabling BDD in PHP projectsEnabling agile devliery through enabling BDD in PHP projects
Enabling agile devliery through enabling BDD in PHP projectsKonstantin Kudryashov
 
Rails Engines as a way to Micro services
Rails Engines as a way to Micro servicesRails Engines as a way to Micro services
Rails Engines as a way to Micro servicesLucas Alencar
 
Angular server side rendering - Strategies & Technics
Angular server side rendering - Strategies & Technics Angular server side rendering - Strategies & Technics
Angular server side rendering - Strategies & Technics Eliran Eliassy
 
Where Does the Fat Goes? Utilizando Form Objects Para Simplificar seu Código
Where Does the Fat Goes? Utilizando Form Objects Para Simplificar seu CódigoWhere Does the Fat Goes? Utilizando Form Objects Para Simplificar seu Código
Where Does the Fat Goes? Utilizando Form Objects Para Simplificar seu CódigoGuilherme
 
Coffee@DBG - Exploring Angular JS
Coffee@DBG - Exploring Angular JSCoffee@DBG - Exploring Angular JS
Coffee@DBG - Exploring Angular JSDeepu S Nath
 
Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...
Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...
Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...Fwdays
 
Intro to-rails-webperf
Intro to-rails-webperfIntro to-rails-webperf
Intro to-rails-webperfNew Relic
 
Introduction to Sightly and Sling Models
Introduction to Sightly and Sling ModelsIntroduction to Sightly and Sling Models
Introduction to Sightly and Sling ModelsStefano Celentano
 
Styling recipes for Angular components
Styling recipes for Angular componentsStyling recipes for Angular components
Styling recipes for Angular componentsNir Kaufman
 
Introduction to Sightly
Introduction to SightlyIntroduction to Sightly
Introduction to SightlyAnkit Gubrani
 
Telling Stories With RSpec
Telling Stories With RSpecTelling Stories With RSpec
Telling Stories With RSpecrahoulb
 
Understanding JSP -Servlets
Understanding JSP -ServletsUnderstanding JSP -Servlets
Understanding JSP -ServletsGagandeep Singh
 
How to build customizable multitenant web applications - PHPBNL11
How to build customizable multitenant web applications - PHPBNL11How to build customizable multitenant web applications - PHPBNL11
How to build customizable multitenant web applications - PHPBNL11Stephan Hochdörfer
 

What's hot (19)

Angularjs
AngularjsAngularjs
Angularjs
 
Rails engines in large apps
Rails engines in large appsRails engines in large apps
Rails engines in large apps
 
Rails Engines
Rails EnginesRails Engines
Rails Engines
 
RESTful API Design & Implementation with CodeIgniter PHP Framework
RESTful API Design & Implementation with CodeIgniter PHP FrameworkRESTful API Design & Implementation with CodeIgniter PHP Framework
RESTful API Design & Implementation with CodeIgniter PHP Framework
 
Outside-in Development with Cucumber and Rspec
Outside-in Development with Cucumber and RspecOutside-in Development with Cucumber and Rspec
Outside-in Development with Cucumber and Rspec
 
Enabling agile devliery through enabling BDD in PHP projects
Enabling agile devliery through enabling BDD in PHP projectsEnabling agile devliery through enabling BDD in PHP projects
Enabling agile devliery through enabling BDD in PHP projects
 
Rails Engines as a way to Micro services
Rails Engines as a way to Micro servicesRails Engines as a way to Micro services
Rails Engines as a way to Micro services
 
Angular server side rendering - Strategies & Technics
Angular server side rendering - Strategies & Technics Angular server side rendering - Strategies & Technics
Angular server side rendering - Strategies & Technics
 
ParisJS #10 : RequireJS
ParisJS #10 : RequireJSParisJS #10 : RequireJS
ParisJS #10 : RequireJS
 
Where Does the Fat Goes? Utilizando Form Objects Para Simplificar seu Código
Where Does the Fat Goes? Utilizando Form Objects Para Simplificar seu CódigoWhere Does the Fat Goes? Utilizando Form Objects Para Simplificar seu Código
Where Does the Fat Goes? Utilizando Form Objects Para Simplificar seu Código
 
Coffee@DBG - Exploring Angular JS
Coffee@DBG - Exploring Angular JSCoffee@DBG - Exploring Angular JS
Coffee@DBG - Exploring Angular JS
 
Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...
Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...
Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...
 
Intro to-rails-webperf
Intro to-rails-webperfIntro to-rails-webperf
Intro to-rails-webperf
 
Introduction to Sightly and Sling Models
Introduction to Sightly and Sling ModelsIntroduction to Sightly and Sling Models
Introduction to Sightly and Sling Models
 
Styling recipes for Angular components
Styling recipes for Angular componentsStyling recipes for Angular components
Styling recipes for Angular components
 
Introduction to Sightly
Introduction to SightlyIntroduction to Sightly
Introduction to Sightly
 
Telling Stories With RSpec
Telling Stories With RSpecTelling Stories With RSpec
Telling Stories With RSpec
 
Understanding JSP -Servlets
Understanding JSP -ServletsUnderstanding JSP -Servlets
Understanding JSP -Servlets
 
How to build customizable multitenant web applications - PHPBNL11
How to build customizable multitenant web applications - PHPBNL11How to build customizable multitenant web applications - PHPBNL11
How to build customizable multitenant web applications - PHPBNL11
 

Viewers also liked

0.5년차 iOS개발자의 첫 앱스토어 도전기 + 팁
0.5년차 iOS개발자의 첫 앱스토어 도전기 + 팁0.5년차 iOS개발자의 첫 앱스토어 도전기 + 팁
0.5년차 iOS개발자의 첫 앱스토어 도전기 + 팁Soojin Ro
 
Sports social platform halftime
Sports social platform halftimeSports social platform halftime
Sports social platform halftimeDong Kyu Kim
 
외계어 스터디 1/5 - Overview
외계어 스터디 1/5 - Overview외계어 스터디 1/5 - Overview
외계어 스터디 1/5 - Overview민태 김
 
사업계획서
사업계획서사업계획서
사업계획서창옥 김
 
Product Market Fit 제품시장궁합
Product Market Fit 제품시장궁합Product Market Fit 제품시장궁합
Product Market Fit 제품시장궁합Andrew Ahn
 
How Google Works / 구글은 어떻게 일하는가 (Korean / 한국어 버전)
How Google Works / 구글은 어떻게 일하는가 (Korean / 한국어 버전)How Google Works / 구글은 어떻게 일하는가 (Korean / 한국어 버전)
How Google Works / 구글은 어떻게 일하는가 (Korean / 한국어 버전)Mika Eunjin Kang
 
[플러스포럼] 고한얼 자비스 이사(회계사)가 말하는 '스타트업을 위한 세무회계 가이드'
[플러스포럼] 고한얼 자비스 이사(회계사)가 말하는 '스타트업을 위한 세무회계 가이드'[플러스포럼] 고한얼 자비스 이사(회계사)가 말하는 '스타트업을 위한 세무회계 가이드'
[플러스포럼] 고한얼 자비스 이사(회계사)가 말하는 '스타트업을 위한 세무회계 가이드'Jiyoung Yi
 
Google Analytics 가이드 (한국어)
Google Analytics 가이드 (한국어)Google Analytics 가이드 (한국어)
Google Analytics 가이드 (한국어)Min Hee Lee
 

Viewers also liked (8)

0.5년차 iOS개발자의 첫 앱스토어 도전기 + 팁
0.5년차 iOS개발자의 첫 앱스토어 도전기 + 팁0.5년차 iOS개발자의 첫 앱스토어 도전기 + 팁
0.5년차 iOS개발자의 첫 앱스토어 도전기 + 팁
 
Sports social platform halftime
Sports social platform halftimeSports social platform halftime
Sports social platform halftime
 
외계어 스터디 1/5 - Overview
외계어 스터디 1/5 - Overview외계어 스터디 1/5 - Overview
외계어 스터디 1/5 - Overview
 
사업계획서
사업계획서사업계획서
사업계획서
 
Product Market Fit 제품시장궁합
Product Market Fit 제품시장궁합Product Market Fit 제품시장궁합
Product Market Fit 제품시장궁합
 
How Google Works / 구글은 어떻게 일하는가 (Korean / 한국어 버전)
How Google Works / 구글은 어떻게 일하는가 (Korean / 한국어 버전)How Google Works / 구글은 어떻게 일하는가 (Korean / 한국어 버전)
How Google Works / 구글은 어떻게 일하는가 (Korean / 한국어 버전)
 
[플러스포럼] 고한얼 자비스 이사(회계사)가 말하는 '스타트업을 위한 세무회계 가이드'
[플러스포럼] 고한얼 자비스 이사(회계사)가 말하는 '스타트업을 위한 세무회계 가이드'[플러스포럼] 고한얼 자비스 이사(회계사)가 말하는 '스타트업을 위한 세무회계 가이드'
[플러스포럼] 고한얼 자비스 이사(회계사)가 말하는 '스타트업을 위한 세무회계 가이드'
 
Google Analytics 가이드 (한국어)
Google Analytics 가이드 (한국어)Google Analytics 가이드 (한국어)
Google Analytics 가이드 (한국어)
 

Similar to Rails antipattern-public

OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialYi-Ting Cheng
 
Código Saudável => Programador Feliz - Rs on Rails 2010
Código Saudável => Programador Feliz - Rs on Rails 2010Código Saudável => Programador Feliz - Rs on Rails 2010
Código Saudável => Programador Feliz - Rs on Rails 2010Plataformatec
 
Namespace less engine
Namespace less engineNamespace less engine
Namespace less engineshaokun
 
Building Mobile Friendly APIs in Rails
Building Mobile Friendly APIs in RailsBuilding Mobile Friendly APIs in Rails
Building Mobile Friendly APIs in RailsJim Jeffers
 
Pragmatic Patterns of Ruby on Rails - Ruby Kaigi2009
Pragmatic Patterns of Ruby on Rails - Ruby Kaigi2009Pragmatic Patterns of Ruby on Rails - Ruby Kaigi2009
Pragmatic Patterns of Ruby on Rails - Ruby Kaigi2009Yasuko Ohba
 
Rails MVC by Sergiy Koshovyi
Rails MVC by Sergiy KoshovyiRails MVC by Sergiy Koshovyi
Rails MVC by Sergiy KoshovyiPivorak MeetUp
 
Ride on the Fast Track of Web with Ruby on Rails- Part 2
Ride on the Fast Track of Web with Ruby on Rails- Part 2Ride on the Fast Track of Web with Ruby on Rails- Part 2
Ride on the Fast Track of Web with Ruby on Rails- Part 2A.K.M. Ahsrafuzzaman
 
Ruby on Rails + AngularJS + Twitter Bootstrap
Ruby on Rails + AngularJS + Twitter BootstrapRuby on Rails + AngularJS + Twitter Bootstrap
Ruby on Rails + AngularJS + Twitter BootstrapMarcio Marinho
 
Documenting from the Trenches
Documenting from the TrenchesDocumenting from the Trenches
Documenting from the TrenchesXavier Noria
 
Intro to Ruby on Rails
Intro to Ruby on RailsIntro to Ruby on Rails
Intro to Ruby on RailsMark Menard
 
Panmind at Ruby Social Club Milano
Panmind at Ruby Social Club MilanoPanmind at Ruby Social Club Milano
Panmind at Ruby Social Club MilanoPanmind
 
Action Controller Overview, Season 2
Action Controller Overview, Season 2Action Controller Overview, Season 2
Action Controller Overview, Season 2RORLAB
 
walkmod: An open source tool for coding conventions
walkmod: An open source tool for coding conventionswalkmod: An open source tool for coding conventions
walkmod: An open source tool for coding conventionswalkmod
 
RoR 101: Session 5
RoR 101: Session 5RoR 101: Session 5
RoR 101: Session 5Rory Gianni
 
Rails for Beginners - Le Wagon
Rails for Beginners - Le WagonRails for Beginners - Le Wagon
Rails for Beginners - Le WagonAlex Benoit
 

Similar to Rails antipattern-public (20)

OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails Turtorial
 
Código Saudável => Programador Feliz - Rs on Rails 2010
Código Saudável => Programador Feliz - Rs on Rails 2010Código Saudável => Programador Feliz - Rs on Rails 2010
Código Saudável => Programador Feliz - Rs on Rails 2010
 
Namespace less engine
Namespace less engineNamespace less engine
Namespace less engine
 
Building Mobile Friendly APIs in Rails
Building Mobile Friendly APIs in RailsBuilding Mobile Friendly APIs in Rails
Building Mobile Friendly APIs in Rails
 
Pragmatic Patterns of Ruby on Rails - Ruby Kaigi2009
Pragmatic Patterns of Ruby on Rails - Ruby Kaigi2009Pragmatic Patterns of Ruby on Rails - Ruby Kaigi2009
Pragmatic Patterns of Ruby on Rails - Ruby Kaigi2009
 
Rails MVC by Sergiy Koshovyi
Rails MVC by Sergiy KoshovyiRails MVC by Sergiy Koshovyi
Rails MVC by Sergiy Koshovyi
 
Ride on the Fast Track of Web with Ruby on Rails- Part 2
Ride on the Fast Track of Web with Ruby on Rails- Part 2Ride on the Fast Track of Web with Ruby on Rails- Part 2
Ride on the Fast Track of Web with Ruby on Rails- Part 2
 
Ruby on Rails + AngularJS + Twitter Bootstrap
Ruby on Rails + AngularJS + Twitter BootstrapRuby on Rails + AngularJS + Twitter Bootstrap
Ruby on Rails + AngularJS + Twitter Bootstrap
 
Documenting from the Trenches
Documenting from the TrenchesDocumenting from the Trenches
Documenting from the Trenches
 
Intro to Ruby on Rails
Intro to Ruby on RailsIntro to Ruby on Rails
Intro to Ruby on Rails
 
Introduction to AngularJs
Introduction to AngularJsIntroduction to AngularJs
Introduction to AngularJs
 
Ruby For Startups
Ruby For StartupsRuby For Startups
Ruby For Startups
 
Panmind at Ruby Social Club Milano
Panmind at Ruby Social Club MilanoPanmind at Ruby Social Club Milano
Panmind at Ruby Social Club Milano
 
Action Controller Overview, Season 2
Action Controller Overview, Season 2Action Controller Overview, Season 2
Action Controller Overview, Season 2
 
Codegnitorppt
CodegnitorpptCodegnitorppt
Codegnitorppt
 
walkmod: An open source tool for coding conventions
walkmod: An open source tool for coding conventionswalkmod: An open source tool for coding conventions
walkmod: An open source tool for coding conventions
 
RoR 101: Session 5
RoR 101: Session 5RoR 101: Session 5
RoR 101: Session 5
 
mean stack
mean stackmean stack
mean stack
 
Rails for Beginners - Le Wagon
Rails for Beginners - Le WagonRails for Beginners - Le Wagon
Rails for Beginners - Le Wagon
 
Rails 4.0
Rails 4.0Rails 4.0
Rails 4.0
 

More from Chul Ju Hong

Rails antipatterns
Rails antipatternsRails antipatterns
Rails antipatternsChul Ju Hong
 
게임 클론하기
게임 클론하기게임 클론하기
게임 클론하기Chul Ju Hong
 
안드로이드 세미나 2
안드로이드 세미나 2안드로이드 세미나 2
안드로이드 세미나 2Chul Ju Hong
 
안드로이드 세미나
안드로이드 세미나안드로이드 세미나
안드로이드 세미나Chul Ju Hong
 
협업 툴 사용법
협업 툴 사용법협업 툴 사용법
협업 툴 사용법Chul Ju Hong
 

More from Chul Ju Hong (9)

Mixture model
Mixture modelMixture model
Mixture model
 
Digit recognizer
Digit recognizerDigit recognizer
Digit recognizer
 
Naive ML Overview
Naive ML OverviewNaive ML Overview
Naive ML Overview
 
Rails antipatterns
Rails antipatternsRails antipatterns
Rails antipatterns
 
Node.js intro
Node.js introNode.js intro
Node.js intro
 
게임 클론하기
게임 클론하기게임 클론하기
게임 클론하기
 
안드로이드 세미나 2
안드로이드 세미나 2안드로이드 세미나 2
안드로이드 세미나 2
 
안드로이드 세미나
안드로이드 세미나안드로이드 세미나
안드로이드 세미나
 
협업 툴 사용법
협업 툴 사용법협업 툴 사용법
협업 툴 사용법
 

Recently uploaded

%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisamasabamasaba
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...masabamasaba
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdfPearlKirahMaeRagusta1
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech studentsHimanshiGarg82
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...masabamasaba
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplatePresentation.STUDIO
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Hararemasabamasaba
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...masabamasaba
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...masabamasaba
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension AidPhilip Schwarz
 
SHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions PresentationSHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions PresentationShrmpro
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareJim McKeeth
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park masabamasaba
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfkalichargn70th171
 

Recently uploaded (20)

%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
SHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions PresentationSHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions Presentation
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 

Rails antipattern-public

  • 3. Speaker Hong ChulJu • http://blog.fegs.kr • https://github.com/FeGs • Rails Newbie • SW Maestro 5th
  • 4. RAILS ANTIPATTERN mainly about code refactoring
  • 5. Index • Monolithic Controllers • Fat Controller • PHPitis • Voyeuristic Models • Spaghetti SQL • Fat Model • Duplicate Code Duplication • Fixture Blues • Messy Migration
  • 6. Monolithic Controllers • User Authentication class UsersController ApplicationController def action operation = params[:operation] # ... end end
  • 7. Monolithic Controllers • Our projects resources :users, only: [] do collection do get 'show' get 'sign_in', to: 'users#sign_in' get 'sign_up', to: 'users#new' post 'sign_up', to: 'users#create' get 'email_sent', to: 'users#email_sent' get 'verify/:code', to: 'users#verify' end end powerful user
  • 8. Monolithic Controllers • Our projects class UsersController ApplicationController def new end def create end def show end ?? def sign_in end def sign_out end def email_sent end def verify end end
  • 9. • UsersController#new • UsersController#create • UsersController#verify • UsersController#show • UsersController#sign_in • UsersController#sign_out • UsersController#email_sent • - break apart controllers ActivationsController [:new, :create, :show] SessionsController [:new, :destroy]
  • 10. Fat Controller class RailsController ApplicationController def create # ... # transaction, association # service logic, etc # Suppose that this method contains 100+ lines of code. end end
  • 11. Fat Controller class RailsController ApplicationController def create active record callback, build object # ... # transaction, association # service logic, etc # Suppose that this method contains 100+ lines of code. end end service objects, lib
  • 12. Controller + lib class ReservationsController ApplicationController def create reservation = Reservation.new ticket = Ticket.new # ticket code generation # ... ticket.code = # ... reservation.transaction do ticket.save! reservation.ticket = ticket reservation.save! end end end 1) to lib?
  • 13. Controller + lib class TicketsController ApplicationController def create ticket = Ticket.new code_generator = CodeGenerator.new ticket.code = code_generator.generate # ... end end ticket need to be coupling with code may miss it?
  • 14. Model + lib class Ticket ActiveRecord::Base # has a code column before_save :generate_code private def generate_code active record callback code_generator = CodeGenerator.new self.code ||= code_generator.generate end end # TicketsController#create ticket = Ticket.create! profit!
  • 15. internal transaction class ReservationsController ApplicationController def create reservation = Reservation.new reservation.transaction do reservation.ticket = Ticket.create! reservation.save! end end end 2) Remove transaction
  • 16. internal transaction class ReservationsController ApplicationController def create reservation = Reservation.new reservation.ticket.build reservation.save! end end association
  • 17. Service Object class ReservationsController ApplicationController def create result = CreateReservationService.new.execute end end ServiceObject
  • 19. PHPitis • Do you know PHP? % if current_user (current_user == @post.user || @post.editors.include?(current_user)) @post.editable? @post.user.active? % %= link_to 'Edit this post', edit_post_url(@post) % % end %
  • 20. Useful accessors to model • Post#editable_by? (not a helper method) % if @post.editable_by?(current_user) % %= link_to 'Edit this post', edit_post_url(@post) % % end %
  • 21. Useful accessors to model • Our project module Admin::UsersHelper def pretty_phone_number(phone_number) return unless phone_number # prettify logic prettified end def pretty_rails # ... end %= pretty_phone_number(user.phone_number) %
  • 22. Useful accessors to model • Decorate a user class User ActiveRecord::Base # recommend to use draper def display_phone_number return unless phone_number # prettify logic prettified end end %= user.display_phone_number %
  • 23. content_for? • named yield block html head %= yield :head % /head body %= yield % /body /html % content_for :head do % titleA simple page/title % end % pHello, Rails!/p
  • 24. Extract into Custom Helpers • Markup Helpers def rss_link(project = nil) link_to Subscribe to these #{project.name if project} alerts., alerts_rss_url(project), :class = feed_link end div class=feed %= rss_link(@project) % /div
  • 25. Extract into Custom Helpers • Our project def nav_link_to (text, link) active = active if current_page?(link) content_tag :li, class: active do link_to text, link end end ul class=nav nav-pills nav-stacked col-md-3 pull-left %= nav_link_to Unread, notifications_path % %= nav_link_to All Notifications, notifications_all_path % /ul
  • 26. Voyeuristic Models • Situation class Invoice ActiveRecord::Base belongs_to :customer end class Customer ActiveRecord::Base has_one :address has_many :invoice end class Address ActiveRecord::Base belongs_to :customer end %= @invoice.customer.address.city %
  • 27. Voyeuristic Models • Law of Demeter • No method chaining (Down coupling) • Basic refactoring of OOP (why getter, setter?) • Not only for rails
  • 28. Voyeuristic Models • General way class Invoice ActiveRecord::Base # ... def customer_city customer.city end end class Customer ActiveRecord::Base # ... def city address.city end end %= @invoice.customer_city %
  • 29. Voyeuristic Models class Customer ActiveRecord::Base def city address.city end def street address.street end def state address.state end # many fields below end ??
  • 30. Voyeuristic Models • Refactoring using delegate (Rails way) class Customer ActiveRecord::Base # ... delegate :street, :city, :state, to: :address end class Invoice ActiveRecord::Base # ... delegate :city, to: :customer, prefix: true end %= @invoice.customer_city %
  • 31. Voyeuristic Models • Furthermore • http://blog.revathskumar.com/2013/08/rails-use- delegates-to-avoid-long-method-chains. html • http://simonecarletti.com/blog/2009/12/inside-ruby- on-rails-delegate/ • http://blog.aliencube.org/ko/2013/12/06/law-of-demeter- explained/
  • 32. Spaghetti SQL class RemoteProcess ActiveRecord::Base def self.find_top_running_processes(limit = 5) find(:all, :conditions = state = 'Running', :order = percent_cpu desc, :limit = limit) end end Reusability?
  • 33. Spaghetti SQL class RemoteProcess ActiveRecord::Base scope :running, where(:state = 'Running') scope :system, where(:owner = ['root', 'mysql']) scope :sorted, order(percent_cpu desc) scope :top, lambda {|l| limit(l) } end RemoteProcess.running.sorted.top(5) RemoteProcess.running.system.sorted.top(5) Reusability!
  • 34. Spaghetti SQL class RemoteProcess ActiveRecord::Base scope :running, where(:state = 'Running') scope :system, where(:owner = ['root', 'mysql']) scope :sorted, order(percent_cpu desc) scope :top, lambda {|l| limit(l) } # Shortcut def self.find_top_running_processes(limit = 5) running.sorted.top(limit) end end
  • 35. Scope vs Class method • Almost same, but scopes are always chainable class Post ActiveRecord::Base def self.status(status) where(status: status) if status.present? end def self.recent limit(10) end end Post.status('active').recent Post.status('').recent Post.status(nil).recent nil
  • 36. Scope vs Class method • Almost same, but scopes are always chainable class Post ActiveRecord::Base scope :status, - status { where(status: status) if status.present? } scope :recent, limit(10) end Post.status('active').recent Post.status('').recent Post.status(nil).recent just ignored
  • 37. Spaghetti SQL • Further reading • http://blog.plataformatec.com.br/2013/02/ active-record-scopes-vs-class-methods/
  • 38. Fat Model • Use extend, include module • example: too many scope, finder, etc.
  • 39. Fat Model • ledermann/unread module Unread module Readable module Scopes def join_read_marks(user) # ... end def unread_by(user) # ... end # ... end end end class SomeReadable ActiveRecord::Base # ... extend Unread::Readable::Scopes end
  • 40. Fat Model • Do you prefer composition to inheritance?
  • 41. Fat Model • Further Reading • http://blog.codeclimate.com/blog/ 2012/10/17/7-ways-to-decompose-fat-activerecord- models/
  • 42. Duplicate Code Duplication • Basic of refactoring • Extract into modules • included, extended • using metaprogramming
  • 43. Extract into modules class Car ActiveRecord::Base validates :direction, :presence = true validates :speed, :presence = true def turn(new_direction) self.direction = new_direction end def brake self.speed = 0 end def accelerate self.speed = [speed + 10, 100].min end # Other, car-related activities... end class Bicycle ActiveRecord::Base validates :direction, :presence = true validates :speed, :presence = true def turn(new_direction) self.direction = new_direction end def brake self.speed = 0 end def accelerate self.speed = [speed + 1, 20].min end end
  • 44. Extract into modules module Drivable extend ActiveSupport::Concern included do validates :direction, :presence = true validates :speed, :presence = true end def turn(new_direction) self.direction = new_direction end def brake self.speed = 0 end def accelerate self.speed = [speed + acceleration, top_speed].min end end
  • 45. Write a your gem! (plugin) ex) https://github.com/FeGs/read_activity module Drivable extend ActiveSupport::Concern included do validates :direction, :presence = true validates :speed, :presence = true end def turn(new_direction) self.direction = new_direction end def brake self.speed = 0 end def accelerate self.speed = [speed + acceleration, top_speed].min end end ‘drivable’ gem
  • 46. Write a your gem! (plugin) module DrivableGem def self.included(base) base.extend(Module) end module Module def act_as_drivable include Drivable end end end ActiveRecord::Base.send(:include, DrivableGem)
  • 47. Write a your gem! (plugin) class Car ActiveRecord::Base act_as_drivable end
  • 48. How about Metaprogramming? class Purchase ActiveRecord::Base validates :status, presence: true, inclusion: { in: %w(in_progress submitted ...) } # Status Finders scope :all_in_progress, where(status: in_progress) # ... # Status def in_progress? status == in_progress end # ... end
  • 49. How about Metaprogramming? class Purchase ActiveRecord::Base STATUSES = %w(in_progress submitted ...) validates :status, presence: true, inclusion: { in: STATUSES } STATUSES.each do |status_name| scope all_#{status_name}, where(status: status_name) define_method #{status_name}? do status == status_name end end end How to improve reusability?
  • 50. How about Metaprogramming? class ActiveRecord::Base def self.has_statuses(*status_names) validates :status, presence: true, inclusion: { in: status_names } status_names.each do |status_name| scope all_#{status_name}, where(status: status_name) define_method #{status_name}? do status == status_name end end end end Use extension! class Purchase ActiveRecord::Base has_statuses :in_progress, :submitted, # ... end
  • 51. Fixture Blues • Rails fixture has many problems: • No validation • Not following model lifecycle • No context • …
  • 52. Make Use of Factories • Rails fixture has many problems: • No validation • Not following model lifecycle • No context • …
  • 53. Make Use of Factories module Factory class self def create_published_post post = Post.create!({ body: lorem ipsum, title: published post title, published: true }) end def create_unpublished_post # ... end end end
  • 54. Make Use of Factories: FactoryGirl Factory.sequence :title do |n| Title #{n} end Factory.define :post do |post| post.body lorem ipsum post.title { Factory.next(:title) } post.association :author, :factory = :user post.published true end Factory(:post) Factory(:post, :published = false)
  • 55. Make Use of Factories • Rails fixture has many problems: • No validation • Not following model lifecycle • No context • …
  • 56. Refactor into Contexts context A dog do setup do @dog = Dog.new end should bark when sent #talk do assert_equal bark, @dog.talk end context with fleas do setup do @dog.fleas Flea.new @dog.fleas Flea.new end should scratch when idle do @dog.idle! assert @dog.scratching? end
  • 57. Refactor into Contexts: rspec • context is alias of describe describe #bark do before(:each) do @dog = Dog.new end context sick dog do before(:each) do @dog.status = :sick end # ... end end
  • 58. Messy Migrations • You should ensure that your migrations never irreconcilably messy. • Never Modify the up Method on a Committed Migration : obviously • Always Provide a down Method in Migrations
  • 59. Never Use External Code in a Migration class AddJobsCountToUser ActiveRecord::Migration def self.up add_column :users, :jobs_count, :integer, :default = 0 Users.all.each do |user| user.jobs_count = user.jobs.size user.save end end If No User, No Job? def self.down remove_column :users, :jobs_count end end
  • 60. Never Use External Code in a Migration class AddJobsCountToUser ActiveRecord::Migration def self.up add_column :users, :jobs_count, :integer, :default = 0 update(-SQL) UPDATE users SET jobs_count = ( SELECT count(*) FROM jobs WHERE jobs.user_id = users.id ) SQL end def self.down remove_column :users, :jobs_count end end No dependancy
  • 61. Never Use External Code in a Migration class AddJobsCountToUser ActiveRecord::Migration class Job ActiveRecord::Base end class User ActiveRecord::Base has_many :jobs end def self.up add_column :users, :jobs_count, :integer, :default = 0 User.reset_column_information Users.all.each do |user| Provide definition internally Alternative to raw SQL user.jobs_count = user.jobs.size user.save end end # ... end
  • 62. Never Use External Code in a Migration • Further Reading • http://railsguides.net/change-data-in-migrations- like-a-boss/ • https://github.com/ajvargo/data-migrate • https://github.com/ka8725/migration_data
  • 63. EOF