Backend/RubyOnRails

[RubyOnRails Guides] Active Record Basics

Seyun(Marco) 2021. 2. 17. 09:40
728x90

[RubyOnRails Guides] Active Record Basics

๐Ÿ’ผ ์„œ๋ก 

  • RubyOnRails Guides Active Record Basics ๋ฅผ ์ฐธ๊ณ ํ•ด ์ž‘์„ฑํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.
  • Ruby version์€ 2.6.3์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • Ruby On Rails version์€ 5.2.1์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ˜ฎ Active Record?

  • MVC ํŒจํ„ด ์ค‘ M์— ํ•ด๋‹น ๋˜๋ฉฐ Rails์—์„œ ์ œ๊ณตํ•˜๋Š” ๋ชจ๋“ˆ๋กœ ์ฃผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋กœ์ง์„ ์ œ์–ดํ•˜๋Š”๋ฐ ์žˆ์–ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • Active Record๋Š” ORM(Object Relational Mapping) ๋ฌธ๋ฒ•์„ ํ†ตํ•ด DB๋ฅผ ์ œ์–ดํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

ORM(Object Relational Mapping)

  • ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํ…Œ์ด๋ธ”๊ณผ Model(Object)๋ฅผ ๋งคํ•‘ํ•˜๋Š” ๊ธฐ์ˆ ๋กœ SQL๋ฌธ์„ ์ง์ ‘ ์ž‘์„ฑํ•˜์ง€ ์•Š๊ณ ๋„ DB๋ฅผ ์•ก์„ธ์Šค ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ชจ๋ธ์˜ ์†์„ฑ ๋ฐ ๊ด€๊ณ„๋ฅผ DB์— ์‰ฝ๊ฒŒ ์ €์žฅํ•˜๊ณ  ์กฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ORM์˜ Active Record ํŠน์ง•

  • ๋ชจ๋ธ๊ณผ ๋ฐ์ดํ„ฐ๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค.
  • ๋ชจ๋ธ ๊ฐ„์˜ ์—ฐ๊ด€์„ฑ์„ ๋‚˜ํƒ€๋‚ธ๋‹ค
  • ์ƒ์† ๊ณ„์ธต์„ ๋‚˜ํƒ€๋‚ธ๋‹ค
  • ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
  • ๊ฐ์ฒด ์ง€ํ–ฅ์ ์œผ๋กœ DB ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

๐Ÿ‘ฎโ€โ™€๏ธ Active Record Configuration์˜ ๊ทœ์น™

Naming Convention

  • ๋ชจ๋ธ์€ ๋‹จ์ˆ˜๋กœ DB ํ…Œ์ด๋ธ”์„ ๋ณต์ˆ˜๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ๋ชจ๋ธ์€ ์ฒซ ๊ธ€์ž๋ฅผ ๋Œ€๋ฌธ์ž๋กœ ์‚ฌ์šฉํ•˜๋Š” UpperCamelCase๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ DB์˜ ํ…Œ์ด๋ธ”์€ ๋ชจ๋‘ ์†Œ๋ฌธ์ž๋กœ ์‚ฌ์šฉํ•˜๋ฉด์„œ ๊ฐ ๋‹จ์–ด์˜ ์‚ฌ์ด๋ฅผ ์–ธ๋”๋ฐ”(_)๋กœ ํ•˜๋Š” snake_cate๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
    • ex) Article / articles
    • ex) LineItem / line_items

Schema Convention

  • Foreign keys(์™ธ๋ž˜ํ‚ค)๋Š” [singularized_table_name]_id๋กœ ์•„๋ž˜์˜ ์˜ˆ์‹œ์™€ ๊ฐ™์ด ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

    • order_id
    • article_id
  • Primary Keys

    • ๊ธฐ๋ณธํ‚ค๋Š” id ๋ผ๋Š” ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  • created_at

    • ์ƒ์„ฑ ๋‚ ์งœ
  • updated_at

    • ์ˆ˜์ • ๋‚ ์งœ
  • lock_version

    • ๋‚™๊ด€์  ์ž ๊ธˆ
  • type

    • ๋‹จ์ผ ํ…Œ์ด๋ธ” ์ƒ์†
  • (association_name)_type

    • ๋‹คํ˜•์„ฑ ๊ฐ์ฒด ์ด๋ฆ„
  • (table_name)_count

    • ์—ฐ๊ด€๊ด€๊ณ„(has_many)์— ์†ํ•œ ๊ฐœ์ฒด์˜ ์ˆ˜๋ฅผ ์บ์‹œํ•˜๋Š”๋ฐ ์‚ฌ์šฉ
  • Tip

    • created_at, updated_at์€ Migration ํŒŒ์ผ ์†์— :t.timestemp์— ์˜ํ•ด ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ‘จโ€๐ŸŽจ Active Record Models ์ƒ์„ฑ

  • ApplicationRecord ์ƒ์†ํ•˜๋Š” ์ˆœ๊ฐ„ Active Record๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
class Product < ApplicationRecord
end

Naming Convetion ์žฌ์ •์˜

  • self.table_name ๋กœ ํ…Œ์ด๋ธ” ์ด๋ฆ„์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
class Product < ApplicationRecord
  self.table_name = "my_products"
end
  • text class๋„ ๋ณ€๊ฒฝํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.
class ProductTest < ActiveSupport::TestCase
  set_fixture_class my_products: Product
  fixtures :my_products
  ...
end
  • ๊ธฐ๋ณธ ํ‚ค๋„ ์žฌ์ •์˜ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
class Product < ApplicationRecord
  self.primary_key = "product_id"
end

๐Ÿ“ฆ CRUD - Create

  • ๋ชจ๋ธ๋ช….create() ๋ฅผ ์ด์šฉํ•ด ๋ชจ๋ธ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
user User.create(name: "David", occupation: "Code Artist")
  • new() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ์ฒด๋ฅผ ์ธ์Šคํ„ด์Šคํ™” ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
user = User.new
user.name = "David"
user.occupation = "Code Artist"

user.save
  • save ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ์ €์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ‘“ CRUD - Read

User.all # ๋ชจ๋“  User Model์„ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜
User.first # ์ฒซ๋ฒˆ์งธ User Model์„ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜
User.find_by(name: 'rutgo') #name์„ ์ด์šฉํ•ด ์กฐํšŒํ•˜๋Š” ํ•จ์ˆ˜
User.where(name: 'rutgo', age: 29).order(created_at: :desc) # SELECT ์ฟผ๋ฆฌ์— WHERE ์ ˆ์„ ์ถ”๊ฐ€ํ•˜๊ณ  created_at์„ ์ด์šฉํ•ด ์ •๋ ฌํ•˜๋Š” ํ•จ์ˆ˜

๐Ÿ†™ CRUD - Update

@user = User.find_by(name: 'rutgo');
user.name = 'marco'
user.save
  • ์œ„์™€ ๊ฐ™์ด ์ด๋ฆ„์˜ ํ•„๋“œ๊ฐ’๋งŒ ๋ณ€๊ฒฝํ•˜๊ณ  ๋‹ค์‹œ save๋ฅผ ํ•˜๋ฉด ์ˆ˜์ •์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • ์œ„์˜ ์ฝ”๋“œ๋ฅผ update ํ•จ์ˆ˜๋กœ ์ข€ ๋” ์ค„์ผ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
user = User.find_by(name: 'rutgo')
user.update(name: 'marco')
  • ์—ฌ๋Ÿฌ๊ฐœ๋ฅผ update์„ ํ•  ๊ฒฝ์šฐ update_all ๋ฉ”์„œ๋“œ๊ฐ€ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.
User.update_all "max_login_attempts = 3, must_change_password = 'true'"

โšฐ๏ธ CRUD - Delete

user = User.find_by(name: 'rutgo')
user.destroy
  • ์—ฌ๋Ÿฌ๊ฐœ๋ฅผ ์‚ญ์ œํ•  ๊ฒฝ์šฐ destroy_all ๋ฉ”์„œ๋“œ๊ฐ€ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.
User.where(name: 'rutgo').destroy_all # ํŠน์ • ์กฐ๊ฑด์— ๋งž๋Š” User Model ์‚ญ์ œ
User.destroy_all # ๋ชจ๋“  User Model ์‚ญ์ œ

๐Ÿ‘จโ€โš•๏ธ Validation

  • DB์— ์ €์žฅ๋˜๊ธฐ ์ „์— Model์˜ ์ƒํƒœ๋ฅผ ํ™•์ธํ•ด ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
class User < ApplicationRecord
  validates :name, presence: true
end
  • ์œ„์™€ ๊ฐ™์ด validates๋กœ validationํ•  ํ•„๋“œ์™€ presence๋Š” ๋นˆ๊ฐ’์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ์ข‹์Šค๋นˆ๋‹ค.
  • ๋”ฐ๋ผ์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ์‹คํ–‰ํ•˜๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
user = User.new
user.save # return false
user.save! # Exception
  • save, update ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ validate๋Š” ์‹คํ–‰๋˜๋ฉฐ ์‹คํŒจ ์„ฑ๊ณต์„ true/false๋กœ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค. ์ข€ ๋” ์—„๊ฒฉํ•˜๊ฒŒ Exception์„ ๋ฐœ์ƒ์‹œํ‚ค๊ณ  ์‹ถ๋‹ค๋ฉด save!, update! ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
  • ์ž์„ธํ•œ ๋‚ด์šฉ์€ Active Record Validations ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

โœ’๏ธ Callback

  • Model ๋‚ด์—์„œ ์ด๋ฒคํŠธ๊ฐ€ ์ฒ˜๋ฆฌ ๋˜๊ธฐ ์ „์— ๋‚ด๋ถ€์ ์œผ๋กœ ์–ด๋–ค ์ด๋ฒคํŠธ ๋ฐœ์ƒ ์ „ ๋˜๋Š” ํ›„์— ๊ฒ€์ฆํ•˜๋Š” ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค.
  • ์ฆ‰, SQL ํŠธ๋žœ์žญ์…˜ ์ž‘๋™ ์ „(before) ๋ฐ ํ›„(after)์— ์ž์œ ๋กญ๊ฒŒ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • ์ž์„ธํ•œ ๋‚ด์šฉ์€ Active Record Callback ์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.

๐ŸŽ– Migrations

  • Migration์ด๋ž€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘๊ทผ ๋ฐ ์Šคํ‚ค๋งˆ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํŒŒ์ผ์ž…๋‹ˆ๋‹ค.
  • rails g model ~ ์„ ์‹คํ–‰ํ•˜๋ฉด model๊ณผ Migration ํŒŒ์ผ์ด ์ƒ์„ฑ๋˜๋Š” ๊ฑธ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Migration์€ Table์˜ ๋ช…์„ธ์„œ๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ์ข‹์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ Table๋“ค์˜ Column๋“ค์˜ ๊ทœ์น™ ๋“ฑ์„ ์ •์˜ํ•ด๋†“์Šต๋‹ˆ๋‹ค.
  • Migration์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” rake db:migration / rails db:migration๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
  • ์ค‘๊ฐ„์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์œ„ํ•ด Rollback ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. rake db:rollback
  • ๋˜ํ•œ Migration์€ DB(PostgreSQL, MySQL, Orcle) ๋“ฑ์—์„œ ๋ชจ๋‘ ์ ์šฉ์ด ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ˜ธํ™˜์„ฑ์„ ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
  • ์ž์„ธํ•œ ๋‚ด์šฉ์€ Active Record Migrations ๋ฅผ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”.

๐Ÿ˜‡ ๊ฒฐ๋ก 

  • Rails๋Š” Active Record๋กœ ORM ๊ธฐ๋Šฅ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
  • ์‰ฝ๊ฒŒ DB๊ด€๋ จ ๋กœ์ง๋“ค์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ธฐ๋ณธ์œผ๋กœ ์ œ๊ณต๋˜๋Š” ๋ฉ”์„œ๋“œ๋“ค๋กœ ๊ฐœ๋ฐœ์ž๋“ค์˜ ์ฟผ๋ฆฌ ์ƒ์‚ฐ์„ ์ตœ์†Œํ™”๋ฅผ ํ•ด์ค๋‹ˆ๋‹ค.
  • ๋˜ํ•œ ์ •ํ™•ํ•œ ๋ช…๋ช…๊ทœ์น™์„ ๋ช…์‹œํ•ด๋†“์Œ์œผ๋กœ์จ ๊ฐœ๋ฐœ์ž๋“ค๊ฐ„์˜ ์†Œํ†ต์„ ์ข€ ๋” ์œ ์šฉํ•˜๊ฒŒ ํ•ด์ฃผ๋Š”๊ฒƒ ๊ฐ™๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹์„ ํ†ตํ•ด Query Method๊ฐ€ ๊ฐ€๋Šฅํ•จ์œผ๋กœ์จ ์ข€ ๋” ๊ฐ€๋…์„ฑ์ด ๋†’์•„์ง€๋Š”๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
  • ๋˜ํ•œ Migaration ๊ธฐ๋Šฅ์„ ํ†ตํ•ด Model๊ณผ DB Table์˜ ๊ฐ„๊ทน์„ ๋งŽ์ด ํ•ด๊ฒฐํ•ด์ฃผ๋ฉฐ, ๊ฐœ๋ฐœ์ž๋Š” Model์— ๋Œ€ํ•œ ์ง€์‹์„ ํ†ตํ•ด ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋Š”๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค ๐Ÿ˜Ž

์ถœ์ฒ˜

Active Record Basics - Ruby on Rails Guides

728x90
728x90