Ruby on rails 在Rails中形成对象

Ruby on rails 在Rails中形成对象,ruby-on-rails,ruby,Ruby On Rails,Ruby,下面的示例代码是一个故意尝试使用表单对象的示例,在这种情况下,使用表单对象可能会有过大的杀伤力。尽管如此:它显示了我面临的问题: 我有两种型号:一个用户和一个电子邮件: # app/models/user.rb class User < ApplicationRecord has_many :emails end 注意:表单对象上的验证。如果用户表单的名称属性为空,或者如果电子邮件表单数组中的任何电子邮件表单对象的电子邮件文本属性为空,则认为该表单无效 为简洁起见:我将仅介绍使用用

下面的示例代码是一个故意尝试使用表单对象的示例,在这种情况下,使用表单对象可能会有过大的杀伤力。尽管如此:它显示了我面临的问题:

我有两种型号:一个
用户
和一个
电子邮件

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

注意:表单对象上的验证。如果
用户表单
名称
属性为空,或者如果
电子邮件表单
数组中的任何
电子邮件表单
对象的
电子邮件文本
属性为空,则认为该表单无效

为简洁起见:我将仅介绍使用
用户表单的
新建
创建
操作:

# 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
应该发生的是表单应该被重新呈现,并且没有任何内容被持久化,因为form_对象无效:所有三封关联的电子邮件都不能为空。但是:form_对象认为它是有效的,它在
persist中爆炸UserForm
上的code>方法。它突出显示
Email.create(用户:用户,Email\u文本:Email.Email\u文本)
行,并显示:

[“0”,{“email\u text”=>“test\u email\u 1}]:数组的未定义方法“email\u text”

很明显,有两件事正在发生:嵌套的验证似乎不起作用,而且我在从params散列重新生成每个电子邮件时遇到困难

我已经检查过的资源:

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

#app/models/email.rb
class Email < ApplicationRecord
  belongs_to :user
end
#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 %>
  • 看起来很有希望,但我很难让它发挥作用
  • 我已经尝试了使用virtus gem和reform rails gem的实现。我还为这两个实现发布了悬而未决的问题:然后
  • 我曾尝试插入
    接受嵌套的属性,但在弄清楚如何利用表单对象和嵌套表单对象(如本代码示例中)时遇到了问题。问题的一部分是
    有许多
    接受
    的嵌套属性似乎没有包含在
    ActiveModel::Model

非常感谢您提供有关如何让此表单对象执行预期操作的任何指导!谢谢

完整答案

型号:

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

#app/models/email.rb
class Email < ApplicationRecord
  belongs_to :user
end
#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 %>
视图:

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

#app/models/email.rb
class Email < ApplicationRecord
  belongs_to :user
end
#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 %>
app/views/users/new.html.erb
新用户
#app/views/users/_form.html.erb
禁止保存此用户:

您是否查看了“”的接受嵌套属性。。。这加上gem
cocoon
基本上消除了处理嵌套属性的所有困难。@SteveTurczyn是的,我已经看过了
接受嵌套属性。我在弄清楚如何在表单对象中为
实现
accepts\u nested\u attributes\u时遇到了很多麻烦。我更新了我的问题,表达了对这条路线的尝试。说真的,看看“茧”。这让一切变得容易。如果您在实现“cocoon”时遇到问题,请使用标签
RubyonRails
cocoon gem
发布问题,gem就在这里。。。我有同样的问题,用户模型有一个关联的模型地址。如果地址记录是否为空,如何设计formobject。如果地址记录为空,则应呈现地址字段,否则不应显示。