

モデルのバリデーションで

[code]

    class Hoge < ActiveRecord::Base
      validates :foo, presence: true
    end
    
[/code]

となっていた場合、必須項目であることをフォームに表示させたいと思っています。  
メタプログラミング的にモデルに`presence`が`true`か`false`問い合わせる方法はありませんか？

## 追記

考慮漏れしていたのですが  
`validates :foo, presence: true, if: -> { false }`  
とifを使ったパターンが抜けてしまっていました。できればこれにも対応したいです。  
（ifオプションがtrueかfalseか知る方法がわかればいけそうな気が...）

いけました。

`.options[:if]`にProcが入っているので、  
`.options[:if].call`でifオプションの結果が取得できました。

だたしやはり、  
`if: :admin?`のパターンはシンボルが入っているので`.call`できないですね...


CC BY-SA 3.0
2016-01-27T08:54:36.877
21378
2016-09-16T01:56:01.077
2016-02-01T00:45:01.727
5793
9008
question
ruby-on-rails
presenceがtrueかfalseか知る方法


`validators_on`を利用して以下のように判定する方法はいかがでしょうか。

[code]

    # presence: trueが設定されている場合、trueが返る
    Hoge.validators_on(:foo).any? { |_| _.is_a?(ActiveRecord::Validations::PresenceValidator) }
    
[/code]

参考:
<http://apidock.com/rails/ActiveModel/Validations/ClassMethods/validators_on>


CC BY-SA 3.0
2016-01-27T10:09:33.293
21387
2016-01-27T10:09:33.293
13874
21378
answer


こういうヘルパーメソッドを作ると便利かもしれません。

[code]

    def required_field?(obj, attribute)
      obj.class.validators_on(attribute).map(&:class).include?(ActiveRecord::Validations::PresenceValidator)
    end
    
    <% if required_field?(@user, :email) %>
      <span class="required">必須</span>
    <% end %>
    
[/code]

## 追記

> `validates :foo, presence: true, if: -> { false }`
> でもtrueになってしまうようです。できればこのパターンも考慮したいです。
>
> `.options[:if].call`でifオプションの結果が取得できました。

うーん、ifが指定された場合は、「ある程度」なら対応できるかもしれませんが、完璧を目指すのは難しそうです。

ifにはいろいろな指定方法があります。

[code]

    # シンボルを使う
    validates :name, presence: true, if: :admin?
    # 文字列を使う
    validates :name, presence: true, if: "admin?"
    # 関連先のオブジェクトを参照する
    validates :name, presence: true, if: -> { self.company.present? }
    
[/code]

さらに、ifと逆パターンのunlessオプションや、`on: :create`、`on: :update`といった、onオプションもあります。  
こういったケースにすべて対応させようと思うとかなり面倒なロジックが必要になりそうです。

そもそもifやunlessを使うと、オブジェクトの状態（条件）によって必須かどうかも変わるので、フォームを表示した時点では必須かどうか決定できない場合もあります。  
（例：フォームの管理者チェックボックスにチェックを入れた場合のみ名前が必須、等）

要件によっては「`.options[:if].call` で十分」ということもあるかもしれませんが、万能ではないという点に留意された方が良いと思います。

参考：[5
条件付きバリデーション](http://railsguides.jp/active_record_validations.html#%E6%9D%A1%E4%BB%B6%E4%BB%98%E3%81%8D%E3%83%90%E3%83%AA%E3%83%87%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3)


CC BY-SA 3.0
2016-01-27T10:55:35.837
21390
2016-01-28T00:01:41.130
2016-01-28T00:01:41.130
85
85
21378
answer


ちょっとズレますが情報提供的に。

ActiveModelのバリデーションの一部をHTMLに反映する(例: `validates presence: true` なら
`required="required"` を付ける)ことによってHTML5のクライアントサイドバリデーションを行なわせる
[amatsuda/html5_validators](https://github.com/amatsuda/html5_validators)
なんてのもあります。


CC BY-SA 3.0
2016-09-16T01:56:01.077
28917
2016-09-16T01:56:01.077
17037
21378
answer