active record basics

72
Active Record Basics RoR Lab BiWeekly Lecture 남승균 - RoR Lab

Upload: seungkyun-nam

Post on 20-Jul-2015

178 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: Active record basics

Active Record BasicsRoR Lab BiWeekly Lecture

남승균 - RoR Lab

Page 2: Active record basics

모든 초고는 쓰레기다- 어네스트 헤밍웨이

2/72

Page 3: Active record basics

먼저 소설가가 되어야만 소설을 쓸 수 있는 게 아니라 먼저뭔가를 써야만 소설가가 될 수 있다.- 김연수, <소설가의 일> 중

3/72

Page 4: Active record basics

'초고' -> '처음 작성한 코드''소설' -> '프로그램(코드)''소설가' -> '프로그래머'로 치환하면?

작동하는 코드를 만들고, 그 코드를 점진적으로 개선하는 일- <프로그래머(개발자)의 일>

4/72

Page 5: Active record basics

AgendaActive Record: IntroductionCreating Active Record ModelCRUD: Reading and Writing DataConvention in Active RecordOverriding the Naming ConventionsMigrations : 살짝 맛보기Validations : 살짝 맛보기Callbacks : 살짝 맛보기

········

5/72

Page 6: Active record basics

Active Record: IntroductionWhat is Active Record

Rails MVC 중 'M(Model)'의 역할을 담당비즈니스 데이터와 로직을 다루는 역할을 하는 시스템 레이어ORM(Object Relational Mapping)의 Active Record 패턴을 구현한 구현체

···

6/72

Page 7: Active record basics

Active Record: IntroductionThe Active Record Pattern

Patterns of Enterprise Application Architecture, by Martin Fowler

Data와 Behavior를 Object가 보유, 관리+ Data access logic을 도메인 오브젝트가 수행

··

7/72

Page 8: Active record basics

Active Record: Introductionas an ORM Framework

표현(Represents):

검증(Validates):

수행(Performs):

·모델(Model)과 데이터를 표현모델간의 연관관계(associations)를 표현관련 모델을 통한 상속 계층(inheritance hierachies)를 표현

···

·데이터베이스에 저장하기 전 모델을 검증·

·객체지향(Object-Oriented) 방식으로 데이터베이스 명령을 수행·

8/72

Page 9: Active record basics

ORM Huddle

ORM frameworks need

A lot of "CONFIGURATION CODE"in general

9/72

Page 10: Active record basics

SolutionRails Way

Convention over ConfigurationFollow the conventions adopted by Rails

very little configurationno configuration in some case

··

10/72

Page 11: Active record basics

Creating Active Record ModelPreparing MySQL Database

CREATE DATABASE ar_basics_development;CREATE TABLE products ( id int(11) NOT NULL auto_increment, name varchar(255), vender varchar(255), PRIMARY KEY (id))

SQL

Table 명이 products (복수형: Plural Form)인 것에 유의Naming Convention과 Customizing은 뒤에서 다룰 예정

··

11/72

Page 12: Active record basics

Creating Active Record ModelPreparing Rails Application

rails new ar_basics SHELL

# in config/database.ymldevelopment: adapter: mysql2 encoding: utf8 database: ar_basics_development username: root password:

YML

12/72

Page 13: Active record basics

Creating Active Record ModelComnecting to MySQL

# in Gemfilegem "mysql2"

bundle install SHELL

13/72

Page 14: Active record basics

Creating Active Record ModelCreating Model

# in app/models/product.rbclass Product < ActiveRecord::Baseend

RUBY

Model 명이 product (단수형: Singular Form)인 것에 유의·

14/72

Page 15: Active record basics

CRUD: Reading and Writing DataRunning Rails Console

# in {RAILS_ROOT}rails console# orrails c

SHELL

레일스 애플리케이션과 상호작용웹사이트를 이용하지 않고 서버의 데이터를 빠르게 변경

··

15/72

Page 16: Active record basics

CRUD: Reading and Writing DataCreate

# Using create methodproduct = Product.create(name: "iPhone 6", vender: "Apple")

RUBY

새 모델을 만들어 반환데이터베이스에 저장

··

16/72

Page 17: Active record basics

CRUD: Reading and Writing DataCreate

# Using new methodproduct = Product.newproduct.name = "iPhone 6"product.vender = "Apple"

product.save

RUBY

새 모델을 만들어 반환save 메서드가 호출되기 전까지는 데이터베이스에 저장되지 않음

··

17/72

Page 18: Active record basics

CRUD: Reading and Writing DataCreate

# Using new method with blockproduct = Product.new do |p| p.name = "iPhone 6" p.vender = "Apple"end

product.save

RUBY

새 모델을 만들어 반환save 메서드가 호출되기 전까지는 데이터베이스에 저장되지 않음

··

18/72

Page 19: Active record basics

CRUD: Reading and Writing DataRead

# return a collection with all productsproducts = Product.all

RUBY

# => equivalent to:SELECT `products`.* FROM `products`

SQL

products 테이블 내 모든 데이터 컬렉션을 반환·

19/72

Page 20: Active record basics

CRUD: Reading and Writing DataRead

count = Product.count RUBY

# => equivalent to:SELECT COUNT(*) FROM `products`

SQL

products 테이블 데이터 개수를 반환·

20/72

Page 21: Active record basics

CRUD: Reading and Writing DataRead

# return the first productproduct = Product.first

RUBY

# => equivalent to:SELECT `products`.* FROM `products` ORDER BY `products`.`id` ASC LIMIT 1

SQL

products 테이블 내 첫 번째 데이터를 반환ORDER BY id ASC

··

21/72

Page 22: Active record basics

CRUD: Reading and Writing DataRead

# return the last productproduct = Product.last

RUBY

# => equivalent to:SELECT `products`.* FROM `products` ORDER BY `products`.`id` DESC LIMIT 1

SQL

products 테이블 내 마지막 데이터를 반환ORDER BY id DESC

··

22/72

Page 23: Active record basics

CRUD: Reading and Writing DataRead

# Using find methodproduct = Product.find(1)

RUBY

# => equivalent to:SELECT `products`.* FROM `products` WHERE `products`.`id` = 1 LIMIT 1

SQL

products 테이블 내 Primary Key 가 1인 레코드 불러오기·

23/72

Page 24: Active record basics

CRUD: Reading and Writing DataRead

# using find_by_{column_name} methodiphone6 = Product.find_by_name('iPhone 6')

RUBY

# => equivalent to:SELECT `products`.* FROM `products` WHERE `products`.`name` = 'iPhone 6' LIMIT 1

SQL

name이 'iPhone 6'인 레코드 중첫 번째 것을 가져옴

··

24/72

Page 25: Active record basics

CRUD: Reading and Writing DataRead

# using where and order clauseapple_products = Product.where(vender: 'Apple').order("name ASC")

RUBY

# => equivalent to:SELECT `products`.* FROM `products` WHERE `products`.`vender` = 'Apple' ORDER BY name ASC

SQL

vender가 'Apple'인 레코드 컬렉션을name 컬럼의 오름차순(ASC)으로 가져옴

··

25/72

Page 26: Active record basics

Further Reading:

Active Record Query Interface

26/72

Page 27: Active record basics

CRUD: Reading and Writing DataWait... We need price column on products table

ALTER TABLE products ADD COLUMN price int(11); SQL

27/72

Page 28: Active record basics

CRUD: Reading and Writing DataUpdate

iphone6 = Product.find_by_name('iPhone 6')iphone6.price = 850000iphone6.save

RUBY

name이 'iPhone 6'인 첫 번째 레코드를 불러 와서price 컬럼을 850000으로 설정하고저장

···

28/72

Page 29: Active record basics

CRUD: Reading and Writing DataUpdate

iphone6 = Product.find_by_name('iPhone 6')iphone6.update(price: 850000)

RUBY

update 메서드를 이용하는 방법·

29/72

Page 30: Active record basics

CRUD: Reading and Writing DataBulk Update using update_all method

Product.update_all "price = price + 50000" RUBY

products 테이블 내 모든 레코드의 price를50000원 인상

··

30/72

Page 31: Active record basics

CRUD: Reading and Writing DataDelete

product = Product.find_by_name('iPhone 6')product.destroy

RUBY

name이 'iPhone 6'인 첫 번째 레코드를 불러 와서삭제

··

31/72

Page 32: Active record basics

Live Coding

32/72

Page 33: Active record basics

Convention in Active RecordNaming Convention

Table (Database) - 언더스코어(_)로 단어 사이를 구분한 복수형Model (Class) - 각 단어의 첫 문자를 대문자로 표기한 단수형

··

33/72

Page 34: Active record basics

Convention in Active RecordNaming Convention - By Example

Model / Class Table / Schema

Post posts

BookClub book_clubs

Deer deer

Mouse mice

Person people

34/72

Page 35: Active record basics

Convention in Active RecordSchema Conventions

Column Name (Pattern) Use

id (by default) Primary Key

(singularized_table_name)_id Foreign Key

35/72

Page 36: Active record basics

Convention in Active RecordSchema Conventions - Optional

Column Name (Pattern) Use

created_at Timestamp

updated_at Timestamp

lock_version Optimistic Locking

type Single Table Inheritance

(association_name)_type Polymorphic Association

(table_name)_count Cache the Number fo Belonging Objects on Associations

36/72

Page 37: Active record basics

Convention in Active RecordUsing Timestamps

ALTER TABLE products ADD COLUMN created_at datetime;ALTER TABLE products ADD COLUMN updated_at datetime;

SQL

created_at : 레코드가 최초 생성될 때 현재 날짜와 시간을 설정updated_at : 레코드가 갱신될 때마다 현재 날짜와 시간을 설정

··

37/72

Page 38: Active record basics

Overriding the Naming ConventionWhen

Need to Follow a Different Naming ConventionRails Application with a Legacy Database

··

38/72

Page 39: Active record basics

Overriding the Naming ConventionExample

CREATE TABLE `book` ( `book_id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(255) DEFAULT NULL, `description` text, PRIMARY KEY (`book_id`))

SQL

39/72

Page 40: Active record basics

Overriding the Naming ConventionSet Custom Table Name

class Book < ActiveRecord::Base self.table_name = "book"end

RUBY

use ActiveRecord::Base.table_name= method·

40/72

Page 41: Active record basics

Overriding the Naming ConventionSet Custom Primary Key

class Book < ActiveRecord::Base self.table_name = "book" self.primary_key = "book_id"end

RUBY

use ActiveRecord::Base.primary_key= method·

41/72

Page 42: Active record basics

Live Coding

42/72

Page 43: Active record basics

MigrationDefinition

일관성 있고쉬운 방식으로데이터베이스를 변경할 수 있는편리한 방법

····

43/72

Page 44: Active record basics

MigrationCreate New Model with Rails Command

# rails generate model {ModelName} [{column_name}:{type} [...]]rails generate model User name:string

TERMINAL

invoke active_record create db/migrate/20150131045821_create_users.rb create app/models/user.rb invoke test_unit create test/models/user_test.rb create test/fixtures/users.yml

OUTPUT

migrate 파일을 생성 (db/migrate 디렉터리)model 클래스를 생성 (app/model 디렉터리)테스트 유닛을 생성 (test 디렉터리)schema.rb 파일을 최신으로 갱신

····

44/72

Page 45: Active record basics

MigrationMigration File (crete_table)

# in db/migrate/20150131045821_create_users.rbclass CreateUsers < ActiveRecord::Migration def change create_table :users do |t| t.string :name

t.timestamps end endend

RUBY

45/72

Page 46: Active record basics

MigrationExecute Migration

rake db:migrate TERMINAL

== 20150131045821 CreateUsers: migrating ======================================-- create_table(:users) -> 0.0158s== 20150131045821 CreateUsers: migrated (0.0159s) =============================

OUTPUT

rake db:migrate현재까지 수행하지 않은 마이그레이션을 일괄 수행rake db:rollback으로 마이그레이션 수행 취소 가능schema_migrations 테이블 내에서 migration version을 관리

····

46/72

Page 47: Active record basics

MigrationGenerate Migration

# rails generate migration {MigrationName} [{column_name}:{type} [...]]rails generate migration AddAgeAndJobToUsers age:integer job:string

TERMINAL

invoke active_record create db/migrate/20150131052039_add_age_and_job_to_users.rb

OUTPUT

migrate 파일을 생성 (db/migrate 디렉터리)·

47/72

Page 48: Active record basics

MigrationMigration Naming Convention

source: Head First Rails

48/72

Page 49: Active record basics

MigrationMigration File

# in db/migrate/20150131052039_add_age_and_job_to_users.rbclass AddAgeAndJobToUsers < ActiveRecord::Migration def change add_column :users, :age, :integer add_column :users, :job, :string endend

RUBY

49/72

Page 50: Active record basics

MigrationExecute Migration

rake db:migrate TERMINAL

== 20150131052039 AddAgeAndJobToUsers: migrating ==============================-- add_column(:users, :age, :integer) -> 0.0220s-- add_column(:users, :job, :string) -> 0.0168s== 20150131052039 AddAgeAndJobToUsers: migrated (0.0389s) =====================

OUTPUT

50/72

Page 51: Active record basics

MigrationWhenever you need to alter Database

migrate를 만들고rake db:migrate

··

51/72

Page 52: Active record basics

참 쉽죠?

52/72

Page 53: Active record basics

하나만 더 해 봅시다.

53/72

Page 54: Active record basics

MigrationGenerate New Model with Relationship

rails generate model TodoItem user:references title:string memo:text TERMINAL

invoke active_record create db/migrate/20150131054248_create_todo_items.rb create app/models/todo_item.rb invoke test_unit create test/models/todo_item_test.rb create test/fixtures/todo_items.yml

OUTPUT

54/72

Page 55: Active record basics

MigrationExecute Migration

rake db:migrate TERMINAL

== 20150131054248 CreateTodoItems: migrating ==================================-- create_table(:todo_items) -> 0.0444s== 20150131054248 CreateTodoItems: migrated (0.0445s) =========================

OUTPUT

55/72

Page 56: Active record basics

MigrationModify Models

# in app/model/todo_item.rbclass TodoItem < ActiveRecord::Base belongs_to :userend

RUBY

# in app/model/user.rbclass User < ActiveRecord::Base has_many :todo_items, dependent: :destroyend

RUBY

User 모델과 TodoItem 간에 1:다 관계를 맺고User 모델이 삭제될 때, 연관된 TodoItem들도 삭제되도록 dependent를 지정

··

56/72

Page 57: Active record basics

Live Coding

57/72

Page 58: Active record basics

Further Reading:

Active Record Migrations

58/72

Page 59: Active record basics

ValidationsWhat is Validations?

모델이 데이터베이스에 저장되기 전에모델 상태의 유효성을 검증

··

59/72

Page 60: Active record basics

ValidationsSimple Example

# in app/model/user.rbclass User < ActiveRecord::Base validates :name, presence: trueend

RUBY

User.create # => falseUser.create! # => ActiveRecord::Record Invalid: Validation failed: Name can't be blank

RUBY

create, save, update 등 저장 명령이 수행될 때=> 유효성 검증이 실패하면 false를 반환, 실제 데이터베이스에 저장되지 않음Bang 메서드(create!, save!, update!)의 경우=> 보다 엄격한 검사를 수행: 실패시 ActiveRecord::RecordInvalid 예외를 일으킴

····

60/72

Page 61: Active record basics

Validations언제 유효성을 검증하는가?

method ! method

create create!

save save!

update update!

61/72

Page 62: Active record basics

ValidationsSkipping Validations (1)

method

decrement!

decrement_counter

increment!

increment_counter

toggle!

touch

increment!

62/72

Page 63: Active record basics

ValidationsSkipping Validations (2)

method

update_all

update_attribute

update_column

update_columns

update_counters

63/72

Page 64: Active record basics

ValidationsSkipping Validations (3)

User.save(validate: false) RUBY

save 메서드의 경우 validate: false와 함께 수행하면 검증 절차를 건너뜀매우 유의하여 사용하여야 함

··

64/72

Page 65: Active record basics

Further Reading:

Active Record Validations

65/72

Page 66: Active record basics

CallbacksWhat is Callbacks?

Active Record Object 생애 주기상의 특정 시점을 후킹해당 상태의 시점에서 응용프로그램 혹은 객체의 데이터를 제어

··

66/72

Page 67: Active record basics

CallbacksCreating an Object

Available Callbacks

before_validation

after_validation

before_save

around_save

before_create

around_create

after_create

after_save

67/72

Page 68: Active record basics

CallbacksUpdating an Object

Available Callbacks

before_validation

after_validation

before_save

around_save

before_update

around_update

after_update

after_save

68/72

Page 69: Active record basics

CallbacksDestroying an Object

Available Callbacks

before_destroy

around_destroy

after_destroy

69/72

Page 70: Active record basics

CallbacksSequence of Active Record Callbacks

source: Active Record in Rails 4

70/72

Page 71: Active record basics

Further Reading:

Active Record Callbacks

71/72

Page 72: Active record basics

<Thank You!>To Be Continued...