【问题标题】:Rails 4 - showing errors for nested associationsRails 4 - 显示嵌套关联的错误
【发布时间】:2014-09-02 01:27:19
【问题描述】:

我在两个模型之间有 belongs_tohas_many 关联。我有一个用户创建表单,它创建用户并在此过程中创建一个组织并将两者关联起来。我对是否存在组织名称进行了验证。如果验证失败,我希望OrganiationName cannot be blank 错误添加到User 具有的相同错误消息哈希中。基本上,创建一个错误消息列表。

这是我的模型:

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable, :lockable, :timeoutable

  belongs_to :organization

  validates_presence_of :display_name
end

class Organization < ActiveRecord::Base
  has_many :users, dependent: :destroy

  accepts_nested_attributes_for :users, :allow_destroy => true

  validates_presence_of :name
end

这是我的创建操作:

def create
  @user = User.new(sign_up_params)
  if params[:user][:organization][:access_code].blank?
    # create new organization
    @access_code = "#{SecureRandom.urlsafe_base64(16)}#{Time.now.to_i}"
    @organization = Organization.create(name: params[:user][:organization][:name], access_code: @access_code)
    @user.organization_id = @organization.id
    @user.is_admin = true
  else
    # try and add someone to an organization
    @organization = Organization.find(:all, conditions: ["name = ? AND access_code = ?", params[:user][:organization][:name], params[:user][:organization][:access_code]])
    if @organization.empty?
      flash.now[:error] = "No organization has been found with that name and access code."
      render :new
      return
    else
      @user.organization_id = @organization.first.id
    end
  end
  if @user.save
    flash[:success] = "Your account has been successfully created! Check your email for a confirmation link to activate your account."
    redirect_to sign_in_path
  else
    flash.now[:error] = "Something went wrong! Please try again."
    render :new
  end
end

这是我的观点:

<% provide(:title, 'Sign Up') %>

<h1>Create Account</h1>

<%= nested_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= render "shared/error_messages", obj: @user %>

  <fieldset>
    <legend>Account Information</legend>
    <div class="form-group">
      <%= f.label :email %>
      <%= f.email_field :email, class: "form-control", autofocus: true %>
    </div>
    <div class="form-group">
      <%= f.label :display_name, "Display Name" %>
      <%= f.text_field :display_name, class: "form-control" %>
    </div>
    <div class="form-group">
      <%= f.label :password %> <% if @validatable %><i>(<%= @minimum_password_length %> characters minimum)</i><% end %>
      <%= f.password_field :password, class: "form-control", autocomplete: "off" %>
    </div>
    <div class="form-group">
      <%= f.label :password_confirmation %>
      <%= f.password_field :password_confirmation, class: "form-control", autocomplete: "off" %>
    </div>
  </fieldset>
  <%= f.fields_for :organization do |o| %>
    <fieldset>
      <legend>Organization Information</legend>
      <p>
        <strong>Creating a New Organization:</strong> Fill out the Organization Name field, but leave the Access Code field blank.<br />
        <strong>Joining an Existing Organization:</strong> Fill out both the Organization Name and Access Code field, using the access code that you received from someone at your organization.
      </p>
      <div class="form-group">
        <%= o.label :name, "Organization Name" %>
        <%= o.text_field :name, class: "form-control" %>
      </div>
      <div class="form-group">
        <%= o.label :access_code, "Organization Access Code" %>
        <%= o.text_field :access_code, class: "form-control" %>
      </div>
    </fieldset>
  <% end %>
  <div class="form-actions">
    <%= f.submit "Create Account", class: "btn btn-primary" %>
    <%= link_to "Cancel", :back %>
  </div>
<% end %>

<%= render "users/shared/links" %>

还有,这是error_messages 部分:

<% if obj.errors.any? %>
  <div id="error_explanation">
    <h2>There are <%= pluralize(obj.errors.count, "error") %> errors with this form:</h2>
    <ul>
    <% obj.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %>
    </ul>
  </div>
<% end %>

User 的错误显示正常,但Organization 却没有。是否与仅将 @user 传递给部分有关?

【问题讨论】:

  • 如果您只传入用户,那么您只会收到用户对象的错误消息是有道理的,对吧?在你的控制器中,与其说 flash.now[:error] = "...",不如直接说 flash.now[:errors] = @user.errors.full_messages + @organization.errors。 full_messages?
  • flash 消息实际上与此问题无关。问题在于我通过我相信的模型设置的 ActiveModel 验证。我假设通过@user 是可以的,组织错误将通过@user.organization 进入。

标签: ruby-on-rails-4 devise nested-forms


【解决方案1】:

好的,我知道我的问题了。似乎我可能在模型关联方面遇到了一些问题,或者至少在 accepts_nested_attributes 方面有一些问题。

这是我更新的模型:

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable, :lockable, :timeoutable

  belongs_to :organization

  accepts_nested_attributes_for :organization

  validates_presence_of :display_name
end

class Organization < ActiveRecord::Base
  has_many :users, dependent: :destroy

  validates_presence_of :name
end

这是我在控制器中更新的创建操作:

def create
  @user = User.new(sign_up_params)
  if params[:user][:organization_attributes][:access_code].blank?
    # create new organization
    @access_code = "#{SecureRandom.urlsafe_base64(16)}#{Time.now.to_i}"
    @organization = Organization.create(name: params[:user][:organization_attributes][:name], access_code: @access_code)
    @user.organization_id = @organization.id
    @user.is_admin = true
  else
    # try and add someone to an organization
    @organization = Organization.find(:all, conditions: ["name = ? AND access_code = ?", params[:user][:organization_attributes][:name], params[:user][:organization_attributes][:access_code]])
    if @organization.empty?
      flash.now[:error] = "No organization has been found with that name and access code."
      render :new
      return
    else
      @user.organization_id = @organization.first.id
    end
  end
  if @user.save
    flash[:success] = "Your account has been successfully created! Check your email for a confirmation link to activate your account."
    redirect_to sign_in_path
  else
    flash.now[:error] = "Something went wrong! Please try again."
    render :new
  end
end

这是我的更新视图:

<% provide(:title, 'Sign Up') %>

<h1>Create Account</h1>

<%= nested_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= render "shared/error_messages", obj: @user %>

  <fieldset>
    <legend>Account Information</legend>
    <div class="form-group">
      <%= f.label :email %>
      <%= f.email_field :email, class: "form-control", autofocus: true %>
    </div>
    <div class="form-group">
      <%= f.label :display_name, "Display Name" %>
      <%= f.text_field :display_name, class: "form-control" %>
    </div>
    <div class="form-group">
      <%= f.label :password %> <% if @validatable %><i>(<%= @minimum_password_length %> characters minimum)</i><% end %>
      <%= f.password_field :password, class: "form-control", autocomplete: "off" %>
    </div>
    <div class="form-group">
      <%= f.label :password_confirmation %>
      <%= f.password_field :password_confirmation, class: "form-control", autocomplete: "off" %>
    </div>
  </fieldset>
  <% @user.build_organization unless @user.organization %>
  <%= f.fields_for :organization do |o| %>
    <fieldset>
      <legend>Organization Information</legend>
      <p>
        <strong>Creating a New Organization:</strong> Fill out the Organization Name field, but leave the Access Code field blank.<br />
        <strong>Joining an Existing Organization:</strong> Fill out both the Organization Name and Access Code field, using the access code that you received from someone at your organization.
      </p>
      <div class="form-group">
        <%= o.label :name, "Organization Name" %>
        <%= o.text_field :name, class: "form-control" %>
      </div>
      <div class="form-group">
        <%= o.label :access_code, "Organization Access Code" %>
        <%= o.text_field :access_code, class: "form-control" %>
      </div>
    </fieldset>
  <% end %>
  <div class="form-actions">
    <%= f.submit "Create Account", class: "btn btn-primary" %>
    <%= link_to "Cancel", :back %>
  </div>
<% end %>

<%= render "users/shared/links" %>

这是我更新的 error_messages 部分(仅显示上下文 - 更改的代码与问题并不真正相关):

<% if obj.errors.any? %>
  <div id="error_explanation">
    <h2><%= pluralize(obj.errors.count, "error") %> was found with this form:</h2>
    <ul>
    <% obj.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %>
    </ul>
  </div>
<% end %>

现在,当我尝试保存而不输入任何信息时,会显示所有正确的错误。此外,当我输入所有需要的用户数据并将所有组织字段留空时,将显示正确的组织相关验证错误,并且不会创建用户记录。就像我现在需要的那样工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多