🚀
Growth log
  • About me
  • I LEARNED
    • General
      • 개발자 꿀팁
      • 그로스해킹 기초
      • 개발자에게 도메인 지식은 얼마나 중요할까?
      • DTO 논쟁에 대하여
      • MSA란?
    • Seminar
      • 테스트 커버리지 100% - SLASH 21
      • TDD가 실패하는 이유 - by 이규원님
      • 대규모 트래픽 애플리케이션 성능 튜닝 노하우 다 알려 드림|라인개발실록
      • 결제 시스템의 SDK와 API 디자인 - SLASH 21
    • Web
      • SOP와 CORS
    • Spring & OOP
      • DTO vs VO
    • Ruby On Rails
      • Rails lib 디렉토리에 대하여
      • Rails의 concerns란?
      • Rails에서의 GC 작동원리
      • Eager loading vs Lazy loading
      • Rails 환경 구성
      • ActionCable
      • 📔Perfect ruby on rails
        • MVC 패턴인 Rails
        • Ruby on Rails 기본 - 컨트롤러
        • Ruby on Rails 기본 - 뷰
        • Ruby on Rails 기본 - 모델
        • 스캐폴딩 기능을 사용한 Rails 개발 기초
        • 뷰 개발
        • 모델 개발
        • 모델 개발 - 낙관적 동시 실행 제어
        • 모델 개발 - 유효성 검사 구현
        • 모델 개발 - Association
        • 모델 개발 - 콜백
        • 모델 개발 - 마이그레이션
        • 모델 개발 - 데이터 초기화
        • 컨트롤러 개발 - 요청 정보 추출
        • 컨트롤러 개발 - 응답
        • 컨트롤러 개발 - 상태 관리
        • 라우팅 - RESTful
        • 라우팅 - RESTful 인터페이스의 사용자 정의화
        • 라우팅 - RESTful 하지 않은 라우트 정의
        • 테스트
        • 테스트 - 준비
        • 테스트 - Unit 테스트
        • 테스트 - Functional 테스트
        • 테스트 - Integration 테스트
        • 클라이언트 개발 - Sprockets vs Webpacker
        • 클라이언트 개발 - Sprockets
    • Node.js & Express
      • 기본 개념
      • npx
    • Programing Language
      • Java
        • JavaDoc에 대해
        • invocation에 대해서
        • 어노테이션
        • 추상클래스 & 인터페이스
        • Package
        • 오버로딩 vs 오버라이딩
      • Javascript
        • TCP School 훑어보기
          • 타입
          • 형 변환
          • 변수
          • 연산자
          • 반복문
          • 배열(array)
          • 함수
          • 함수 - 스코프와 호이스팅
          • 함수 - 매개변수와 인수
          • 함수 - 미리 정의된 전역 함수
          • 객체
          • 프로토타입
          • DOM
          • BOM - Window 객체
          • 이벤트(event)
      • Ruby
        • 📔퍼펙트 루비
    • DB
      • Redis
        • Redis 개요
      • Index(인덱스)?
      • DB Transaction & Lock
      • 동시성 제어에 관하여
      • Lock(잠금)이란?
      • ActiveRecord lock vs with_lock
      • Table lock vs Row lock
      • WHERE 1=1 구문에 대하여
      • COUNT(*) vs COUNT(indexed column)
      • 📕관계형 데이터베이스 실전입문
      • 📔SQL 첫걸음
      • 📔모두의 SQL
    • Design Patterns
      • Observer pattern
      • Flyweight pattern
      • Singleton pattern
    • OOP
      • 📔오브젝트
        • 6장 메시지와 인터페이스
      • 클래스간 관계 간단 정리
    • Regex
    • Collaboration
      • Git
      • Sourcetree
  • DAILY REVIEW
    • 2021
      • August
        • 2021-08-25(Wed)
        • 2021-08-23(Mon)
        • 2021-08-11(Wed)
        • 2021-08-04(Wed)
        • 2021-08-03(Tue)
        • 2021-08-02(Mon)
      • July
        • 2021-07-29(Thu)
        • 2021-07-26(Mon)
        • 2021-07-23(Fri)
        • 2021-07-22(Thu)
        • 2021-07-21(Wed)
        • 2021-07-20(Tue)
        • 2021-07-19(Mon)
        • 2021-07-15(Thu)
        • 2021-07-14(Wed)
        • 2021-07-13(Tue)
        • 2021-07-12(Mon)
      • June
        • 2021-06-05(Sat)
        • 2021-06-04(Fri)
        • 2021-06-03(Thu)
        • 2021-06-02(Wed)
        • 2021-06-01(Tue)
      • May
        • 2021-05-31(Mon)
        • 2021-05-29(Sat)
        • 2021-05-28(Fri)
        • 2021-05-27(Thu)
        • 2021-05-26(Wed)
        • 2021-05-25(Tue)
        • 2021-05-24(Mon)
        • 2021-05-22(Sat)
        • 2021-05-21(Fri)
        • 2021-05-20(Thu)
        • 2021-05-19(Wed)
        • 2021-05-18(Tue)
        • 2021-05-17(Mon)
        • 2021-05-15(Sat)
        • 2021-05-13(Thu)
        • 2021-05-12(Wed)
        • 2021-05-11(Tue)
        • 2021-05-10(Mon)
        • 2021-05-03(Mon)
      • April
        • 2021-04-30(Fri)
        • 2021-04-29(Thu)
        • 2021-04-28(Wed)
        • 2021-04-27(Tue)
        • 2021-04-26(Mon)
        • 2021-04-24(Sat)
        • 2021-04-23(Fri)
        • 2021-04-21(Wed)
        • 2021-04-20(Tue)
        • 2021-04-19(Mon)
        • 2021-04-18(Sun)
        • 2021-04-16(Fri)
        • 2021-04-15(Thu)
        • 2021-04-14(Wed)
        • 2021-04-12(Mon)
        • 2021-04-11(Sun)
        • 2021-04-09(Fri)
        • 2021-04-08(Thu)
        • 2021-04-06(Tue)
        • 2021-04-05(Mon)
        • 2021-04-04(Sun)
        • 2021-04-03(Sat)
        • 2021-04-02(Fri)
        • 2021-04-01(Thu)
      • March
        • 2021-03-29(Mon)
        • 2021-03-28(Sun)
        • 2021-03-26(Fri)
        • 2021-03-25(Thu)
        • 2021-03-24(Wed)
        • 2021-03-23(Tue)
        • 2021-03-22(Mon)
        • 2021-03-21(Sun)
        • 2021-03-20(Sat)
        • 2021-03-17(Wed)
        • 2021-03-16(Tue)
        • 2021-03-15(Mon)
        • 2021-03-12(Fri)
        • 2021-03-11(Thu)
        • 2021-03-10(Wed)
        • 2021-03-09(Tue)
        • 2021-03-08(Mon)
        • 2021-03-07(Sun)
        • 2021-03-05(Fri)
        • 2021-03-03(Wed)
        • 2021-03-02(Tue)
        • 2021-03-01(Mon)
      • Feb
        • 2021-02-26(Fri)
        • 2021-02-25(Thu)
        • 2021-02-24(Wed)
        • 2021-02-23(Tue)
        • 2021-02-22(Mon)
        • 2021-02-19(Fri)
        • 2021-02-18(Thu)
        • 2021-02-17(Wed)
        • 2021-02-16(Tue)
        • 2021-02-15(Mon)
        • 2021-02-14(Sun)
        • 2021-02-13(Sat)
        • 2021-02-12(Fri)
        • 2021-02-10(Wed)
        • 2021-02-09(Tue)
        • 2021-02-08(Mon)
        • 2021-02-07(Sun)
        • 2021-02-05(Fri)
        • 2021-02-03(Wed)
        • 2021-02-02(Tue)
        • 2021-02-01(Mon)
      • Jan
        • 2021-01-29(Fri)
        • 2021-01-28(Thu)
        • 2021-01-27(Wed)
        • 2021-01-26(Tue)
        • 2021-01-25(Mon)
        • 2021-01-23(Sat)
        • 2021-01-22(Fri)
        • 2021-01-20(Wed)
        • 2021-01-19(Tue)
        • 2021-01-18(Mon)
        • 2021-01-12(Tue)
        • 2020-01-11(Mon)
        • 2021-01-08(Fri)
        • 2021-01-07(Thu)
        • 2021-01-06(Wed)
        • 2021-01-05(Tue)
        • 2021-01-04(Mon)
        • 2021-01-01(Fri)
    • 2020
      • Dec
        • 2020-12-30(Thu)
        • 2020-12-25(Fri)
        • 2020-12-24(Thu)
        • 2020-12-23(Wed)
        • 2020-12-22(Tue)
        • 2020-12-21(Mon)
        • 2020-12-18 (Fri)
      • Nov
        • 2020-11-30(Mon)
        • 2020-11-28(Sat)
        • 2020-11-26(Thu)
        • 2020-11-25(Wed)
        • 2020-11-24(Tue)
        • 2020-11-23(Mon)
        • 2020-11-22(Sun)
        • 2020-11-20(Fri)
        • 2020-11-19(Thu)
        • 2020-11-18(Wed)
        • 2020-11-17(Tue)
        • 2020-11-14(Sat)
        • 2020-11-13(Fri)
        • 2020-11-12(Thu)
        • 2020-11-11(Wed)
        • 2020-11-09(Mon)
        • 2020-11-07(Sat)
        • 2020-11-05(Thu)
        • 2020-11-04(Wed)
        • 2020-11-03(Tue)
        • 2020-11-02(Mon)
    • Good article 아카이빙
Powered by GitBook
On this page

Was this helpful?

  1. I LEARNED
  2. Ruby On Rails
  3. Perfect ruby on rails

모델 개발

모델 클래스가 제대로 동작하는지를 간편하게 확인할 때는 액션 메서드를 일일이 만드는 대신 Rails 콘솔을 이용하면 편하다.

rails console

rails console --sandbox 줄여서 rails console -s 로 콘솔을 실행하면 콘솔을 종료할 때 데이터베이스의 모든 변경사항을 자동으로 롤백하는 것도 가능하다.

참고로 rails runner 명령어를 사용하면 Rails 애플리케이션을 로드한 상태로 코드를 실행하는 것이 가능하다. 오래된 세션 정보를 정기적으로 삭제하는 일괄 처리 등에 사용할 수 있다. 저익적으로 자동 실행하려면 rail runner 명령어를 파일로 만들고 cron 등의 스케줄러에 등록해버리자.

rails runner 'FanComment.where(deleted: true).delete_all'

where 메서드

where 메서드는 조건식에 플레이스홀더(Placeholder)를 사용할 수 있는 방법을 제공한다. 플레이스홀더란, 매개 변수를 두는 장소이다.

아래 예시에서 ?부분이 플레이스홀더다. ? 형태는 '이름 없는 매개변수'라 부른다.

def ph1
  @books = Book.where('publish = ? AND price >= ?', params[:publish], params[:price])

플레이스홀더를 사용하지 않고 조건식을 생성하면 SQL 인젝션 취약성의 원인이 될 수 있으니 주의하자.

조금 코드가 길어지더라도 매개 변수의 대응 관계를 알 수 있도록 '이름 없는 매개변수' 대신 '이름 있는 매개변수'를 쓸 수도 있다.

def ph1
  @books = Book.where('publish = :publish AND price >= :price', params[:publish], params[:price])

unscope 메서드

여러 개의 조건식을 추가한 경우에도 특정한 필드의 조건만 제거하는 것이 가능하다.

def unscope2
  @books = Book.where(pubish: '제이펍', cd: true).order(:price).unscope(where: :cd)
  render 'books/index'
end

none 메서드

none 메서드를 쓰면 Relation(Null Relation) 객체를 만들어 리턴할 수 있다. 아무것도 없는 결과를 출력할 때 그냥 nil 쓰면 each 메서드 같은거 쓸 때 예외가 발생하기 쉽다.

pluck 메서드

여러개 필드를 배열로 추출할 수 있다!

이름있는 스코프

자주 사용하는 조건을 이름 있는 스코프(Named Scope)로 지정할 수 있다.

scope name, -> {exp} 형식으로 아래처럼 지정하면 된다.

class Book < ActiveRecord::Base
  scope :jpub, -> { where(publish: '제이펍') }
  scope :newer, -> { order(published: :desc) }
  #기존 이름 있는 스코프를 기반으로 새로 이름 있는 스코프를 생성할 수도 있다.
  scope :top10, -> { newer.limit(10) } 
end

쓸 때는 아래처럼!

def scope
  @books - Book.jpub.top10
  render 'hello/list'

이름 있는 스코프에 매개 변수를 추가해서 사용할 땐 아래처럼 지정하고

scope :what_new, ->(pub) {
  where(publish: pub).order(published: :desc).limit(5)
}

아래처럼 사용할 수 있다.

@books = Book.whats_new('제이펍')

기본 스코프 정의 - default_scope 정의

모델 관련 메서드를 호출할 때 자동으로 조건이 적용되게 하는 기본 스코프라는 기능이 있다. default_scope 메서드를 이용하면 된다.

기본 스코프를 해제하고 싶은 경우에는 unscoped 메서드를 사용하면 된다.

find_by_sql 메서드

원칙적으로 액티브 레코드는 제공되는 쿼리 메서드를 사용해야 한다. 하지만 넘 복잡한 질의를 날려야하면 find_by_sql로 SQL 명령을 직접 지정한하는게 쉬울 수 있다.

SQL이 익숙하면 find_by_sql이 편할 수 있는데, find_by_sql만 사용하면 특정한 데이터베이스에 의존적이게 될 수 있으니 지양하자.

트랜잭션 처리 - transaction 메서드

트랜잭션 처리는 모든 명령어의 성공 또는 실패를 한꺼번에 모아서 처리하는 것이다. 만약 일련의 명령어 중 처리 실패가 하나라도 있으면 트랜잭션에 등록되어 있던 모든 처리가 '없던 일'이 된다.

def transact
  Book.transaction do
    b1 = Book.new({isbn: '123-4-1234-1234-0',
      title: 'Ruby 포켓 레퍼런스',
      price: 2000, publish: '제이펍', pulished: '2011-01-01'})
    b1.save!
  end
  render text: '트랜젝션에 성공했습니다.'
 rescue => e
  render text: e.message
end

트랜젝션 내부에서 레코드를 저장할 때는 save 메서드 보다 save! 메서드를 사용하는게 편하다. 전자는 성공여부를 boolean을 리턴하여 표시하지만, 후자는 예외를 발생시켜버리기 때문이다.

트랜잭션 분리 레벨 지정

데이터베이스가 분리 레벨 기능을 지원하고 있다면, 트랜잭션 분리 레벨을 지정할 수 있다. 분리 레벨은 여러 개의 트랜잭션을 동시 실행한 경우에 동작을 표시하는 것이다. 분리 레벨이 높으면 그만큼 데이터의 정합성은 높아지지만 동시 실행성은 낮아진다.

여러 개의 트랜잭션 사시에 일어나는 문제는 아래와 같다.

  • 비커밋 읽기 마지막 커밋의 상태 데이터를 다른 트랜잭션이 읽어 들일 수 있음

  • 비반복 읽기 여러 트랜잭션이 여러 번 동일한 데이터를 읽어 들일 때 다른 트랜잭션이 읽어들였던 값도 변화할 수 있음

  • 가상 읽기 여러 번 읽어 들일 때 새로운 데이터가 발생 또는 사라질 수 있음

분리레벨 분류를 레벨이 낮은 순서로 표기하면 아래와 같다.

분리 레벨

비커밋 읽기

비반복 읽기

가상 읽기

:read_uncommitted

발생

발생

발생

:read_committed

-

발생

발생

:repeatable_read

-

-

발생

:serializable

-

-

-

아래처럼 transcation메서드의 isolation 옵션으로 지정한다.

Book.transaction(isolation: :repeatable_read) do
  @book = Book.find(1)
  @book.update(price: 30000)
end
Previous뷰 개발Next모델 개발 - 낙관적 동시 실행 제어

Last updated 4 years ago

Was this helpful?

📔