gpt4 book ai didi

ruby-on-rails - Rails 中的表单对象

转载 作者:数据小太阳 更新时间:2023-10-29 08:02:41 27 4
gpt4 key购买 nike

下面的示例代码是一个尝试使用表单对象的人为示例,其中使用表单对象可能有点矫枉过正。尽管如此:它显示了我遇到的问题:

我有两个模型:UserEmail:

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

# app/models/user.rb
class Email < ApplicationRecord
belongs_to :user
end

我想创建一个表单对象,它创建一个用户记录,然后创建三个关联的电子邮件记录。

这是我的表单对象类:

# app/forms/user_form.rb
class UserForm
include ActiveModel::Model

attr_accessor :name, :email_forms

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)
email_forms.each do |email|
Email.create(user: user, email_text: email.email_text)
end
end
end

# app/forms/email_form.rb
class EmailForm
include ActiveModel::Model

attr_accessor :email_text, :user_id

validates :email_text, presence: true

def save
if valid?
persist!
true
else
false
end
end

private

def persist!
puts "The Form is VALID!"
# DON'T THINK I WOULD PERSIST DATA HERE
# INSTEAD DO IT IN THE user_form
end
end

注意:表单对象的验证。如果 name 属性为空,或者 email_text 属性为任何 留空,则 user_form 被视为无效email_form 对象在它的 email_forms 数组中。

为简洁起见:我将只介绍利用 user_formnewcreate 操作:

# app/controllers/user_controller.rb
class UsersController < ApplicationController

def new
@user_form = UserForm.new
@user_form.email_forms = [EmailForm.new, EmailForm.new, EmailForm.new]
end

def create
@user_form = UserForm.new(user_form_params)

if @user_form.save
redirect_to users_path, notice: 'User was successfully created.'
else
render :new
end
end

private

def user_form_params
params.require(:user_form).permit(:name, {email_forms: [:_destroy, :id, :email_text, :user_id]})
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>

# MESSY, but couldn't think of a better way to do this...
<% unique_index = 0 %>
<% user_form.email_forms.each do |email_form| %>
<div class="field">
<%= label_tag "user_form[email_forms][#{unique_index}][email_text]", "Email Text" %>
<%= text_field_tag "user_form[email_forms][#{unique_index}][email_text]" %>
</div>
<% unique_index += 1 %>
<% end %>


<div class="actions">
<%= f.submit %>
</div>
<% end %>

表单确实呈现:

picture of rendered form with input

这是表单的 html:

html of the form

我去提交表格。这是参数哈希:

Parameters: {"utf8"=>"✓", "authenticity_token"=>”abc123==", "user_form"=>{"name"=>"neil", "email_forms"=>{"0"=>{"email_text"=>"test_email_1"}, "1"=>{"email_text"=>"test_email_2"}, "2"=>{"email_text"=>""}}}, "commit"=>"Create User form"}

应该发生的是表单应该被重新呈现并且没有任何东西被保留,因为 form_object 是无效的:所有三个关联的电子邮件都不能为空。然而:form_object 认为它是有效的,它在 UserFormpersist! 方法中爆炸了。它突出显示 Email.create(user: user, email_text: email.email_text) 行并说:

undefined method `email_text' for ["0", {"email_text"=>"test_email_1"}]:Array

很明显,有几件事正在发生:嵌套验证似乎不起作用,而且我无法从 params 哈希重建每封电子邮件。

我已经检查过的资源:

  • This Article看起来很有希望,但我很难让它发挥作用。
  • 我已尝试使用 virtus gem 和 reform-rails gem 进行实现。我也为这两种实现发布了悬而未决的问题:virtus attempt here然后 reform-rails attempt here .
  • 我曾尝试插入 accepts_nested_attributes,但在弄清楚如何将其与表单对象以及嵌套表单对象(如本代码示例)一起使用时遇到了麻烦。部分问题是 has_manyaccepts_nested_attributes_for 似乎没有包含在 ActiveModel::Model 中。

任何有关让此表单对象执行预期操作的指导将不胜感激!谢谢!

最佳答案

完整答案

模型:

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

#app/models/email.rb
class Email < ApplicationRecord
belongs_to :user
end

Controller :

#app/controllers/users_controller.rb
class UsersController < ApplicationController

def index
@users = User.all
end

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 users_path, notice: 'User was successfully created.'
else
render :new
end
end


private

def user_form_params
params.require(:user_form).permit(:name, {emails_attributes: [:email_text]})
end
end

表单对象:

#app/forms/user_form.rb
class UserForm
include ActiveModel::Model

attr_accessor :name, :emails

validates :name, presence: true
validate :all_emails_valid


def emails_attributes=(attributes)
@emails ||= []
attributes.each do |_int, email_params|
email = EmailForm.new(email_params)
@emails.push(email)
end
end

def save
if valid?
persist!
true
else
false
end
end

private

def persist!
user = User.new(name: name)
new_emails = emails.map do |email_form|
Email.new(email_text: email_form.email_text)
end
user.emails = new_emails
user.save!
end

def all_emails_valid
emails.each do |email_form|
errors.add(:base, "Email Must Be Present") unless email_form.valid?
end
throw(:abort) if errors.any?
end
end


app/forms/email_form.rb
class EmailForm
include ActiveModel::Model

attr_accessor :email_text, :user_id
validates :email_text, presence: true
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 :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 中的表单对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42930117/

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