

現在、Ruby On Railsでタグ機能を自作しております。  
ArticleモデルとTagモデル、中間モデルのおそらく一般的な実装です。

[code]

    has_many :article_tags, dependent: :destroy
    has_many :tags, through: :article_tags
    
[/code]

ArticleとTagを同時に保存したいと思っており、  
Articleを保存する際にコントローラーの処理に挟み込んでいます。

[code]

    if @article.save && @article.save_tags(tags_list)
      flash[:success] = "記事を作成しました"
      redirect_to articles_url
    else
      render 'articles/new'
    end
    
[/code]

`save_tags`メソッドの中で、バリデーションを行い（個数制限や文字数制限など）、  
`error.add`でエラーを追加。エラーだと`false`を返すようにしています。  
エラーメッセージの追加方法は以下のような感じ。

[code]

    errors.add(:tag_list, "タグの個数がオーバーしています。") if tags.count > 5
    
[/code]

この際、（当然なのですが）まず最初にArticleモデルのバリデーションが行われて、その後にTagのチェックが行われます。

つまり、まずArticleモデルのバリデーションをクリアしないとタグのエラーメッセージは表示されません（Articleモデルのバリデーションをクリアした場合、Tagのエラーメッセージが表示されます）。

例えば、Articleのタイトルがない状態で、かつ、タグが７個以上登録されている場合、エラーメッセージは

・Articleのタイトルが空です。

のみが表示されて、タグのバリデーション結果は表示されません。

希望としては、

・Articleのタイトルが空です。  
・タグの個数がオーバーしています。

を同時に出力したいです。

これはどのようにすれば実現するでしょうか？  
割とよくある形のような気がするのですが素人すぎて検索方法もわからず、、

ご教示頂けましたら幸いです。  
よろしくお願いいたします。


CC BY-SA 4.0
2018-09-06T13:27:58.060
48156
2023-02-07T04:02:55.353
2018-12-08T07:26:16.157
754
30015
question
ruby-on-rails ruby
Railsで別モデルのバリデーション結果も同時に出力したい


コメントですでに解決している様子ですが、回答にまとめます。

今回問題になっているのは、最初のレコード保存である `@article.save` が失敗したときに、 `@article.save &&
@article.save_tags(tag_list)` のうち後半部分の `save_tags`
が実行されず、結果、バリデーションを実行したならば追加されていたであろうエラーたちが、 errors に追加されないことが問題です。

ruby において `&&`, `||`
オペレーターは、その評価の際にショートサーキットという処理が行われます。何かと言うと、この２項演算子の最初の引数の時点で式の返り値が確定する場合、２つめの引数の評価を行わない、という処理です。

具体例でいうと、以下はエラーになりません。

[code]

    true || raise
    false && raise
    
[/code]

さて、今回の件では、むしろそのショートサーキットが邪魔で、ただただ両方を実行してその結果を and したい、が要件です。

そして、 ruby において、それを実現するためには、 `&` と `|` が利用できます。その実、これらはただの `TrueClass`,
`FalseClass` のメソッドとして定義されていて、なので、通常の２項演算子と同じように、

  1. 第一引数の評価
  2. 第二引数の評価
  3. オペレーター自体の演算処理(メソッド呼び出し)

の順で実行されます。

### 参考

  * <https://docs.ruby-lang.org/ja/2.5.0/class/FalseClass.html>
  * <https://docs.ruby-lang.org/ja/2.5.0/class/TrueClass.html>

> there is no short-circuit evaluation in this case.  
>  — `ri 'FalseClass#&'`


CC BY-SA 4.0
2018-12-08T07:25:40.237
51032
2018-12-08T07:25:40.237
754
48156
answer