Rails形成带有改造轨道的对象,集合无法正常工作或validation

我正在使用reform-rails gem为了在我的rails项目中使用表单对象。

我意识到表单对象对于我在下面使用的示例代码可能有点过分,但它是出于演示目的。

在我创建user的表单中,与该用户记录关联的是两个user_emails

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

请注意,我没有在User模型中使用accepts_nested_attributes_for :user_emails 。 在我看来,表单对象的一个​​要点是它可以帮助你摆脱使用accepts_nested_attributes_for ,所以这就是为什么我试图在没有它的情况下这样做。 我从这个讨论重构胖模型的video中得到了这个想法。 我有链接指向表单对象上的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记录进行表单级validation

  • user#name必须具有值
  • 每个user_email#email_text必须有一个值

如果表单有效:那么它应该创建一个user记录,然后创建几个关联的user_email记录。 如果表单无效:那么它应该重新呈现带有错误消息的表单。

到目前为止,我将展示控制器中的内容。 为简洁起见:仅显示new操作和create操作:

 # 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 

最后:forms本身:

 # app/views/users/_form.html.erb 

New User


 # app/views/users/_form.html.erb   

prohibited this user from being saved:

作为测试:这是带有输入值的表单:

在此处输入图像描述

现在我继续提交。 应该发生的是应该存在validation错误,因为必须存在第二封电子邮件的值。 但是,这里提交的是日志:

 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 情况下使此表单对象工作? 最终:我只想让表格对象起作用。

除了改革轨道文档之外,我已经探索过一些资源:

  • gitlab上的reform_example项目,已经过时了
  • 关于改革的文章
  • 另一篇文章

我第一次尝试制作一个表单对象就是使用了virtus gem ,但我似乎也无法使用它。 我也为该实现发布了stackoverflow问题 。

完整答案:

楷模:

 # 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 

New User

<%= 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? %> 

<%= pluralize(user_form.errors.count, "error") %> prohibited this user from being saved:

    <% user_form.errors.full_messages.each do |message| %>
  • <%= message %>
  • <% end %>
<% end %>
<%= f.label :name %> <%= f.text_field :name %>
<%= f.fields_for :user_emails do |email_form| %>
<%= email_form.label :email_text %> <%= email_form.text_field :email_text %>
<% end %>
<%= f.submit %>
<% end %>

我终于搞定了!

首先,我无法在Rails 5上保存它的集合。我创建了一个4.2.6并且它可以使用我们的盒子。 我建议你在Reform gem的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 

validation发生时, 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 

这将validation您的用户模型以及任何嵌套关联。

你有它! 干模型,validation和保存模型和关联。

我希望这有帮助!