我有一個艱難的時間搞清楚如何使一個form_object創建多個關聯對象has_many
與virtus gem關聯。Rails窗體對象與Virtus:has_many關聯
下面是一個人爲的例子,其中一個表單對象可能是矯枉過正,但它確實表明我遇到的問題:
比方說,有一個創建user
記錄一user_form
對象,然後一對夫婦的相關user_email
記錄。下面是型號:
# models/user.rb
class User < ApplicationRecord
has_many :user_emails
end
# models/user_email.rb
class UserEmail < ApplicationRecord
belongs_to :user
end
我繼續創建一個表單對象來表示用戶形式:
# app/forms/user_form.rb
class UserForm
include ActiveModel::Model
include Virtus.model
attribute :name, String
attribute :emails, Array[EmailForm]
validates :name, presence: true
def save
if valid?
persist!
true
else
false
end
end
private
def persist!
puts "The Form is VALID!"
puts "I would proceed to create all the necessary objects by hand"
# user = User.create(name: name)
# emails.each do |email_form|
# UserEmail.create(user: user, email: email_form.email_text)
# end
end
end
One將在UserForm
類,我有attribute :emails, Array[EmailForm]
通知。這是試圖驗證和捕獲將爲相關的user_email
記錄保留的數據。這裏是Embedded Value
形式爲user_email
記錄:
# app/forms/email_form.rb
# Note: this form is an "Embedded Value" Form Utilized in user_form.rb
class EmailForm
include ActiveModel::Model
include Virtus.model
attribute :email_text, String
validates :email_text, presence: true
end
現在,我會繼續前進,顯示其中規定了user_form的users_controller
。
# app/controllers/users_controller.rb
class UsersController < ApplicationController
def new
@user_form = UserForm.new
@user_form.emails = [EmailForm.new, EmailForm.new, EmailForm.new]
end
def create
@user_form = UserForm.new(user_form_params)
if @user_form.save
redirect_to @user, notice: 'User was successfully created.'
else
render :new
end
end
private
def user_form_params
params.require(:user_form).permit(:name, {emails: [:email_text]})
end
end
的new.html.erb
:
<h1>New User</h1>
<%= render 'form', user_form: @user_form %>
而且_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>
<% unique_index = 0 %>
<% f.object.emails.each do |email| %>
<%= label_tag "user_form[emails][#{unique_index}][email_text]","Email" %>
<%= text_field_tag "user_form[emails][#{unique_index}][email_text]" %>
<% unique_index += 1 %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
注:如果有一個更簡單,更傳統的方式顯示在此user_emails
輸入形式對象:讓我知道。我無法獲得fields_for
的工作。如上所示:我必須親手寫出name
屬性。
的好消息是,形式也呈現:
形式的HTML看起來不錯對我說:
當上述輸入提交:在這裏是參數哈希:
Parameters: {"utf8"=>"✓", "authenticity_token"=>」abc123==", "user_form"=>{"name"=>"neil", "emails"=>{"0"=>{"email_text"=>"foofoo"}, "1"=>{"email_text"=>"bazzbazz"}, "2"=>{"email_text"=>""}}}, "commit"=>"Create User form"}
params哈希對我來說看起來不錯。
在日誌中我得到兩個廢棄警告,這讓我覺得VIRTUS可能已經過期,並在軌道表單對象從而不再是一個有效的解決方案:
DEPRECATION WARNING: Method to_hash is deprecated and will be removed in Rails 5.1, as
ActionController::Parameters
no longer inherits from hash. Using this deprecated behavior exposes potential security problems. If you continue to use this method you may be creating a security vulnerability in your app that can be exploited. Instead, consider using one of these documented methods which are not deprecated: http://api.rubyonrails.org/v5.0.2/classes/ActionController/Parameters.html (called from new at (pry):1) DEPRECATION WARNING: Method to_a is deprecated and will be removed in Rails 5.1, asActionController::Parameters
no longer inherits from hash. Using this deprecated behavior exposes potential security problems. If you continue to use this method you may be creating a security vulnerability in your app that can be exploited. Instead, consider using one of these documented methods which are not deprecated: http://api.rubyonrails.org/v5.0.2/classes/ActionController/Parameters.html (called from new at (pry):1) NoMethodError: Expected ["0", "foofoo"} permitted: true>] to respond to #to_hash from /Users/neillocal/.rvm/gems/ruby-2.3.1/gems/virtus-1.0.5/lib/virtus/attribute_set.rb:196:in `coerce'
然後整個事情出錯了與以下消息:
Expected ["0", <ActionController::Parameters {"email_text"=>"foofoo"} permitted: true>] to respond to #to_hash
我覺得我要麼關閉,我失去了一些東西小,以便爲它工作,或者我意識到VIRTUS已經過時,不再可用(通過廢棄警告)。
資源我看了看:
我沒有試圖讓相同的形式工作,但與reform-rails gem。我也遇到了一個問題。那個問題是posted here。
在此先感謝!
請接受修改,我會很樂意將您的答案標記爲已接受的答案。稍作修改以使驗證按預期工作,然後爲了方便:爲所有主要部分提供代碼。我想給你信貸,因爲你張貼的答案讓我通過了我被卡住的部分。 – Neil
應該指出的是,人們應該考慮使用virtu gem爲你的表單對象帶來的好處。機會是:你可以很容易地創建你的表單對象,而不需要將virt-gem依賴項添加到你的項目中。 [見Rails窗體對象實現在這裏](http://stackoverflow.com/questions/42930117/form-objects-in-rails/43024542#43024542) – Neil
感謝您的答案。這正是我一直在尋找的。 雖然我是Rails newb。有人可以向我解釋爲什麼我們需要定義'emails_attributes =(屬性)'。這是什麼調用?我發現如果這個方法沒有定義,那麼'@user_form.emails = [EmailForm.new,EmailForm.new,EmailForm.new]'不能按預期工作。 Rails中的這個魔術發生在哪裏? – user3574603