gpt4 book ai didi

ruby-on-rails - Rails 表单对象与 reform-rails 与集合不工作或验证

转载 作者:数据小太阳 更新时间:2023-10-29 07:05:30 26 4
gpt4 key购买 nike

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

我意识到表单对象对于我在下面使用的示例代码来说可能有点矫枉过正,但它仅用于演示目的。

在我创建一个用户的表单中,与该用户记录关联的是两个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,所以这就是为什么我试图在没有它的情况下这样做。我从 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 记录记录。 useruser_email 记录有表单级验证,此表单包含:

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

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

到目前为止,我将展示 Controller 中的内容。为简洁起见:仅显示 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

最后:表单本身:

# 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 %>

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

enter image description here

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

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 的情况下工作?最终:我只想让表单对象正常工作。

除了 reform-rails 文档之外,我已经探索了一些资源:

我第一次尝试制作表单对象是使用 virtus gem ,但我似乎也无法让那个工作。我确实发布了 stackoverflow question对于该实现也是如此。

最佳答案

完整答案:

模型:

# 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

Controller :

# 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 %>

关于ruby-on-rails - Rails 表单对象与 reform-rails 与集合不工作或验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42866357/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com