Rails Service Objects를 사용하여 모델 및 컨트롤러 슬림화
14803 단어 optimizationrailsrefactoring
"Fat models, skinny controllers"는 Rails 애플리케이션 리팩터링을 위한 모범 사례 중 하나입니다. 그러나 애플리케이션이 커지고 복잡해짐에 따라 모델에 비즈니스 로직이 더 많아지고 단일 책임 원칙을 적용하기가 더 어려워집니다. "스키니 모델, 스키니 컨트롤러"를 달성하기 위해 비즈니스 로직을 서비스 객체로 추출하는 것을 고려해야 할 때입니다.
서비스 개체란 무엇입니까?
OOP의 캡슐화를 기억하십니까? Rails의 서비스 객체는 기본적으로 하나의 단일 작업을 실행하도록 설계된 Ruby 객체로 비즈니스 로직을 캡슐화합니다. 서비스 개체는 어디에서나 호출할 수 있으며 테스트하기도 쉽습니다. 다음과 같은 경우 사용을 고려하십시오.
서비스 개체 추출
실제로 그것을 보자. 사용자가 이미지를 게시할 때 Google Cloud Vision API을 사용하여 해시태그를 생성하는 Rails 애플리케이션을 만들었습니다. 에서 소개한 샘플 코드를 사용하고 있습니다.
get_tags
모델에 Post
방법이 있습니다.
# app/models/post.rb
class Post < ApplicationRecord
def get_tags(image)
api_key = ENV['GOOGLE_API_KEY']
api_url = "https://vision.googleapis.com/v1/images:annotate?key=#{api_key}"
base64_image = Base64.strict_encode64(File.new(image, 'rb').read)
body = {
requests: [{
image: {
content: base64_image
},
features: [
{
type: 'LABEL_DETECTION',
maxResults: 5
}
]
}]
}.to_json
uri = URI.parse(api_url)
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri)
request['Content-Type'] = 'application/json'
response = https.request(request, body)
results = JSON.parse(response.body)
results['responses'][0]['labelAnnotations'].each do |result|
tag = Tag.find_or_create_by(name: result['description'])
PostTag.create(post_id: id, tag_id: tag.id)
end
end
end
모델은 이미지에 태그를 지정하는 방법에 대해 너무 많이 알고 있습니다. 작업을 서비스 개체로 추출하여 리팩터링해 보겠습니다.
먼저 app/services
폴더와 그 아래에 tag_generator.rb
를 생성합니다. 모든 논리를 get_tags
에서 클래스.call
메서드로 이동합니다.
# app/services/tag_generator.rb
class TagGenerator
def self.call(post, image)
api_key = ENV['GOOGLE_API_KEY']
api_url = "https://vision.googleapis.com/v1/images:annotate?key=#{api_key}"
base64_image = Base64.strict_encode64(File.new(image, 'rb').read)
body = {
requests: [{
image: {
content: base64_image
},
features: [
{
type: 'LABEL_DETECTION',
maxResults: 5
}
]
}]
}.to_json
uri = URI.parse(api_url)
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri)
request['Content-Type'] = 'application/json'
response = https.request(request, body)
results = JSON.parse(response.body)
results['responses'][0]['labelAnnotations'].each do |result|
tag = Tag.find_or_create_by(name: result['description'])
PostTag.create(post_id: post.id, tag_id: tag.id)
end
end
end
이제 TagGenerator
클래스의 클래스 메서드입니다. post_controller.rb
도 업데이트합시다.
전에:
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
def create
@post = current_user.posts.new(post_params)
if @post.save
@post.get_tags(params[:post][:image])
redirect_to @post
else
render :new
end
end
후에:
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
def create
@post = current_user.posts.new(post_params)
if @post.save
TagGenerator.call(@post, params[:post][:image])
redirect_to @post
else
render :new
end
end
이제 우리는 Post
모델의 크기를 축소했을 뿐만 아니라 태그 생성기 작업을 유지 관리하고 재사용할 수 있게 만들었습니다.
TagGenerator.call
를 실행한 결과입니다. 이미지에서 자동 생성된 해시태그:
참조:
7 Patterns to Refactor Fat ActiveRecord Models
Reference
이 문제에 관하여(Rails Service Objects를 사용하여 모델 및 컨트롤러 슬림화), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/junko911/slim-down-models-and-controllers-using-rails-service-objects-4i2c
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
# app/models/post.rb
class Post < ApplicationRecord
def get_tags(image)
api_key = ENV['GOOGLE_API_KEY']
api_url = "https://vision.googleapis.com/v1/images:annotate?key=#{api_key}"
base64_image = Base64.strict_encode64(File.new(image, 'rb').read)
body = {
requests: [{
image: {
content: base64_image
},
features: [
{
type: 'LABEL_DETECTION',
maxResults: 5
}
]
}]
}.to_json
uri = URI.parse(api_url)
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri)
request['Content-Type'] = 'application/json'
response = https.request(request, body)
results = JSON.parse(response.body)
results['responses'][0]['labelAnnotations'].each do |result|
tag = Tag.find_or_create_by(name: result['description'])
PostTag.create(post_id: id, tag_id: tag.id)
end
end
end
# app/services/tag_generator.rb
class TagGenerator
def self.call(post, image)
api_key = ENV['GOOGLE_API_KEY']
api_url = "https://vision.googleapis.com/v1/images:annotate?key=#{api_key}"
base64_image = Base64.strict_encode64(File.new(image, 'rb').read)
body = {
requests: [{
image: {
content: base64_image
},
features: [
{
type: 'LABEL_DETECTION',
maxResults: 5
}
]
}]
}.to_json
uri = URI.parse(api_url)
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri)
request['Content-Type'] = 'application/json'
response = https.request(request, body)
results = JSON.parse(response.body)
results['responses'][0]['labelAnnotations'].each do |result|
tag = Tag.find_or_create_by(name: result['description'])
PostTag.create(post_id: post.id, tag_id: tag.id)
end
end
end
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
def create
@post = current_user.posts.new(post_params)
if @post.save
@post.get_tags(params[:post][:image])
redirect_to @post
else
render :new
end
end
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
def create
@post = current_user.posts.new(post_params)
if @post.save
TagGenerator.call(@post, params[:post][:image])
redirect_to @post
else
render :new
end
end
Reference
이 문제에 관하여(Rails Service Objects를 사용하여 모델 및 컨트롤러 슬림화), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/junko911/slim-down-models-and-controllers-using-rails-service-objects-4i2c텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)