๐ Introduction
Rails(Ruby on Rails, RoR)๋ Ruby์ ๋ํ์ ์ธ ํ๋ ์์ํฌ๋ก MVC ๋ชจ๋ธ์ ์ฌ์ฉํ๋ ํ์คํ ์น ํ๋ ์์ํฌ์ ๋๋ค. Ruby ํน์ ์ ์ฝ๊ณ ์ง๊ด์ ์ธ ๋ฌธ๋ฒ์ผ๋ก ์ธํด Rails ๋ํ ์ฝ๋๋ฅผ ์ดํดํ๋๋ฐ ์ด๋ ต์ง ์์ผ๋ฉฐ scaffold ๋ฑ์ ๊ธฐ๋ฅ์ผ๋ก ๋น ๋ฅด๊ฒ ์น ์๋น์ค๋ฅผ ๊ตฌ์ฑํ ์ ์์ต๋๋ค.
์ด์ธ์๋ ์น ์๋น์ค๋ฅผ ๊ฐ๋ฐํ๋๋ฐ ์์ด ํ์ํ ์ฌ๋ฌ๊ฐ์ง ๊ธฐ์ , ํ ํฌ๋, ๋ณด์์ ๋ํ ๋ถ๋ถ์ด ๋ง์ด ๊ณ ๋ ค๋์ด ์์ต๋๋ค.
Installation
sudo gem install rails
Struct of Rails app
Model
- config/database.yml : DB ์ ์์ ๋ณด ๋ฐ ์ค์
- db/migrate/* : active_record ๊ด๋ จ ์ฝ๋
- app/models/* : model(db schema)์ ๊ด๋ จ๋ ์ฝ๋
View
- app/views/* : Model, Controller์ ์ฐ๊ฒฐ๋ View ์ฝ๋๋ค
Controller
- app/controllers/* : ์ปจํธ๋กค๋ฌ ์ฝ๋
- config/routes.rb : ์ค์ ๋ผ์ฐํ ์ด ๋ช ์๋๋ ์ฝ๋
Etc
- config/* : ์ดํ๋ฆฌ์ผ์ด์ ์ ๋ํ ์ค์ ๋ค
- public/* : public ๋๋ ํ ๋ฆฌ
๐น Snippet
New Web App
rails new {appname}
With TailWind
rails new {appname} --css tailwind
Specifies the DB
rails new {appname} --database=postgresql
New API App
rails new {appname} --api
or
# config/application.rb
config.api_only = true
Generate with scaffold
scaffold๋ ํ๋ฒ์ ๋ช ๋ น์ผ๋ก MVC(Model, View, Controller)๋ฅผ ํ๋ฒ์ ์์ฑํ ์ ์๋ ๊ธฐ๋ฅ์ ๋๋ค.
rails g scaffold post title:string context:text
types
- string
- text (long text, up to 64k, often used for text areas)
- datetime
- date
- integer
- binary
- boolean
- float
- decimal (for financial data)
- time
- timestamp
- references
Migration
New model
rails g model Scans name:string url:string
Migration
rake db:migrate
Rollback
rake db:rollback # ๊ฐ์ฅ ์ต๊ทผ DB ์ํ๋ก ๋๋๋ฆฝ๋๋ค.
rake db:rollback STEP=2 # 2๋ฒ Undo ํ์ฌ DB ์ํ๋ฅผ ๋๋๋ฆฝ๋๋ค.
Redo
rake db:migrate:redo STEP=3
# rollback ํ ๋ค์ migration ํฉ๋๋ค. STEP์ผ๋ก task๋ฅผ ์กฐ์ ํ ์ ์์ต๋๋ค.
Add column
rails g migration add_columns_from_model
# Example
rails g migration add_content_from_post
Change column type
rails g migration ChangeColumnType
class ChangeColumnType < ActiveRecord::Migration[7.0]
def change
change_column :users, :age, :integer
end
end
ERD
rails-erd ํฌํจ ํ rake erd๋ก ํ์ฌ model์ ๋ํ erd๋ฅผ ๋ณผ ์ ์์ต๋๋ค.
gem 'rails-erd'
rake erd
Run Server
rails s
rails server
Run Console
Rails๋ console ๋ช ๋ น์ ํตํด ์คํ์ค์ธ ์ฑ์์ ์ง์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๊ฑฐ๋ ์ฝ๋ ์ค๋ํซ์ ์คํํ ์ ์์ต๋๋ค.
rails c
rails console
with env
rails console -e <env>
# rails console -e developement
# rails console -e production
with sandbox mode
rails console --sandbox
sandbox ๋ชจ๋๋ก ๋์ํ๋ฉด ํ ์คํธ๋ก ์ธํด DB ๋ณ๊ฒฝ์ด ์ผ์ด๋๋ console์ด ์ข ๋ฃ๋ ๋ ๋กค๋ฐฑ๋ฉ๋๋ค.
๐ฎ Codes
Caching
Low Level Caching
# Read
value1 = Rails.cache.read 'cache_key'
value2 = Rails.cache.read({key: 'sequence', owner: @user})
## ๊ฐ์ด ์๋ค๋ฉด ๊ฐ์ return, ์๊ฑฐ๋ ๋ง๋ฃ๋ฌ๋ค๋ฉด nil์ ๋ฆฌํด
# Write
Rails.cache.write 'cache_key', some_data
Rails.cache.write 'cache_key', some_data, expires_in: 3.hour
# Fetch
Rails.cache.fetch('cache_key', expires_in: 30.minutes) do
# Code..
end
Active Record
Relationship
์ฌ์ฉ ๊ฐ๋ฅํ Relation์ ์๋์ ๊ฐ์ผ๋ฉฐ ์ด๋ฅผ ์ด์ฉํ๋ฉด ์๋น์ค์ ๊ตฌ์ฑ์ ๋ฐ๋ผ ๋จ์ํ ๋ชจ๋ธ๋ถํฐ Polymorphic ๋ฑ ๋ณต์กํ ํํ์ Relationship์ ๊ตฌ์ฑํ ์ ์์ต๋๋ค. ์ด๋ Model์ ์ง์ ์ ์ผ๋ก ์ฐ๊ด๋๋ฉฐ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋๋ฐ ์์ด์ ํฐ ์ด์ ์ ๊ฐ์ ธ์ต๋๋ค.
belongs_to # 1:1 (ํ ๋ชจ๋ธ์ด ๋ค๋ฅธ ๋ชจ๋ธ์ ์ํ ๋)
has_one # 1:1 (ํ ๋ชจ๋ธ์ด ๋ค๋ฅธ ๋ชจ๋ธ์ ๊ฐ์ง๊ณ ์์ ๋)
has_many # 1:N (ํ ๋ชจ๋ธ์ด ๋ค๋ฅธ ๋ชจ๋ธ์ ์ฌ๋ฌ๊ฐ ๊ฐ์ง๊ณ ์์ ๋)
has_many :through # M:N (์ 3์ ๋ชจ๋ธ๋ก M:N์ ๊ฐ์ ๊ด๊ณ๋ฅผ ๊ฐ์ง ๋)
has_one :through # 1:1 (์ 3์ ๋ชจ๋ธ๋ก ๊ฐ์ ์ ๊ด๊ณ๋ฅผ ๊ฐ์ง ๋)
has_and_belongs_to_many # M:N (M:N์ ๋ชจ๋ธ์ด ๊ด๊ณ๋ฅผ ๊ฐ์ง ๋)
e.g
class Customer < ActiveRecord::Base
has_many :orders
end
# Customer๋ ์ฌ๋ฌ๊ฐ์ Order๋ฅผ ๊ฐ์ง
with scaffold
rails g scaffold Order data:string customer:references
# rails c
irb(main):001:0> Order.create data:"aa", customer_id:4
#<Comment:0x00000001095fbea0
id: 2,
data: "aa",
customer_id: 4,
created_at:
Wed, 10 Aug 2022 14:35:07.140636000 UTC +00:00,
updated_at:
Wed, 10 Aug 2022 14:35:07.140636000 UTC +00:00>
๐ก Security
CORS
gem 'rack-cors'
# config/application.rb
config.middleware.insert_before 0, Rack::Cors do
allow do
origins 'localhost:3000', '127.0.0.1:3000',
/\Ahttp:\/\/192\.168\.0\.\d{1,3}(:\d+)?\z/
resource '*', headers: :any, methods: [:get, :post, :options]
end
end
Blocking & Throttling
https://github.com/rack/rack-attack
e.g
throttle('logins/ip', limit: 5, period: 20.seconds) do |req|
if req.path == '/login' && req.post?
req.ip
end
end
Security Guide
- https://guides.rubyonrails.org/security.html
- https://owasp.org/www-pdf-archive//Rails_Security_2.pdf
๐ Middlewares
https://github.com/coopermaa/awesome-rack
๐ Articles
Rails ์์ฑ ๊ธ์ ๊ฒ์ ๋งํฌ๋ก ๋์ฒดํฉ๋๋ค.
https://www.hahwul.com/search/?keyword=rails
๐ผ Resources
๐ References
- https://guides.rubyonrails.org/getting_started.html
- https://guides.rubyonrails.org/security.html
- https://owasp.org/www-pdf-archive//Rails_Security_2.pdf