2017-03-17 12 views
4

私はreform-rails gemを使用しています。私のレールプロジェクトでフォームオブジェクトを利用するためです。レールは、コレクションが動作しないか検証されている改革柵のオブジェクトを形成します

フォームオブジェクトは、以下で使用するサンプルコードではおそらく過剰ですが、デモンストレーション用です。

userを作成しており、そのユーザーレコードに関連付けられているフォームには、2つのuser_emailsがあります。私はUserモデル内accepts_nested_attributes_for :user_emailsを使用していない

# models/user.rb 
class User < ApplicationRecord 
    has_many :user_emails 
end 

# models/user_email.rb 
class UserEmail < ApplicationRecord 
    belongs_to :user 
end 

注意してください。フォームオブジェクトの主なポイントの1つは、accepts_nested_attributes_forの使用を止めるのに役立つということです。だからこそ、これを使わずにこれをやろうとしています。私はthis videoからそのアイディアを得て、リファクタリング脂肪モデルについて話しています。私は、フォームオブジェクト上のビデオのセクションを指すリンクを持っており、彼はどれくらい嫌いなのかを表していますaccepts_nested_attributes_for

私はその後、私のuser_formの作成に進む:

# app/forms/user_form.rb 
class UserForm < Reform::Form 
    property :name 
    validates :name, presence: true 

    collection :user_emails do 
    property :email_text 
    validates :email_text, presence: true 
    end 
end 

のでuser_formオブジェクトがuser記録し、そのuserレコードに関連したuser_emailレコードのカップルをラップします。 フォーム・レベルの検証がありuser上とuser_emailは、このフォームはラップレコード:

  • user#nameは、各user_email#email_textが場合

値を持っている必要があります

  • 値を持っている必要がありますフォームは有効です:それは1つのuserレコードを作成し、次に関連する2つのレコードを作成する必要があります。user_emailフォームが有効でない場合は、フォームにエラー・メッセージを再表示する必要があります。

    私はここまでコントローラに何があるかを示します。簡潔にするために:最後

    # app/controllers/users_controller.rb 
    class UsersController < ApplicationController 
    
        def new 
        user = User.new 
        user.user_emails.build 
        user.user_emails.build 
        @user_form = UserForm.new(user) 
        end 
    
        def create 
        @user_form = UserForm.new(User.new(user_params)) 
        if @user_form.valid? 
         @user_form.save 
         redirect_to users_path, notice: 'User was successfully created.' 
        else 
         render :new 
        end 
        end 
    
        private 
        def user_params 
         params.require(:user).permit(:name, user_emails_attributes: [:_destroy, :id, :email_text]) 
        end 
    end 
    

    :フォーム自体:試験として

    # app/views/users/_form.html.erb 
    <h1>New User</h1> 
    <%= render 'form', user_form: @user_form %> 
    <%= link_to 'Back', users_path %> 
    

    # app/views/users/_form.html.erb 
    <%= form_for(user_form, url: users_path) do |f| %> 
        <% if user_form.errors.any? %> 
        <div id="error_explanation"> 
         <h2><%= pluralize(user_form.errors.count, "error") %> prohibited this user from being saved:</h2> 
    
         <ul> 
         <% user_form.errors.full_messages.each do |message| %> 
         <li><%= message %></li> 
         <% end %> 
         </ul> 
        </div> 
        <% end %> 
    
        <div class="field"> 
        <%= f.label :name %> 
        <%= f.text_field :name %> 
        </div> 
        <% f.fields_for :user_emails do |email_form| %> 
        <div class="field"> 
         <%= email_form.label :email_text %> 
         <%= email_form.text_field :email_text %> 
        </div> 
        <% end %> 
    
        <div class="actions"> 
        <%= f.submit %> 
        </div> 
    <% end %> 
    

    newのみ作用createアクションを表示ここで入力された値を持つ形であります:

    enter image description here

    今すぐ提出します。何が起きるべきかは、2番目の電子メールの値が存在しなければならないため、検証エラーが発生するはずです。ただし、ここにログを投稿すると、ログは次のようになります。

    Parameters: {"utf8"=>"✓", "authenticity_token"=>”123abc==", "user"=>{"name"=>"neil", "user_emails_attributes"=>{"0"=>{"email_text"=>"email_test1"}, "1"=>{"email_text"=>""}}}, "commit"=>"Create User"} 
    
    ActiveModel::UnknownAttributeError (unknown attribute 'user_emails_attributes' for User.): 
    

    私のフォームオブジェクトに問題があります。

    このフォームオブジェクトを機能させるにはどうすればよいですか?reform_railsを使用して、このフォームオブジェクトをなしでなしで使用することは可能ですか?accepts_nested_attributesを使用していますか?最終的には、私はちょうどオブジェクトobjetを働かせたいと思っています。

    私はすでに改革・レールのドキュメントに加えて、調査してきたいくつかのリソース:フォームオブジェクトを作成する

    私の最初の試みはしていましたvirtus gemが、私はどちらかを動作させるように見えませんでした。私はその実装のためにstackoverflow questionを投稿しました。

  • +0

    Reformが、永続化されていない場合のパラメータからコレクションオブジェクトのインスタンス化と検証を処理する方法を確認したい場合があります。 'accepts_nested_attributes_for'には、たとえば空白を拒否するオプションがあります。 – coreyward

    答えて

    5

    完全な答え:

    モデル:

    # app/models/user.rb 
    class User < ApplicationRecord 
        has_many :user_emails 
    end 
    
    # app/models/user_email.rb 
    class UserEmail < ApplicationRecord 
        belongs_to :user 
    end 
    

    フォームオブジェクト:

    # app/forms/user_form.rb 
    # if using the latest version of reform (2.2.4): you can now call validates on property 
    class UserForm < Reform::Form 
        property :name, validates: {presence: true} 
    
        collection :user_emails do 
        property :email_text, validates: {presence: true} 
        end 
    end 
    

    コントローラー:

    # app/controllers/users_controller.rb 
    class UsersController < ApplicationController 
        before_action :user_form, only: [:new, :create] 
    
        def new 
        end 
    
        # validate method actually comes from reform this will persist your params to the Class objects 
        # you added to the UserForm object. 
        # this will also return a boolean true or false based on if your UserForm is valid. 
        # you can pass either params[:user][:user_emails] or params[:user][user_email_attributes]. 
        # Reform is smart enough to pick up on both. 
        # I'm not sure you need to use strong parameters but you can. 
    
        def create  
        if @user_form.validate(user_params) 
         @user_form.save 
         redirect_to users_path, notice: 'User was successfully created.' 
        else 
         render :new 
        end 
        end 
    
        private 
    
        # call this method in a hook so you don't have to repeat 
        def user_form 
        user = User.new(user_emails: [UserEmail.new, UserEmail.new]) 
        @user_form ||= UserForm.new(user) 
        end 
    
        # no need to add :id in user_emails_attributes 
        def user_params 
        params.require(:user).permit(:name, user_emails_attributes: [:_destroy, :email_text]) 
        end 
    end 
    

    フォーム:

    # app/views/users/new.html.erb 
    <h1>New User</h1> 
    <%= render 'form', user_form: @user_form %> 
    <%= link_to 'Back', users_path %> 
    

    #app/views/users/_form.html.erb 
    <%= form_for(user_form, url: users_path) do |f| %> 
        <% if user_form.errors.any? %> 
        <div id="error_explanation"> 
         <h2><%= pluralize(user_form.errors.count, "error") %> prohibited this user from being saved:</h2> 
    
         <ul> 
         <% user_form.errors.full_messages.each do |message| %> 
         <li><%= message %></li> 
         <% end %> 
         </ul> 
        </div> 
        <% end %> 
    
        <div class="field"> 
        <%= f.label :name %> 
        <%= f.text_field :name %> 
        </div> 
        <%= f.fields_for :user_emails do |email_form| %> 
        <div class="field"> 
         <%= email_form.label :email_text %> 
         <%= email_form.text_field :email_text %> 
        </div> 
        <% end %> 
    
        <div class="actions"> 
        <%= f.submit %> 
        </div> 
    <% end %> 
    
    +0

    うわー!本当にありがとう!すべての部分を含む私のマイナーな編集を承認してください(完了のために)私は喜んであなたの答えを受け入れられた答えとしてマークします! – Neil

    +0

    ちょうどあなたの編集を承認しました –

    +0

    私は[virtus実装の質問](http://stackoverflow.com/questions/42861425/rails-form-object-with-virtus-has-many-association)であなたの答えに取り組んでいます。あなたがそれに気づいている場合:私の[生のレール5のフォームオブジェクトの実装に関する質問](http://stackoverflow.com/questions/42930117/form-objects-in-rails)をチェックアウトしてください。残念ながら、私は評判の点からかなり外れていますので、私はその点について多大な恩恵を提供することはできません。 – Neil

    1

    私は最終的にそれが働いてしまいました!

    まず、Rails 5にコレクションを保存することができませんでした。私は4.2.6を作成しました。改革宝石のgithubリポジトリページに問題を作成することをお勧めします。

    だから、これは作業コードです:

    モデル/ user.rb

    class User < ActiveRecord::Base 
        has_many :user_emails 
    end 
    

    モデル/ user_email.rb

    class UserEmail < ActiveRecord::Base 
        belongs_to :user 
    end 
    

    user_form.rb

    class UserForm < Reform::Form 
    
        property :name 
        validates :name, presence: true 
    
        collection :user_emails, populate_if_empty: UserEmail do 
        property :email_text 
        validates :email_text, presence: true 
        end 
    end 
    

    populate_if_emptyは、検証が行われるときに重要です。

    def create 
        @user_form = UserForm.new(User.new) 
        if @user_form.validate(user_params) 
        @user_form.save 
        redirect_to users_path, notice: 'User was successfully created.' 
        else 
        render :new 
        end 
    end 
    

    この意志validatesあなたのUserモデルだけでなく、任意のネストされた団体:

    そして、コントローラは、メソッドを作成します。

    ありがとうございます!ドライモデル、モデルの検証と保存、および関連付け。

    こちらがお役に立てば幸いです。

    関連する問題