3. 엑티브 레코드 쿼리
(ACTIVERECORD QUERIES)
SQL injection 공격에 취약할 수 있으므로, 쿼리에서 문자열
보간(string interpolation)을 사용하지 않는다.
# 나쁜 예 - 어떠한 매개변수든지 들어갈 수 있음
Client.where("orders_count = #{params[:orders]}")
# 좋은 예 - 적절한 매개변수만 들어갈 수 있음
Client.where('orders_count = ?', params[:orders])
4. 쿼리에 하나 이상의 플레이스홀더를 사용할 때는 위치로 구분
되는 플레이스홀더 대신 이름을 붙여 사용한다.
# 괜찮은 예
Client.where(
'created_at >= ? AND created_at <= ?',
params[:start_date], params[:end_date]
)
# 좋은 예
Client.where(
'created_at >= :start_date AND created_at <= :end_date',
start_date: params[:start_date], end_date: params[:end_date]
)
5. id를 통해 하나의 값을 조회할 때는 where보다 find를 사용
한다.
# 나쁜 예
User.where(id: id).take
# 좋은 예
User.find(id)
6. 특정 속성을 통해 하나의 값을 조회할 때는 where보단
find_by를 사용한다.
# 나쁜 예
# => ActiveRecord::Relation
User.where(first_name: 'Bruce', last_name: 'Wayne').first
# 좋은 예
User.find_by(first_name: 'Bruce', last_name: 'Wayne')
7. 많은 레코드에 대해 어떤 작업을 해야한다면 find_each를
사용한다.
# 나쁜 예 - 모든 데이터를 한 번에 읽어온다.
# users 테이블이 수천개의 행을 가지고 있다면 매우 비효율적이다.
User.all.each do |user|
NewsMailer.weekly(user).deliver_now
end
# 좋은 예 - 배치(batch) 안에서 레코드를 가져온다.
User.find_each do |user|
NewsMailer.weekly(user).deliver_now
end
8. SQL을 직접 사용하기보다 'where.not'을 사용한다.
# 나쁜 예
User.where("id != ?", id)
# 좋은 예
User.where.not(id: id)
10. 기본 설정 값들은 애플리케이션에서 지정하기보다, 마이그레이
션 자체에 포함시킨다.
# 나쁜 예 - 애플리케이션에서 기본설정 값을 지정하는 예
def amount
self[:amount] or 0
end
11. 테이블의 기본 설정 값을 레일즈 애플리케이션에서만 지정하는
것은 많은 레일즈 개발자들이 제안한 방법이지만, 이는 데이터
를 많은 어플리케이션 버그에 노출시키는 아주 불안정한 접근
방법이다. 그리고 대부분의 중요한 애플리케이션들은 하나의
데이터베이스를 다른 애플리케이션과 공유하기 때문에, 레일즈
애플리케이션을 통해 데이터 무결성을 보장하는 것은 불가능하
다는 사실을 고려해야한다.
12. 외래키 제약을 사용한다. 레일즈 4.2부터 엑티브 레코드는 외
래키 제약을 기본적으로 지원한다.
(테이블이나 컬럼을 추가하는) 구조적인 마이그레이션을 작성
할 때는 up과 down메소드 대신 change메소드를 정의한
다.
13. # 예전 방식
class AddNameToPeople < ActiveRecord::Migration
def up
add_column :people, :name, :string
end
def down
remove_column :people, :name
end
end
14. # 새로운 방식
class AddNameToPeople < ActiveRecord::Migration
def change
add_column :people, :name, :string
end
end
15. 마이그레이션에서 모델 클래스를 사용하지 않는다. 모델 클래
스들은 계속해서 변하기 때문에, 마이그레이션에서 사용한 모
델이 변화하게 되면 마이그레이션 작업이 정상적으로 수행되지
않을 수 있다.
16. 뷰(VIEWS)
뷰에서 직접적으로 모델을 사용하지 않는다.
뷰에서는 절대 복잡한 포맷팅을 만들지 말고, 이러한 포맷팅은
뷰 헬퍼 메소드나 모델로 분리한다.
부분 템플릿(partial template)과 레이아웃을 이용하여 코드
중복을 줄인다.
17. 국제화(INTERNATIONALIZATION)
뷰, 모델, 컨트롤러에서는 지역(locale) 관련 설정이나 문자열
을 바로 사용하지 않는다. 이러한 문자열들은
config/locales디렉터리 아래의 로케일 파일로 옮겨 관
리한다.
엑티브 레코드 모델의 레이블에 대한 번역이 필요할 때는
'activerecord' 아래에 작성한다.
19. 뷰에서 사용되는 엑티브 레코드 속성들에 대한 번역은 분리한
다. models디렉터리에 모델을 위한 로케일 파일들을 저장하
고, 뷰에서 사용하는 텍스트는 views에 저장한다.
20. 로케일(locale) 파일들을 적절한 위치에 저장하기 위해 디렉터
리를 추가로 만들었다면, 이 파일들을 읽어들일 수 있도록
application.rb파일에 설정해야 한다.
# config/application.rb
config.i18n.load_path += dir[rails.root.join('config', 'locales', '**'
21. 날짜나 통화 형식과 같은 공유해서 사용할 수 있는 지역화 옵션
들은 locale바로 아래에 저장한다.
i18n의 짧은 형식의 메소드를 사용한다. i18n.translate
=> i18n.ti18n.localize=> i18n.l
22. 뷰에서 사용되는 텍스트에 대해 게으른 참조(lazy lookup)를
사용한다. 게으른 참조란 번역 텍스트의 구조를 뷰 디렉터리 구
조와 같게 하여, 뷰에서 간단히 번역 텍스트를 참조하는 방법이
다. 예를 들어 다음과 같은 구조가 있다고 하자.
en:
users:
show:
title: 'user details page'
24. 컨트롤러와 모델에서 :scope옵션을 사용하기보다, 점으로
분리된 키를 사용한다. 읽기도 쉽고 계층 구조를 파악하기도 쉽
다.
# 나쁜 예
I18n.t :record_invalid, :scope => [:activerecord, :errors, :messages
# 좋은 예
I18n.t 'activerecord.errors.messages.record_invalid'
레일즈 I18n과 관련된 더 자세한 정보는
를 참고하라.
레일즈 가이드(Rails
Guides)
25. 에셋 (ASSETS)
을 사용하라. 이는 애플리케이션 배포에 필요
한 에셋 파일들을 조직해줄 것이다.
커스텀 스타일시트, 자바스크립트, 이미지는 app/assets
디렉터리 아래에 저장한다.
애플리케이션에 포함되지 않는 직접 작성한 라이브러리들은
lib/assets에 저장한다.
에셋 파이프라인
26. 나 와 같은 서드파티 라이브러리는
vendor/assets에 둔다.
가능하다면 젬으로 만들어진 에셋을 사용한다(예를 들어,
, , ,
).
jQuery bootstrap
jquery-rails jquery-ui-rails bootstrap-sass zurb-
foundation
27. 메일러(MAILERS)
메일러의 이름은 'SomethingMailer' 형식을 따른다. 이러한
접미사가 없다면 메일러 클래스인지 바로 파악하기가 어렵고,
어떠한 뷰에 연결되어 있는지 찾아내기 어렵다.
HTML과 텍스트(plain text) 기반의 두 가지 템플릿을 각각 준
비한다.
참조
28. 개발 환경에서 메일 전송에 실패하면 에러가 발생하도록 설정
한다.
기본 설정 값은 에러가 발생하지 않도록 설정되어 있다.
# config/environments/development.rb
config.action_mailer.raise_delivery_errors = true
29. 개발 환경에서는 와 같은 로컬 SMTP 서버를 사
용한다.
Mailcatcher
# config/environments/development.rb
config.action_mailer.smtp_settings = {
address: 'localhost',
port: 1025,
# more settings
}
30. 호스트의 이름을 기본 설정 값을 지정한다.
# config/environments/development.rb
config.action_mailer.default_url_options = { host: "#{local_ip}:3000"
# config/environments/production.rb
config.action_mailer.default_url_options = { host: 'your_site.com' }
# 메일러 클래스 안에서 설정
default_url_options[:host] = 'your_site.com'
31. 이메일에 사이트의 링크를 넣고 싶다면 _path대신 _url메
소드를 사용한다. _url메소드는 호스트 이름을 같이 반환하
고, _path메소드는 그렇지 않다.
# 나쁜 예
# /coures
You can always find more info about this course
<%= link_to 'here', course_path(@course) %>
# 좋은 예
# http://localhost:3000/courses
You can always find more info about this course
<%= link_to 'here', course_url(@course) %>
32. 보내는 사람(from)과 받는 사람(to)의 이메일 형식을 적절하게
지정한다. 다음 형식을 따른다.
# 메일러 클래스 안에서 설정한다
default from: 'Your Name <info@your_site.com>'
33. 테스트 환경에서는 이메일 전송 메소드를 test로 설정한다.
# config/environments/test.rb
config.action_mailer.delivery_method = :test
34. 개발 및 배포 환경에서는 이메일 전송 메소드가 smtp로 설정
되어 있어야 한다.
# config/environments/development.rb, config/environments/production.rb
config.action_mailer.delivery_method = :smtp
35. html 형식의 이메일을 전송할 때, 일부 클라이언트에서는 외부
스타일시트를 참조할 때 문제가 발생할 수 있기 때문에 css는
모두 인라인으로 작성되어야 한다. 하지만 인라인 스타일을 사
용하면 유지보수가 힘들고 코드 중복이 발생하게 된다. 스타일
과 html을 자동적으로 결합해주는 아래 두 가지 젬이 존재한
다. 와 .premailer-rails roadie
36. 컨트롤러에서 요청에 대한 응답을 처리하는 도중에 이메일을
보내서는 안 된다. 이는 페이지 로딩을 지연시키고, 여러 메일
을 동시에 발송할 때 타임아웃이 될 수도 있다. 이메일 전송은
과 같은 백그라운드 작업을 지원하는 젬을 사용해 이루
어져야 한다.
sidekiq
37. 시간(TIME)
application.rb에 타임존을 적절히 설정한다.
config.time_zone = 'Eastern European Time'
# 아래 옵션에는 :utc나 :local만을 지정할 수 있다. (기본 설정 값은 :utc)
config.active_record.default_timezone = :local
38. Time.parse를 사용하지 않는다.
# 나쁜 예
Time.parse('2015-03-02 19:05:37')
# => 이 메소드는 시스템 타임존에서 시간이 주어진 것으로 가정함
# 좋은 예
Time.zone.parse('2015-03-02 19:05:37')
# => Mon, 02 Mar 2015 19:05:37 EET +02:00
39. Time.now를 사용하지 않는다.
# 나쁜 예
Time.now # => 타임존 설정과 무관하게 시스템의 시간을 반환한다
# 좋은 예
Time.zone.now # => Fri, 12 Mar 2014 22:04:47 EET +02:00
Time.current # 위와 같지만 더 짧은 방법