Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

さまざまな検証状況を処理するための軽量な方法

(この投稿を数か月前にリストに送信しました。気に入って、もっと読みたい場合は、登録する必要があります!)

先日、自分のアプリの1つで奇妙な状況に遭遇しました。

Articleがあるとします モデルであり、これらの記事は最初にドラフトとして作成されます。これらのドラフトは軽量である必要があります。本文やタイトルさえも必要とせずに、すぐに作成および編集できるようにする必要があります。

ただし、公開すると これらの記事では、追加の検証が必要です。タイトル、本文、その他すべてのものが必要です。

あなたはたくさんのifを書くことができます 自分でチェックするステートメント。しかし、Railsから得られるすべての優れたフォーム処理を利用できるわけではありません。そして、Railsがうまく処理できるものにRailsを使用することで、後で多くの頭痛の種を減らすことができることがわかりました。これに検証を使用する方法はまだありますか?

if およびunless

検証は:ifをサポートします および:unless パラメータですが、これは必ずしもきれいではありません:

app / models / 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ドキュメントには、カスタムコンテキストについてはまったく触れられていません。これは特に困難になります– 何かが何と呼ばれているのかわからない場合、どのようにしてそれに関するより多くのドキュメントを見つけますか?

私はついにここで良い概要を見つけました:http://blog.arkency.com/2014/04/mastering-rails-validations-contexts/。読む価値があります。この例でどのように見えるか見てみましょう:

app / models / 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
app / controllers / 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)に委任します )。私はその外観が本当に好きです:

app / models / 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の多くのものと同様に、カスタム検証コンテキストは、読みやすさと柔軟性の間の適切な妥協点です。


  1. ラックアプリケーションで受信メールを処理する

    クライアントから電話がありました... 彼は自分のアプリで受信メールを処理することを望んでいます 。 Basecampと同じように。 問題ありません。多くのサービスがPOSTでアプリにメールを送信します。簡単なはずです。でしょ? いいえ。 各サービスは独自の形式を使用します。 解析された電子メールを送信するものもあれば、生で送信するものもあります。認証署名を送信するものもあります。しない人もいます。 この部分をスキップして、標準の(よく知られている)ルビーオブジェクトを操作できたら素晴らしいと思いませんか? コードを書き直さずにベンダーを変更できたら素晴らしいと思いませんか? I

  2. Railsアプリのパフォーマンスを理解するための新しい方法

    Railsアプリは遅いですか? 単純なビューであるはずのものをロードするのに数秒かかる場合、掘り下げる価値のある問題があります。 データベース呼び出しが多すぎるか、メソッドが遅い可能性があります。あるいは、誰かがあなたのコードに入れて忘れてしまったスピードアップループかもしれません。 アプリの速度を低下させている原因を見つけるのに役立つツールがたくさんあります。数週間前、私はrbtraceについて話しました 。 NewRelicのrpm gemは、アプリの高速化にも役立ちました。 しかし、パフォーマンスの問題を調査するための私のお気に入りのツールは、さらに多くのことを行います。 箱か