さまざまな検証状況を処理するための軽量な方法
(この投稿を数か月前にリストに送信しました。気に入って、もっと読みたい場合は、登録する必要があります!)
先日、自分のアプリの1つで奇妙な状況に遭遇しました。
Article
があるとします モデルであり、これらの記事は最初にドラフトとして作成されます。これらのドラフトは軽量である必要があります。本文やタイトルさえも必要とせずに、すぐに作成および編集できるようにする必要があります。
ただし、公開すると これらの記事では、追加の検証が必要です。タイトル、本文、その他すべてのものが必要です。
あなたはたくさんのif
を書くことができます 自分でチェックするステートメント。しかし、Railsから得られるすべての優れたフォーム処理を利用できるわけではありません。そして、Railsがうまく処理できるものにRailsを使用することで、後で多くの頭痛の種を減らすことができることがわかりました。これに検証を使用する方法はまだありますか?
if
およびunless
?
検証は:if
をサポートします および:unless
パラメータですが、これは必ずしもきれいではありません:
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/。読む価値があります。この例でどのように見えるか見てみましょう:
class Article < ActiveRecord::Base
# validate in draft mode
validates_presence_of :author_id
# validate only when published
validates_presence_of :body, on: :publish
...
end
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)
に委任します )。私はその外観が本当に好きです:
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の多くのものと同様に、カスタム検証コンテキストは、読みやすさと柔軟性の間の適切な妥協点です。
-
ラックアプリケーションで受信メールを処理する
クライアントから電話がありました... 彼は自分のアプリで受信メールを処理することを望んでいます 。 Basecampと同じように。 問題ありません。多くのサービスがPOSTでアプリにメールを送信します。簡単なはずです。でしょ? いいえ。 各サービスは独自の形式を使用します。 解析された電子メールを送信するものもあれば、生で送信するものもあります。認証署名を送信するものもあります。しない人もいます。 この部分をスキップして、標準の(よく知られている)ルビーオブジェクトを操作できたら素晴らしいと思いませんか? コードを書き直さずにベンダーを変更できたら素晴らしいと思いませんか? I
-
Railsアプリのパフォーマンスを理解するための新しい方法
Railsアプリは遅いですか? 単純なビューであるはずのものをロードするのに数秒かかる場合、掘り下げる価値のある問題があります。 データベース呼び出しが多すぎるか、メソッドが遅い可能性があります。あるいは、誰かがあなたのコードに入れて忘れてしまったスピードアップループかもしれません。 アプリの速度を低下させている原因を見つけるのに役立つツールがたくさんあります。数週間前、私はrbtraceについて話しました 。 NewRelicのrpm gemは、アプリの高速化にも役立ちました。 しかし、パフォーマンスの問題を調査するための私のお気に入りのツールは、さらに多くのことを行います。 箱か