Ruby on Rails
수업 조직
수색…
비고
이것은 간단한 일처럼 보입니다. 그러나 수업을 시작할 때 크기가 급상승 할 때 시간을내어 정리해 주셔서 감사 할 것입니다.
모델 클래스
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments
validates :user, presence: true
validates :title, presence: true, length: { in: 6..40 }
scope :topic, -> (topic) { joins(:topics).where(topic: topic) }
before_save :update_slug
after_create :send_welcome_email
def publish!
update(published_at: Time.now, published: true)
end
def self.find_by_slug(slug)
find_by(slug: slug)
end
private
def update_slug
self.slug = title.join('-')
end
def send_welcome_email
WelcomeMailer.welcome(self).deliver_now
end
end
모델은 일반적으로 다음을 담당합니다.
- 관계 설정
- 데이터 검증 중
- 범위 및 메서드를 통해 데이터에 액세스 제공
- 데이터 지속성과 관련된 작업 수행
최상위 레벨에서 모델은 도메인 개념을 설명하고 지속성을 관리합니다.
서비스 클래스
컨트롤러는 애플리케이션의 시작점입니다. 그러나 유일한 진입 점이 아닙니다. 내 논리를 다음에서 액세스 할 수있게하려고합니다.
- 갈퀴 작업
- 배경 작업
- 콘솔
- 검사들
컨트롤러에 논리를 삽입하면이 모든 장소에서 액세스 할 수 없습니다. 그럼 "스키니 컨트롤러, 뚱뚱한 모델"접근 방식을 시도하고 로직을 모델로 옮겨 봅시다. 그러나 어느 것? 주어진 로직에 User
, Cart
및 Product
모델이 포함되는 경우 - 어디서 살면됩니까?
ActiveRecord::Base
로부터 상속받은 클래스는 이미 많은 책임이 있습니다. 쿼리 인터페이스, 연결 및 유효성 검사를 처리합니다. 모델에 더 많은 코드를 추가하면 수백 가지의 공용 메소드에서 유지 관리가 쉽지 않습니다.
서비스는 단지 일반적인 Ruby 객체입니다. 이 클래스는 특정 클래스에서 상속 할 필요가 없습니다. 그 이름은 동사입니다 (예 : UserCreation
또는 UserCreationService
대신 CreateUserAccount
. 그것은 app / services 디렉토리에 있습니다. 이 디렉토리는 직접 만들어야하지만, Rails는 자동으로 클래스를 자동로드합니다.
서비스 객체는 한 가지 작업을 수행합니다.
서비스 객체 (메서드 객체라고도 함)는 하나의 작업을 수행합니다. 해당 작업을 수행 할 비즈니스 논리를 보유합니다. 다음은 그 예입니다.
# app/services/accept_invite.rb
class AcceptInvite
def self.call(invite, user)
invite.accept!(user)
UserMailer.invite_accepted(invite).deliver
end
end
내가 따라하는 세 가지 규칙은 다음과 같습니다.
서비스는 app/services directory
아래에 app/services directory
. 비즈니스 로직이 많은 도메인에 하위 디렉토리를 사용하는 것이 좋습니다. 예를 들면 :
-
app/services/invite/accept.rb
파일은Invite::Accept
를 정의하고app/services/invite/create.rb
는Invite::Create
정의합니다. - 서비스는 동사로 시작하며 서비스로 끝나지 않습니다 :
ApproveTransaction
,SendTestNewsletter
,ImportUsersFromCsv
- 서비스가
call
메소드에 응답합니다. 다른 동사를 사용하면 중복 된 것으로 나타났습니다.ApproveTransaction.approve()
는 잘 읽지 않습니다. 또한,call
메소드는lambda
,procs
및 메소드 객체에 대한 사실상의 메소드입니다.
은혜
서비스 객체는 내 애플리케이션에서 수행하는 작업을 보여줍니다.
내 응용 프로그램이 무엇인지보기 위해 서비스 디렉토리를 살펴볼 수 있습니다 : ApproveTransaction
, CancelTransaction
, BlockAccount
, SendTransactionApprovalReminder
...
서비스 오브젝트에 대한 간략한 조사와 관련된 비즈니스 로직을 알고 있습니다. 컨트롤러, ActiveRecord
모델 콜백 및 옵저버를 통해 "트랜잭션 승인"이 무엇을 의미하는지 이해할 필요가 없습니다.
클린업 모델 및 컨트롤러
컨트롤러는 요청 (params, session, cookies)을 인수로 변환하여 서비스로 전달하고 서비스 응답에 따라 리디렉션하거나 렌더링합니다.
class InviteController < ApplicationController
def accept
invite = Invite.find_by_token!(params[:token])
if AcceptInvite.call(invite, current_user)
redirect_to invite.item, notice: "Welcome!"
else
redirect_to '/', alert: "Oopsy!"
end
end
end
모델은 연관, 범위, 유효성 검사 및 지속성 만 처리합니다.
class Invite < ActiveRecord::Base
def accept!(user, time=Time.now)
update_attributes!(
accepted_by_user_id: user.id,
accepted_at: time
)
end
end
따라서 모델과 컨트롤러를 테스트하고 유지 관리하는 것이 훨씬 쉬워집니다!
서비스 클래스 사용시기
작업이 다음 기준 중 하나 이상을 충족하면 서비스 개체 도달 범위 :
- 행동은 복잡합니다 (예 : 회계 기간 말에 책을 닫음)
- 이 작업은 여러 모델에 걸쳐 이루어집니다 (예 : Order, CreditCard 및 Customer 객체를 사용한 전자 상거래 구매)
- 액션은 외부 서비스와 상호 작용합니다 (예 : 소셜 네트워크에 게시)
- 동작은 기본 모델의 핵심 관심사는 아닙니다 (예 : 일정 기간이 지나면 오래된 데이터를 청소).
- 액션을 수행하는 방법에는 여러 가지가 있습니다 (예 : 액세스 토큰 또는 비밀번호로 인증).
출처