Backend/RubyOnRails

[λ²ˆμ—­] Ruby on Rails View Patterns and Anti-patterns(Ruby On Rails의 View의 νŒ¨ν„΄κ³Ό μ•ˆν‹°νŒ¨ν„΄)

Seyun(Marco) 2024. 1. 11. 01:05
728x90

πŸ’‘ 원본글 : https://blog.appsignal.com/2021/02/10/ruby-on-rails-view-patterns-and-anti-patterns.html

 

Ruby on Rails View Patterns and Anti-patterns | AppSignal Blog

Rails views are sometimes amazing and fast, and at other times, they can have all sorts of issues. If you want to increase confidence over how you handle your views, then this blog post is for you.

blog.appsignal.com

 

Ruby On Rails νŒ¨ν„΄κ³Ό μ•ˆν‹°νŒ¨ν„΄ μ‹œλ¦¬μ¦ˆμ˜ μ„Έ 번째 νŽΈμ— μ˜€μ‹ κ±Έ ν™˜μ˜ν•©λ‹ˆλ‹€. 이전 κ²Œμ‹œλ¬Όμ—μ„œ μš°λ¦¬λŠ” Rails λͺ¨λΈκ³Ό κ΄€λ ¨ν•œ νŒ¨ν„΄κ³Ό μ•ˆν‹°νŒ¨ν„΄κ³Ό 일반적인 κ²½μš°μ— λŒ€ν•΄μ„œ λ‹€λ£¨μ—ˆμŠ΅λ‹ˆλ‹€. 이번 κΈ€μ—μ„œλŠ” Rail의 view와 κ΄€λ ¨λœ λͺ‡ κ°€μ§€ νŒ¨ν„΄κ³Ό μ•ˆν‹°νŒ¨ν„΄μ— λŒ€ν•΄μ„œ μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

Rails ViewλŠ” λ•Œλ‘œλŠ” μ™„λ²½ν•˜κ³  λΉ λ₯΄κ²Œ λ™μž‘ν•˜κΈ°λ„ ν•˜μ§€λ§Œ, μ˜¨κ°– μ’…λ₯˜μ˜ λ¬Έμ œκ°€ λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€. Viewλ₯Ό μ²˜λ¦¬ν•˜λŠ” 방법에 λŒ€ν•œ μžμ‹ κ°μ„ 높이고 μ‹Άκ±°λ‚˜ 이 μ£Όμ œμ— λŒ€ν•΄ 더 μžμ„Ένžˆ μ•Œκ³  μ‹Άλ‹€λ©΄ 이 λΈ”λ‘œκ·Έ κ²Œμ‹œλ¬Όμ΄ 도움이 될 κ²ƒμž…λ‹ˆλ‹€. 그럼 λ°”λ‘œ μ‹œμž‘ν•˜κ² μŠ΅λ‹ˆλ‹€.

μ•„μ‹œλ‹€μ‹œν”Ό Rails ν”„λ ˆμž„μ›Œν¬λŠ” ꡬ성에 λŒ€ν•œ κ·œμΉ™μ„ λ”°λ¦…λ‹ˆλ‹€. 그리고 RailsλŠ” λͺ¨λΈ-λ·°-컨트둀러(MVC) νŒ¨ν„΄μ„ μ€‘μš”μ‹œν•˜κΈ° λ•Œλ¬Έμ— 이 λͺ¨ν† λŠ” μžμ—°μŠ€λŸ½κ²Œ View μ½”λ“œμ—λ„ μ μš©λ©λ‹ˆλ‹€. μ—¬κΈ°μ—λŠ” λ§ˆν¬μ—…(ERB λ˜λŠ” Slim 파일), JavaScript 및 CSS 파일이 ν¬ν•¨λ©λ‹ˆλ‹€. μ–Έλœ» λ³΄κΈ°μ—λŠ” View λ ˆμ΄μ–΄κ°€ 맀우 κ°„λ‹¨ν•˜κ³  쉽닀고 생각할 수 μžˆμ§€λ§Œ μš”μ¦˜μ—λŠ” View λ ˆμ΄μ–΄μ— μ—¬λŸ¬κ°€μ§€ 기술이 ν˜Όμž¬λ˜μ–΄ μžˆλ‹€λŠ” 점을 λͺ…μ‹¬ν•˜μ„Έμš”.

Viewμ—λŠ” JavaScript, HTML, CSSκ°€ μ‚¬μš©λ©λ‹ˆλ‹€. 이 μ„Έκ°€μ§€ κΈ°μˆ μ€ ν˜Όλ™κ³Ό μ½”λ“œμ˜ λ¬΄μ§ˆμ„œλ₯Ό μ΄ˆλž˜ν•˜μ—¬ 큰 μ˜λ―Έκ°€ μ—†λŠ” κ΅¬ν˜„μœΌλ‘œ μ΄μ–΄μ§ˆμˆ˜ μžˆμŠ΅λ‹ˆλ‹€. λ‹€ν–‰νžˆλ„ μ˜€λŠ˜μ€ Rails View κ³„μΈ΅μ˜ λͺ‡ κ°€μ§€ 일반적인 λ¬Έμ œμ™€ ν•΄κ²° 방법을 μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

Powerlifting Views

이 μ‹€μˆ˜λŠ” 자주 λ°œμƒν•˜μ§€ μ•Šμ§€λ§Œ,, λ°œμƒν•˜λ©΄ λˆˆμ— κ±°μŠ¬λ¦¬λŠ” μ‹€μˆ˜μž…λ‹ˆλ‹€. λ•Œλ•Œλ‘œ μ‚¬λžŒλ“€μ€ 도메인 λ‘œμ§μ΄λ‚˜ 쿼리λ₯Ό View 내뢀에 직접 λ„£λŠ” κ²½ν–₯이 μžˆμŠ΅λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ View λ ˆμ΄μ–΄κ°€ 무거운 μž‘μ—…μ΄λ‚˜ νŒŒμ›Œλ¦¬ν”„νŒ…(Powerlifting)을 μˆ˜ν–‰ν•˜κ²Œ λ©λ‹ˆλ‹€. ν₯미둜운 점은 Railsλ₯Ό μ‚¬μš©ν•˜λ©΄ μ‹€μ œ 이런 일이 μ‰½κ²Œ 일어날 수 μžˆλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. 이와 κ΄€λ ¨ν•˜μ—¬ β€˜μ•ˆμ „λ§β€™μ΄ μ—†κΈ° λ•Œλ¬Έμ— View λ ˆμ΄μ–΄κ°€ μ›ν•˜λŠ” 무엇이든 λ‹€ ν• μˆ˜κ°€ μžˆμŠ΅λ‹ˆλ‹€.

MVCνŒ¨ν„΄μ˜ View λ ˆμ΄μ–΄μ˜ μ •μ˜μ— 따라 ν•΄λ‹Ή λ ˆμ΄μ–΄μ—λŠ” ν”„λ¦¬μ  ν…Œμ΄μ…˜(ν‘œν˜„)ν•˜λŠ” 둜직이 ν¬ν•¨λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€. 도메인 λ‘œμ§μ΄λ‚˜ 데이터 μΏΌλ¦¬μ—λŠ” μ‹ κ²½ μ“°μ§€ μ•Šμ•„μ•Ό ν•©λ‹ˆλ‹€. Railsμ—λŠ” 루비 μ½”λ“œλ₯Ό μž‘μ„±ν•  수 μžˆλŠ” ERB 파일(μž„λ² λ””λ“œ 루비)κ°€ 제곡되며, 이 νŒŒμΌμ€ HTML둜 ν‰κ°€λ©λ‹ˆλ‹€. index νŽ˜μ΄μ§€μ— λ…Έλž˜λ₯Ό λ‚˜μ—΄ν•˜λŠ” μ›Ήμ‚¬μ΄νŠΈμ˜ 예λ₯Ό 생각해보면, View λ‘œμ μ€ app/views/songs/index.html.erb에 μžˆμ„ κ²ƒμž…λ‹ˆλ‹€.

νŒŒμ›Œλ¦¬ν”„νŒ…(Powerlifting)이 무엇을 μ˜λ―Έν•˜κ³  무엇을 ν•˜μ§€ 말아야 ν•˜λŠ”μ§€μ— λŒ€ν•΄ μ„€λͺ… ν•˜κΈ° μœ„ν•΄ λ‹€μŒ 예제λ₯Ό μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€:

# app/views/songs/index.html.erb

<div class="songs">
  <% Song.where(published: true).order(:title) do |song| %>
    <section id="song_<%= song.id %>">
      <span><%= song.title %></span>

      <span><%= song.description %></span>

      <a href="<%= song.download_url %>">Download</a>
    </section>
  <% end %>
</div>

μ—¬κΈ°μ„œ 크게 λ³΄μ—¬μ§€λŠ” μ•ˆν‹°νŒ¨ν„΄μ€ λ§ˆν¬μ—…μ—μ„œ λ°”λ‘œ Song을 κ°€μ Έμ˜€λŠ” β€œSong.where(published: true).order(:title)” μ½”λ“œλΆ€λΆ„μž…λ‹ˆλ‹€. 데이터λ₯Ό κ°€μ Έμ˜€λŠ” μ±…μž„μ€ Controller λ˜λŠ” Service에 μœ„μž„ν•΄μ•Ό ν•˜λŠ”λ° 가끔 Controllerμ—μ„œ 일뢀 데이터λ₯Ό μ€€λΉ„ν•œ 후에 λ‚˜μ€‘μ— Viewμ—μ„œ 더 λ§Žμ€ 데이터λ₯Ό κ°€μ Έμ˜€λŠ” 경우λ₯Ό λ΄…λ‹ˆλ‹€. μ΄λŠ” 잘λͺ»λœ 섀계이며 쿼리둜 λ°μ΄ν„°λ² μ΄μŠ€μ— 더 λΆ€ν•˜λ₯Ό μ£ΌκΈ° λ•Œλ¬Έμ— μ›Ήμ‚¬μ΄νŠΈ 속도가 λŠλ €μ§‘λ‹ˆλ‹€.

λ”°λΌμ„œ μœ„μ™€ 같은 방식 λŒ€μ‹ μ— Controller μ•‘μ…˜μ—μ„œ β€œ@Songβ€μ˜ μΈμŠ€ν„΄μŠ€ λ³€μˆ˜λ₯Ό λ…ΈμΆœν•˜κ³  λ‹€μŒκ³Ό 같이 λ§ˆν¬μ—…μ—μ„œ ν˜ΈμΆœν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

class SongsController < ApplicationController
  ...

  def index
    @songs = Song.all.where(published: true).order(:title)
  end

  ...
end
# app/views/songs/index.html.erb

<div class="songs">
  <% @songs.each do |song| %>
    <section id="song_<%= song.id %>">
      <span><%= song.title %></span>

      <span><%= song.description %></span>

      <a href="<%= song.download_url %>">Download</a>
    </section>
  <% end %>
</div>

이 μ˜ˆμ œλŠ” μ™„λ²½ν•˜μ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€. Controller μ½”λ“œλ₯Ό 더 읽기 μ‰½κ²Œ λ§Œλ“€κ³  SQL νŒŒμŠ€νƒ€ μ½”λ“œλ₯Ό ν”Όν•˜κ³  μ‹Άλ‹€λ©΄ 이전 λΈ”λ‘œκ·Έ(λ²ˆμ—­λ³Έ)λ₯Ό ν™•μΈν•˜μ‹œκΈ° λ°”λžλ‹ˆλ‹€. λ˜ν•œ View λ ˆμ΄μ–΄μ—μ„œ λ‘œμ§μ„ μ œμ™Έν•˜λ©΄ λ‹€λ₯Έ μ‚¬λžŒλ“€μ΄ 이λ₯Ό 기반으둜 해결책을 κ΅¬μΆ•ν•˜λ €λŠ” κ°€λŠ₯성이 λ†’μ•„μ§‘λ‹ˆλ‹€.

Railsκ°€ μ œκ³΅ν•˜λŠ” κΈ°λŠ₯을 ν™œμš©ν•˜κΈ°

μ—¬κΈ°μ„œλŠ” 짧게 μ„€λͺ…ν•˜κ² μŠ΅λ‹ˆλ‹€. ν”„λ ˆμž„μ›Œν¬λ‘œμ„œ Ruby On RailsλŠ” 특히 View 내뢀에 κΉ”λ”ν•œ Helperκ°€ 많이 ν¬ν•¨λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. 이 λ©‹μ§„ μž‘μ€ Helperλ₯Ό μ‚¬μš©ν•˜λ©΄ View λ ˆμ΄μ–΄λ₯Ό λΉ λ₯΄κ³  μ‰½κ²Œ λΉŒλ“œν•  수 μžˆμŠ΅λ‹ˆλ‹€. Rails의 초보자라면 erb파일 내에 전체 HTML을 μ•„λž˜μ™€ 같이 μž‘μ„±ν•˜κ³  싢을 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€:

# app/views/songs/new.html.erb

<form action="/songs" method="post">
  <div class="field">
    <label for="song_title">Title</label>
    <input type="text" name="song[title]" id="song_title">
  </div>

  <div class="field">
    <label for="song_description">Description</label>
    <textarea name="song[description]" id="song_description"></textarea>
  </div>

  <div class="field">
    <label for="song_download_url">Download URL</label>
    <textarea name="song[download_url]" id="song_download_url"></textarea>
  </div>

  <input type="submit" name="commit" value="Create Song">
</form>

이 HTML을 μ‚¬μš©ν•˜λ©΄ μ•„λž˜ μŠ€ν¬λ¦°μƒ·κ³Ό 같이 μƒˆλ‘œμš΄ λ…Έλž˜λ₯Ό 등둝할 수 μžˆλŠ” Form을 μ–»μ„μˆ˜ μžˆμŠ΅λ‹ˆλ‹€.

 
 

 

ν•˜μ§€λ§Œ Railsλ₯Ό μ‚¬μš©ν•œλ‹€λ©΄, Railsκ°€ κΈ°λŠ₯을 μ œκ³΅ν•΄μ£ΌκΈ° λ•Œλ¬Έμ— 일반 HTML을 μž‘μ„±ν•  ν•„μš”λ„ μ—†κ³  μž‘μ„±ν•΄μ„œλ„ μ•ˆλ©λ‹ˆλ‹€. form_with view helperλ₯Ό μ‚¬μš©ν•˜λ©΄ HTML을 μžλ™μœΌλ‘œ 생성해 μ€λ‹ˆλ‹€. form_with은 Rails 5.1에 λ„μž…λ˜μ—ˆμœΌλ©° 일뢀 μ‚¬μš©μžμ—κ²Œ μ΅μˆ™ν•œ form_tag 및 form_forλ₯Ό λŒ€μ²΄ν•˜κΈ° μœ„ν•œ κ²ƒμž…λ‹ˆλ‹€. form_with이 μ–΄λ–»κ²Œ μΆ”κ°€ μ½”λ“œ μž‘μ„±μ„ λœμ–΄μ£ΌλŠ”μ§€ μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

<%= form_with(model: song, local: true) do |form| %>
  <div class="field">
    <%= form.label :title %>
    <%= form.text_field :title %>
  </div>

  <div class="field">
    <%= form.label :description %>
    <%= form.text_area :description %>
  </div>

  <div class="field">
    <%= form.label :download_url do %>
      Download URL
    <% end %>
    <%= form.text_area :download_url %>
  </div>

  <%= form.submit %>
<% end %>

β€œform_with”은 HTML을 μƒμ„±ν•˜λŠ” 것 외에도 CSRF 곡격을 λ°©μ§€ν•˜λŠ” 인증 토큰도 μƒμ„±ν•©λ‹ˆλ‹€. λ”°λΌμ„œ 거의 λͺ¨λ“  κ²½μš°μ— μ§€μ •λœ 헬퍼λ₯Ό μ‚¬μš©ν•˜λŠ” 것이 더 μ’‹μœΌλ©°, μ΄λŠ” Rails ν”„λ ˆμž„μ›Œν¬μ™€ 잘 μž‘λ™ν•  수 있기 λ•Œλ¬Έμž…λ‹ˆλ‹€. 일반 HTML Form을 μ œμΆœν•˜λ €κ³  ν•˜λ©΄ μš”μ²­κ³Ό ν•¨κ»˜ 제좜된 μœ νš¨ν•œ 토큰이 μ—†κΈ° λ•Œλ¬Έμ— μ‹€νŒ¨ν•©λ‹ˆλ‹€.

CSRF(Cross Site Request Forgery)λž€?

μ›Ή μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜ 취약점 쀑 ν•˜λ‚˜λ‘œ, μ‚¬μš©μžκ°€ μžμ‹ μ˜ μ˜μ§€μ™€λŠ” λ‹€λ₯΄κ²Œ κ³΅κ²©μžκ°€ μ˜λ„ν•œ ν–‰μœ„λ₯Ό νŠΉμ • μ›Ήμ‚¬μ΄νŠΈμ— μš”μ²­ν•˜κ²Œ λ§Œλ“œλŠ” κ³΅κ²©μž…λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, μ‚¬μš©μžκ°€ λ‘œκ·ΈμΈν•œ μƒνƒœμ—μ„œ νŽ˜μ΄μŠ€λΆμ— 글을 μ“°λŠ” κ²ƒμ²˜λŸΌ λ³΄μ΄λŠ” ν”Όμ‹± μ‚¬μ΄νŠΈμ— μ ‘μ†ν•˜λ©΄, κ³΅κ²©μžκ°€ λ§Œλ“  κ΄‘κ³ μ„± 글이 νŽ˜μ΄μŠ€λΆμ— κ²Œμ‹œλ  수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŸ¬ν•œ 곡격을 λ°©μ§€ν•˜κΈ° μœ„ν•΄, μ„œλ²„μ—μ„œλŠ” μž„μ˜μ˜ λ‚œμˆ˜ 값을 μƒμ„±ν•˜μ—¬ μ„Έμ…˜μ— μ €μž₯ν•˜κ³ , μš”μ²­λ§ˆλ‹€ 이 값을 μ „λ‹¬ν•©λ‹ˆλ‹€. μ„œλ²„λŠ” μš”μ²­μ„ 받을 λ•Œλ§ˆλ‹€ μ„Έμ…˜μ— μ €μž₯된 κ°’κ³Ό μš”μ²­μ— μ „λ‹¬λœ 값이 μΌμΉ˜ν•˜λŠ”μ§€ κ²€μ¦ν•˜μ—¬, μœ„μ‘° μš”μ²­μ„ κ±°λΆ€ν•©λ‹ˆλ‹€. μ΄λŸ¬ν•œ λ‚œμˆ˜ 값을 Security Token이라고 λΆ€λ¦…λ‹ˆλ‹€.

 

β€œform_with”, β€œlabel”, β€œtext_area”, β€œsubmit” 헬퍼 외에도 Railsμ—λŠ” View 헬퍼가 더 많이 기본으둜 μ œκ³΅λ©λ‹ˆλ‹€. μ΄λŸ¬ν•œ View ν—¬νΌλŠ” μ—¬λŸ¬λΆ„λ“€μ˜ 개발 삢을 더 μ‰½κ²Œ λ§Œλ“€μ–΄ μ£ΌκΈ° μœ„ν•΄ μ‘΄μž¬ν•˜λ―€λ‘œ 더 잘 μ•Œμ•„λ‘¬μ•Ό ν•©λ‹ˆλ‹€. μ˜¬μŠ€νƒ€μ€‘ ν•˜λ‚˜λŠ” β€œlink_to” μž…λ‹ˆλ‹€.

<%= link_to "Songs", songs_path %>

μ•„λž˜μ™€ 같이 HTML이 μƒμ„±λ©λ‹ˆλ‹€.

<a href="/songs">Songs</a>

각 헬퍼에 λŒ€ν•΄μ„œ μžμ„Ένžˆ μ„€λͺ…ν•˜λ‹€ 보면 이글이 λ„ˆλ¬΄ κΈΈμ–΄μ§€κ³ , λͺ¨λ“  헬퍼λ₯Ό μ‚΄νŽ΄λ³΄λŠ” 것이 였늘의 μ£Όμ œλŠ” μ•„λ‹ˆλ―€λ‘œ μžμ„Ένžˆ μ„€λͺ…ν•˜μ§€ μ•Šκ² μŠ΅λ‹ˆλ‹€. κΆκΈˆν•˜μ‹œλ‹€λ©΄ **Rails Action View helpers guide**λ₯Ό μ°Έκ³ ν•΄μ„œ ν•„μš”ν•œ 헬퍼λ₯Ό μ„ νƒν•˜λŠ”κ²ƒμ΄ μ’‹μŠ΅λ‹ˆλ‹€.

View μ½”λ“œλ₯Ό μž¬μ‚¬μš©ν•˜κ³  μ •λ¦¬ν•˜κΈ°

μ™„λ²½ν•œ μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ μžˆλ‹€κ³  상상해 λ΄…μ‹œλ‹€. μ™„λ²½ν•œ μ‚¬μš© μ‚¬λ‘€μ—λŠ” if-else문이 μ—†κ³  Controllerμ—μ„œ 데이터λ₯Ό 가져와 HTML νƒœκ·Έ 사이에 λ„£λŠ” μˆœμˆ˜ν•œ μ½”λ“œλ§Œ μžˆμŠ΅λ‹ˆλ‹€. μ΄λŸ¬ν•œ μ’…λ₯˜μ˜ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ€ ν•΄μ»€ν†€μ΄λ‚˜ κΏˆμ†μ—μ„œλ‚˜ μ‘΄μž¬ν•  수 μžˆμ§€λ§Œ, μ‹€μ œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—λŠ” Viewλ₯Ό λžœλ”λ§ν•  λ•Œ μ—¬λŸ¬κ°€μ§€ 뢄기와 쑰건이 μ‘΄μž¬ν•©λ‹ˆλ‹€.

νŽ˜μ΄μ§€μ˜ 일뢀λ₯Ό ν‘œμ‹œν•˜λŠ” 둜직이 λ„ˆλ¬΄ λ³΅μž‘ν•΄μ§€λ©΄ μ–΄λ–»κ²Œ ν•΄μ•Ό ν• κΉŒμš”? 일반적인 λŒ€λ‹΅μ€ μ΅œμ‹  JavaScript λΌμ΄λΈŒλŸ¬λ¦¬λ‚˜ ν”„λ ˆμž„μ›Œν¬λ₯Ό μ‚¬μš©ν•˜μ—¬ λ³΅μž‘ν•œ 것을 κ΅¬μΆ•ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. ν•˜μ§€λ§Œ 이 κ²Œμ‹œλ¬Όμ€ Rails View에 κ΄€ν•œ κ²ƒμ΄λ―€λ‘œ κ·Έ μ•ˆμ— μžˆλŠ” 선택지듀을 μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

After-Market (Custom) Helpers

Song μ•„λž˜μ— CTA(call-to-action) λ²„νŠΌμ„ ν‘œμ‹œν•˜κ³  μ‹Άλ‹€κ³  κ°€μ •ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ ν•œ κ°€μ§€ 정책이 μžˆμŠ΅λ‹ˆλ‹€. Song에 λ‹€μš΄λ‘œλ“œ URL이 μ‘΄μž¬ν• μˆ˜λ„ 있고 μ•„λ‹μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. κ·Έλ ‡λ‹€λ©΄ λ‹€μŒκ³Ό 같이 μ½”λ“œλ₯Ό μž‘μ„±ν•˜κ²Œ λ κ²ƒμž…λ‹ˆλ‹€.

app/views/songs/show.html.erb

...

<div class="song-cta">
  <% if @song.download_url %>
    <%= link_to "Download", download_url %>
  <% else %>
    <%= link_to "Subscribe to artists updates",
                artist_updates_path(@song.artist) %>
  <% end %>
</div>

...

μœ„μ˜ μ˜ˆμ‹œμ—μ„œ 고립된 ν”„λ ˆμ  ν…Œμ΄μ…˜ 둜직으둜만 λ³Έλ‹€λ©΄ κ·Έλ ‡κ²Œ λ‚˜μ˜μ§€ μ•Šμ„κ±° κ°™μŠ΅λ‹ˆλ‹€. κ·Έμ΅Έ? ν•˜μ§€λ§Œ μ΄λŸ¬ν•œ 쑰건뢀 λžœλ”λ§μ΄ λ§Žμ•„μ§„λ‹€λ©΄ μ½”λ“œμ˜ 가독성이 λ–¨μ–΄μ§‘λ‹ˆλ‹€. 특히 쑰건이 많으면 μ–΄λ”˜κ°€μ—μ„œ μ œλŒ€λ‘œ λžœλ”λ§ λ˜μ§€ μ•Šμ„ κ°€λŠ₯성도 λ†’μ•„μ§‘λ‹ˆλ‹€.

μ΄λŸ¬ν•œ 문제λ₯Ό ν•΄κ²°ν•˜λŠ” ν•œ κ°€μ§€ 방법은 λ³„λ„μ˜ ν—¬νΌλ‘œ μΆ”μΆœν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. λ‹€ν–‰νžˆλ„ RailsλŠ” μ‚¬μš©μž μ •μ˜ 헬퍼λ₯Ό μ‰½κ²Œ μž‘μ„±ν•  수 μžˆλŠ” 방법을 μ œκ³΅ν•©λ‹ˆλ‹€. β€œapp/helpersβ€μ—μ„œ λ‹€μŒκ³Ό 같이 β€œSongHelper”λ₯Ό λ§Œλ“€μˆ˜ μžˆμŠ΅λ‹ˆλ‹€.

module SongsHelper
  def song_cta_link
    content_tag(:div, class: 'song-cta') do
      if @song.download_url
        link_to "Download", @song.download_url
      else
        link_to "Subscribe to artists updates",
                artist_updates_path(@song.artist)
      end
    end
  end
end

Song의 show νŽ˜μ΄μ§€λ₯Ό 열어도 μ—¬μ „νžˆ λ™μΌν•œ κ²°κ³Όλ₯Ό μ–»μ„μˆ˜κ°€ μžˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ 이 예제λ₯Ό 쑰금 더 κ°œμ„ ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μœ„μ˜ μ˜ˆμ œμ—μ„œλŠ” μΈμŠ€ν„΄μŠ€ λ³€μˆ˜μΈ β€œ@Song”을 μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€. λ…Έλž˜κ°€ nil인 κ³³μ—μ„œ 이 헬퍼λ₯Ό μ‚¬μš©ν•˜κΈ°λ‘œ κ²°μ •ν–ˆλ‹€λ©΄ 이 λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν• μˆ˜κ°€ μ—†μ„μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ μΈμŠ€ν„΄μŠ€ λ³€μˆ˜ ν˜•νƒœμ˜ μ™ΈλΆ€ 쒅속성을 μ°¨λ‹¨ν•˜κΈ° μœ„ν•΄ λ‹€μŒκ³Ό 같이 ν—¬νΌμ—κ²Œ 인수λ₯Ό μ „λ‹¬ν• μˆ˜ μžˆμŠ΅λ‹ˆλ‹€.

module SongsHelper
  def song_cta_link(song)
    content_tag(:div, class: 'song-cta') do
      if song.download_url
        link_to "Download", song.download_url
      else
        link_to "Subscribe to artists updates",
                artist_updates_path(song.artist)
      end
    end
  end
end

viewμ—μ„œ μ•„λž˜μ™€ 같이 μ‚¬μš©ν• μˆ˜ μžˆμŠ΅λ‹ˆλ‹€

app/views/songs/show.html.erb
...
<%= song_cta_link(@song) %>
...

μ΄λ ‡κ²Œ ν•˜λ©΄ Viewμ—μ„œ 이전과 λ™μΌν•œ κ²°κ³Όλ₯Ό 얻을 수 μžˆμŠ΅λ‹ˆλ‹€. 헬퍼λ₯Ό μ‚¬μš©ν•  λ•Œμ˜ μž₯점은 헬퍼에 λŒ€ν•œ ν…ŒμŠ€νŠΈλ₯Ό μž‘μ„±ν•΄μ„œ ν–₯ν›„ 헬퍼와 κ΄€λ ¨λœ νšŒκ·€κ°€ λ°œμƒν•˜μ§€ μ•Šλ„λ‘ ν•  수 μžˆλ‹€λŠ” μ μž…λ‹ˆλ‹€. 단점은 헬퍼가 μ „μ—­μ μœΌλ‘œ μ •μ˜λ˜λ―€λ‘œ μ•± μ „μ²΄μ—μ„œ 헬퍼 이름이 κ³ μœ ν•œμ§€ 확인해야 ν•œλ‹€λŠ” μ μ΄λΉˆλ‹€.

Rails μ‚¬μš©μž 헬퍼λ₯Ό μž‘μ„±ν•˜λŠ” 것을 μ’‹μ•„ν•˜μ§€ μ•ŠλŠ” λ‹€λ©΄ draper gem을 μ‚¬μš©ν•΄ View ModelνŒ¨ν„΄μ„ μ‚¬μš©ν•΄λ³Όμˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. μ—¬κΈ°μ—μ„œ μžμ‹ λ§Œμ˜ View Model νŒ¨ν„΄μ„ 직접 λ§Œλ“€μˆ˜ 있으며, κ·Έλ ‡κ²Œ λ³΅μž‘ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 웹앱을 막 μ‹œμž‘ν•˜λŠ” κ²½μš°μ—λŠ” μ‚¬μš©μž μ •μ˜ 헬퍼λ₯Ό μž‘μ„±ν•˜μ—¬ 천천히 μ‹œμž‘ν•˜κ³  λ¬Έμ œκ°€ λ°œμƒν•˜λ©΄ λ‹€λ₯Έ ν•΄κ²°μ±…μœΌλ‘œ μ „ν™˜ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

DRY up Your Views

Railsλ₯Ό μ‹œμž‘ν•˜λ©΄μ„œ 정말 λ§ˆμŒμ— λ“€μ—ˆλ˜ 점은 λ§ˆν¬μ—…μ„ μ‰½κ²Œ 정리할 수 μžˆλ‹€λŠ” μ μ΄μ˜€μŠ΅λ‹ˆλ‹€. RailsλŠ” μ–΄λ””μ—λ‚˜ 포함될 수 μžˆλŠ” μž¬μ‚¬μš© κ°€λŠ₯ν•œ μ½”λ“œ 쑰각인 partialsλ₯Ό 생성할 수 μžˆλŠ” κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄ μ—¬λŸ¬ κ³³μ—μ„œ Song을 λžœλ”λ§ν•˜κ³  있고 μ—¬λŸ¬ νŒŒμΌμ— λ™μΌν•œ μ½”λ“œκ°€ μžˆλŠ” 경우 Song partial을 λ§Œλ“œλŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

μ•„λž˜μ™€ 같이 λ…Έλž˜λ₯Ό ν‘œμ‹œν•œλ‹€κ³  κ°€μ •ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

# app/views/songs/show.html.erb

<p id="notice"><%= notice %></p>

<p>
  <strong>Title:</strong>
  <%= @song.title %>
</p>

<p>
  <strong>Description:</strong>
  <%= @song.description %>
</p>

<%= song_cta_link %>

<%= link_to 'Edit', edit_song_path(@song) %> |
<%= link_to 'Back', songs_path %>

ν•˜μ§€λ§Œ λ™μΌν•œ λ§ˆν¬μ—…μœΌλ‘œ λ‹€λ₯Έ νŽ˜μ΄μ§€μ—λ„ ν‘œμ‹œν•˜κ³  μ‹Άμ„μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. κ·Έλ ‡λ‹€λ©΄ β€œapp/views/songs/_song.html.erb”와 같이 언더바(_) 접두사가 뢙은 μƒˆ νŒŒμΌμ„ λ§Œλ“€λ©΄ λ©λ‹ˆλ‹€.

# app/views/songs/_song.html.erb

<p>
  <strong>Title:</strong>
  <%= @song.title %>
</p>

<p>
  <strong>Description:</strong>
  <%= @song.description %>
</p>

<%= song_cta_link(@song) %>

그리고 μ–΄λ””μ—μ„œλ‚˜ μ›ν•˜λŠ” 곳에 Song partial을 μ•„λž˜μ™€ 같이 μΆ”κ°€ν•˜λ©΄ λ©λ‹ˆλ‹€.

...
<%= render "song" %>
...

β€œ_Song” partial의 쑴재 μ—¬λΆ€λ₯Ό μžλ™μœΌλ‘œ μ‘°νšŒν•œ 후에 λžœλ”λ§μ„ ν•©λ‹ˆλ‹€. μ‚¬μš©μž μ •μ˜ 헬퍼λ₯Ό μ‚¬μš©ν•œ μ˜ˆμ œμ™€ λ§ˆμ°¬κ°€μ§€λ‘œ partialμ—μ„œ μΈμŠ€ν„΄μŠ€ λ³€μˆ˜μ˜ β€œ@song”을 μ œκ±°ν•˜λŠ” 것이 κ°€μž₯ μ’‹μŠ΅λ‹ˆλ‹€.

# app/views/songs/_song.html.erb
<p>
  <strong>Title:</strong>
  <%= song.title %>
</p>

<p>
  <strong>Description:</strong>
  <%= song.description %>
</p>

<%= song_cta_link(song) %>

그런 λ‹€μŒ song의 λ³€μˆ˜λ₯Ό partial에 μ „λ‹¬ν•˜μ—¬ μž¬μ‚¬μš©μ„±μ„ 높이고 λ‹€λ₯Έ 곳에 ν¬ν•¨μ‹œν‚€κΈ°μ— μ ν•©ν•˜λ„λ‘ λ§Œλ“€μ–΄μ•Ό ν•©λ‹ˆλ‹€.

...
<%= render "song", song: @song %>
...

λ§ˆμ§€λ§‰ 생각

이 ν¬μŠ€νŒ…μ€ μ—¬κΈ°κΉŒμ§€μž…λ‹ˆλ‹€. μš”μ•½ν•˜μžλ©΄ Rails View μ˜μ—­μ—μ„œ λ³Ό 수 μžˆλŠ” λͺ‡ κ°€μ§€ νŒ¨ν„΄κ³Ό μ•ˆν‹°νŒ¨ν„΄μ„ μ‚΄νŽ΄λ΄€μŠ΅λ‹ˆλ‹€. λ‹€μŒμ€ λͺ‡ κ°€μ§€ μš”μ μž…λ‹ˆλ‹€:

  • UIμ—μ„œ λ³΅μž‘ν•œ 둜직 ν”Όν•˜κΈ°(Viewκ°€ λ§Žμ€ Powerlifting을 μˆ˜ν–‰ν•˜μ§€ μ•Šλ„λ‘ λ§Œλ“€κΈ°.)
  • Railsκ°€ View 헬퍼와 κ΄€λ ¨λœ 기본적으둜 μ œκ³΅ν•˜λŠ” κΈ°λŠ₯에 λŒ€ν•΄ μ•Œμ•„λ³΄μ„Έμš”.
  • μ‚¬μš©μž μ§€μ • 헬퍼 및 partial μ½”λ“œλ₯Ό κ΅¬μ‘°ν™”ν•˜κ³  μž¬μ‚¬μš© ν•˜μ„Έμš”.
  • μΈμŠ€ν„΄μŠ€ λ³€μˆ˜μ— λ„ˆλ¬΄ 많이 μ˜μ‘΄ν•˜μ§€ λ§ˆμ„Έμš”.

λ‹€μŒ κ²Œμ‹œλ¬Όμ—μ„œλŠ” μƒλ‹Ήνžˆ μ§€μ €λΆ„ν•΄μ§ˆμˆ˜ μžˆλŠ” Rails Controller νŒ¨ν„΄κ³Ό μ•ˆν‹° νŒ¨ν„΄μ— λŒ€ν•΄ λ‹€λ£° κ²ƒμž…λ‹ˆλ‹€. κΈ°λŒ€ν•΄μ£Όμ„Έμš”.

λ‹€μŒ μ‹œκ°„κΉŒμ§€ ν™”μ΄νŒ…!

PS. Ruby Magic κ²Œμ‹œλ¬Όμ΄ λ³΄λ„λ˜λŠ” λŒ€λ‘œ 읽고 μ‹ΆμœΌμ‹œλ©΄ Ruby Magic λ‰΄μŠ€λ ˆν„°λ₯Ό κ΅¬λ…ν•˜μ‹œκ³  단 ν•˜λ‚˜μ˜ κ²Œμ‹œλ¬Όλ„ λ†“μΉ˜μ§€ λ§ˆμ„Έμš”!

728x90
728x90