5

次の包含検証に苦労しています。

class User < ActiveRecord::Base
  attr_accessible :language

  validates :language, :presence => true, :inclusion => { :in => I18n.available_locales.join(' ')}
end

これをコンソールで実行すると、

u = User.new
u.valid?

次にTypeError: can't convert nil into String、のinclude?メソッドでa を取得しactive_model/validations/inclusion.rbます。

ただし、検証行を次のように変更すると、

validates :language, :presence => true, :inclusion => { :in => %(en fr es)}

その後、検証は期待どおりに機能します。language が nil であるか、予想どおりリスト内のエントリの 1 つでない場合は無効であり、クラッシュはありません。

コードをステップ実行して、包含リストが正常に生成されていることを確認しました。では、なぜクラッシュするのでしょうか。プレゼンスの検証で問題が検出され、それ以上の検証が妨げられるべきではありませんか? また、値をハードコーディングするのではなく、リストを生成するとクラッシュするのはなぜですか?

proc 形式を使用して、:in違いが生じるかどうかを確認してみましたが、違いはありませんでした。しかし、アプリの実行中に I18n.available_locales が変更されることはないため、アプリが読み込まれたときに一度だけリストを生成したいので、それが必要になるとは本当に思っていませんでした。

更新: アイデアがあり、次のコードをテストしました。

class User < ActiveRecord::Base
  attr_accessible :language

  validates :language, :presence => true, :inclusion => { :in => ['en','fr','es'].join(' ') }
end

このコードも同じエラーを生成するため、問題は I18n などにはありません。と の違いに関係してい%(en fr es)ます['en','fr','es'].join(' ')

4

2 に答える 2

12

2 番目の条件が機能する理由は#include?、String クラスに対して定義されているためです。

> "qwertyuiop".include? "tyu"
true

したがって、%(en fr es)(正確に"en fr es")に含まれていることを検証すると、値"n f"は検証に合格します。

配列を (リテラル[]または words として%w()) 使用する必要があります。I18n.available_locales を使用する場合は、必ず文字列に変換してください

validates :language, :inclusion => { :in => I18n.available_locales.map(&:to_s) }

エラーを再現することはできませんが、値がリストに含まれているかどうかが既にチェックされているため:presence、検証は役に立ちません。:inclusion

于 2012-09-30T08:56:09.187 に答える
4

文字列ではなく、配列をinclusion検証に渡す必要があります。したがって、%(en fr es)使用する場合の例では、%w(en fr es)正常に機能します。

于 2012-09-30T08:36:09.067 に答える