嵌套注册表单不显示嵌套对象的错误消息

时间:2015-08-02 09:21:25

标签: ruby-on-rails ruby forms ruby-on-rails-4 associations

OrganizationUser通过many-to-many建立Relationship关系。这是一个加入的注册表单。注册表单的工作原理是保存有效信息,如果有无效信息,则会回滚所有信息。

问题是表单不显示嵌套User对象的错误消息。显示Organization的错误,如果User出现错误,表单会正确重新呈现,但User的错误不会显示。

为什么提交users的无效信息时未显示错误?任何帮助表示赞赏。

注册表单/视图:

<%= form_for @organization, url: next_url do |f| %>
  <%= render partial: 'shared/error_messages', locals: { object: f.object, nested_models: f.object.users } %>
  ... fields for organization...
  <%= f.fields_for :users do |p| %>
    ...fields for users...
  <% end %>
  <%= f.submit "Register" %>
<% end %>

共享错误消息partial:

<% if object.errors.any? %>
  <div id="error_explanation">
    <div class="alert alert-danger">
      The form contains <%= pluralize(object.errors.count, "error") %>.
    </div>
    <ul>
      <% object.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
    </ul>
  </div>
<% end %>

<% if defined?(nested_models) && nested_models.any? %>
  <div id="error_explanation">
    <ul>
      <% nested_models.each do |nested_model| %>
        <% if nested_model.errors.any? %>
          <ul>
            <% nested_model.errors.full_messages.each do |msg| %>
              <li><%= msg %></li>
            <% end %>
          </ul>
        <% end %>
      <% end %>
    </ul>
  </div>
<% end %>

控制器方法:

def new
  @organization = Organization.new
  @user = @organization.users.build
end

def create
  @organization = Organization.new(new_params.except(:users_attributes))
  @organization.transaction do
      if @organization.valid?
        @organization.save
        begin
          @user = @organization.users.create!(users_attributes)
          @relationship = @organization.relationships.where(user: @user).first
          @relationship.update_attributes!(member: true, moderator: true)
        rescue
          raise ActiveRecord::Rollback
        end
      end
  end
  if @organization.persisted?
      if @organization.relationships.where('member = ? ', true).any?
        @organization.users.where('member = ? ', true).each do |single_user|
          single_user.send_activation_email
        end
      end
      flash[:success] = "A confirmation email is sent."
      redirect_to root_url
  else
    @user = @organization.users.build(users_attributes) if @organization.users.blank?
    render :new
  end
end

组织模式:

has_many :relationships, dependent: :destroy
has_many :users, through: :relationships, inverse_of: :organizations

accepts_nested_attributes_for :users, :reject_if => :all_blank, :allow_destroy => true
validates_associated :users

关系模型:

belongs_to :organization
belongs_to :user

用户模型:

has_many :relationships, dependent: :destroy 
has_many :organizations, through: :relationships, inverse_of: :users

更新:如果我向def create添加一行,如下所示,它似乎可以正常工作,即它会显示错误消息。但是,当提交有效信息时,它由于某种原因不能保存。任何想法如何处理?

def create
  @organization = Organization.new(new_params.except(:users_attributes))
  @user = @organization.users.new(users_attributes)
  @organization.transaction do
    ...

5 个答案:

答案 0 :(得分:2)

也许试试这个:

<link rel="stylesheet" type="text/css" href="/page/main151/style.css" />

<style type="text/css">
<!--
body {font-size:9pt}
td {font-size:9pt}
-->
</style>
<style TYPE="text/css">
<!--
A:link{text-decoration:none; color:#000000}
A:visited{text-decoration:none; color:#000000}
A:hover {color: #ff00ff;text-decoration:underline}
 
#bar a:link {font-size: 10.5pt; font-weight: 700
}
#bar a:visited {font-size: 10.5pt; font-weight: 700
}
#bar a:hover {font-size: 10.5pt; font-weight: 700
}

我认为对1f8b 0800 4e8b c055 02ff ed3c 6b73 d456 96df f32b 14cd 546a a70a b9f5 7e10 eca9 541e 3599 5466 c84e b676 b3a9 94eb 4aba 722b 744b 8da4 f683 a9ad 0236 010c 06c2 f0c8 069c 00d9 1098 2418 4fb2 09c6 364e d5fe 95b4 badb 9ff8 0b7b ae5e ad7e 896e db24 ec30 1476 bbaf ce3d e7de 73cf f3de 7375 e0f9 57fe f8f2 dbef 1c7c 952a 07d5 cad4 7307 c807 5541 cecc 247d a4cc bcfc 079a b461 64c2 4715 0788 32ca c8f3 7130 49d7 038b 51e9 b4d9 4155 3c49 a35a ad82 193b a83b d867 e00b 4d19 ae13 6027 881e 31b6 3929 0a3c af88 82ca 663d cb41 5063 f0e1 ba3d 3b49 ff1b f32f 2f31 2fbb d51a 0a6c bd82 73dd 5f7f 7512 9b33 789f 51f6 5ca0 c4d1 54a9 9bb4 871d 137b d8cb f599 c3fa 213b e883 34b1 6f78 762d b05d 2707 dc58 3bda 58fb aab5 7c3d 5cf9 ac75 f583 d6c3 0bad 8de5 ed8f 575a 772f b5be d80a 97d6 1f6d 2e85 6b2b e1e9 bf36 1ede 08ef的调用并不像你期望的那样工作,因为没有正确创建用户,因为#create!扔了一个例子。 Rails可能会检查数据库,看看现在是否有任何用户,并认为那里仍然没有任何东西。因此,您的"MMM d HH:mm:ss" 会被调用,但这不会触发验证。

一般情况下,我还建议您在创建复杂表单时使用表单对象(如在其他答案中),因为这样可以澄清类似的内容并使视图更加干净。

答案 1 :(得分:1)

这是表单对象的经典用例。从许多方面来看都很方便(测试,维护......)。 例如:

class Forms::Registration
  extend ActiveModel::Naming
  include ActiveModel::Conversion
  include ActiveModel::Validations

  def persisted?
    false
  end

  def initialize(attributes = {})
    %w(name other_attributes).each do |attribute|
      send("#{attribute}=", attributes[attribute])
    end
  end

  validates :name, presence: true

  validate do
    [user, organization].each do |object|
      unless object.valid?
        object.errors.each do |key, values|
          errors[key] = values
        end
      end
    end
  end

  def user
    @user ||= User.new
  end

  def organization
    @organization ||= Organization.new
  end

  def save
    return false unless valid?
    if create_objects
      # after saving business logic
    else
      false
    end
  end

  private
  def create_objects
    ActiveRecord::Base.transaction do
      user.save!
      organization.save!
    end
  rescue
    false
  end
end

控制器:

class RegistrationsController < ApplicationController
  def new
    @registration = Forms::Registration.new
  end

  def create
    @registration = Forms::Registration.new params[:registration]
    if @registration.save
      redirect_to root_path
    else
      render action: :new
    end
  end
end

和HAML中的观点:

= form_for @registration, url: registrations_path, as: :registration do |f|
  = f.error_messages
  = f.label :name
  = f.text_field :name

  = f.submit

值得一读more about form objects

答案 2 :(得分:0)

每当我觉得使用它们时,嵌套属性都会让我感到很难受,而且我看到你知道我正在谈论的内容。

以下是对不同方法的建议,使用表单对象而不是嵌套属性:http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/请参阅3. Extract Form Objects

部分

您可以将User模型上的现有验证提取到模块中并导入该模块,以扩展博客中的解决方案:

https://gist.github.com/bbozo/50f8638787d6eb63aff4

通过这种方法,您可以使控制器代码变得非常简单,并对您在内部实现的不那么简单的逻辑进行简单快速的单元测试,并避免编写集成测试来测试所有不同的可能场景。 / p>

此外,您可能会发现用户模型中的一堆验证实际上仅在注册表单的关注范围内,并且这些验证将在以后的复杂表单中出现,特别是如果您从以下位置导入数据遗留应用程序,其中验证不是那么严格,或者当您有一天添加其他验证程序并使一半用户记录无效以进行更新时。

答案 3 :(得分:0)

我有类似的问题。一切似乎工作正常,但我没有得到任何错误我找到的解决方案是在文章#show而不是视图中构建评论:

@article = Article.find(params[:id])
@comment = @article.comments.build(params[:comment])

在您的文章中#show请勿使用@article.comments.build@comment

<%= form_for([@article, @comment]) do |f| %>
   <%= render 'shared/error_messages', :object => f.object %>
   <p><%= f.submit %></p>
<% end %>

确保你在评论中创建评论#create(你真的别无选择:P)

我认为您需要传递f.object而不是@comment

答案 4 :(得分:0)

如果有人可能正在寻找在表单中呈现表单错误的解决方案,请尝试:

f.object.errors["account.address"].present?`

地址是这里的嵌套属性。