Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

다양한 검증 상황을 처리하는 가벼운 방법

(몇 달 전에 이 게시물을 내 목록에 보냈습니다. 이 게시물이 마음에 들고 더 읽고 싶다면 가입해야 합니다!)

요전날 내 앱 중 하나에 이상한 상황이 발생했습니다.

Article가 있다고 가정해 보겠습니다. 모델이며 이러한 기사는 먼저 초안으로 작성됩니다. 이러한 초안은 가벼워야 합니다. 본문이나 제목 없이 바로 만들고 편집할 수 있기를 원합니다.

하지만 게시하면 이 기사를 보려면 몇 가지 추가 유효성 검사가 필요합니다. 제목, 본문 및 기타 모든 항목이 있어야 합니다.

if 스스로 확인하는 문장. 하지만 Rails에서 얻을 수 있는 모든 멋진 폼 핸들링을 갖고 있지는 않을 것입니다. 그리고 Rails가 잘 처리하는 일에 대해 Rails를 사용하면 나중에 골치 아픈 일을 많이 줄일 수 있다는 것을 알게 되었습니다. 이에 대한 유효성 검사를 사용할 수 있는 방법이 있습니까?

ifunless ?

검증 지원 :if:unless 매개변수가 있지만 항상 깨끗한 것은 아닙니다.

앱/모델/article.rb
class Article < ActiveRecord::Base
  # validate in draft mode
  validates_presence_of :author_id 

  # validate only when published
  validates_presence_of :body, unless: lambda { |o| o.draft? }
  
  ...
end

게다가 기사를 게시하려는 방식이 아닙니다. 기사를 액션으로 게시하는 것에 대해 생각하고 싶습니다. , 가 아님 기사가 들어있어 속성을 설정하고 확인하는 것은 정답이 아닙니다.

잘 알려지지 않고 약간 문서화된 Rails 기능

이 문제는 Rails의 유효성 검사 컨텍스트에 완벽하게 맞습니다. 나는 먼저 DHH가 쓴 요지에서 사용자 정의 유효성 검사 컨텍스트에 대해 배웠습니다. 그러나 이것들이 무엇인지, 어떻게 사용하는지에 대한 좋은 설명을 찾기가 어려웠습니다.

사용자 정의 컨텍스트에 대한 문서는 매우 얇습니다. API 문서에서 찾을 수 있는 유일한 언급은 여기에 있습니다. 그리고 이러한 유효성 검사에 대한 API 문서에는 사용자 정의 컨텍스트가 전혀 언급되어 있지 않습니다! 이것은 특히 어렵습니다. 무언가의 이름을 모르는 경우 관련 문서를 어떻게 더 찾을 수 있습니까?

마침내 https://blog.arkency.com/2014/04/mastering-rails-validations-contexts/에서 좋은 개요를 찾았습니다. 읽을 가치가 있습니다. 우리의 예에서 어떻게 보이는지 봅시다:

앱/모델/article.rb
class Article < ActiveRecord::Base
  # validate in draft mode
  validates_presence_of :author_id
 
  # validate only when published
  validates_presence_of :body, on: :publish
  ...
end
앱/컨트롤러/article_controller.rb
class ArticleController < ApplicationController
  respond_to :html

  def create
    @article = Article.create(article_params)
    respond_with @article
  end

  def publish
    @article = Article.find(params[:id])
    @article.attributes = article_params
    @article.save(context: :publish)
    respond_with @article
  end

  private
  def article_params
    params.
      require(:article).
      permit(:body, :title, :author_id)
  end
end

나쁘지 않아! 유일한 이상한 점은 save를 사용해야 한다는 것입니다. update 대신 게시 방법에서. 이는 update 때문에 발생합니다. 유효성 검사 컨텍스트를 매개변수로 사용할 수 없습니다. (그게 풀 리퀘스트의 기회가 아닐까요?)

저장 이상

사용자 지정 유효성 검사 컨텍스트는 다양한 방법으로 레코드를 저장하는 것 이상으로 유용합니다. 컨텍스트는 valid?와 함께 작동합니다. :

@article.valid?(:publish)

따라서 “이 개체에 이 속성이 있습니까? 그렇지 않다면 그 이유는 무엇입니까?”

DHH는 -able?로 끝나는 메소드를 생성합니다. valid?(:context)에 위임 ). 그 모습이 정말 마음에 듭니다:

앱/모델/article.rb
class Article
  validate :has_been_published, on: :view
  validate :is_not_spam, on: :view

  def viewable?
    valid? :view
  end

  private

  def has_been_published
    if published_at.future?
      errors.add(:published_at, "is in the future")
    end
  end

  def is_not_spam
    if is_spam?(body)
      errors.add(:body, "has been detected as spam")
    end
  end
end

이렇게 하면 확인할 때 true보다 더 많은 정보를 얻을 수 있습니다. 또는 false :

unless @article.viewable?
  # @article.errors is now filled out
end

기사를 볼 수 있습니까? 글쎄요?

충분히 가벼움

이러한 종류의 유효성 검사 동작을 얻을 수 있는 몇 가지 다른 방법이 있습니다. 사용자 정의 ActiveModel을 빌드할 수 있습니다. 자체 유효성 검사가 있는 서비스 개체. :if를 사용할 수 있습니다. 또는 :unless 당신의 검증에. 그러나 Rails의 많은 항목과 마찬가지로 사용자 지정 유효성 검사 컨텍스트는 가독성과 유연성 사이에서 좋은 절충안입니다.