1

我有一个部分链接到我的 application.html.erb 的标题,如下所示:

<header class="unselectable">
  <h2 class="float_left">
    <% if @user.try(:errors).present? %>
      <%= render 'shared/error_messages' %>
    <% else %>
      <%= @title %>
    <% end %>
  </h2>

  <nav class="round">
    <ul>
        <% if logged_in? %>
          <li><%= link_to "Home", current_user %></li>
          <li><%= link_to "Settings", edit_user_path %></li>
          <li><%= link_to "Log out", logout_path %></li>
        <% else %>
          <li><%= link_to "Log in", login_path %></li>
        <% end %>
    </ul>
  </nav>
</header>

这一切都很好,除非加载的页面没有 @user 变量(例如 about 或 logout 页面),在这种情况下我得到这个:

undefined method `errors' for nil:NilClass

我怎样才能使这项工作?我尝试更改逻辑以呈现标题unless @user.errors.any?,但这也不起作用。我确定这是一个简单的修复,但我无法弄清楚!

编辑添加了建议的修复(在上面的部分标题中更新),现在得到这个错误:

No route matches {:action=>"edit", :controller=>"users"}这似乎来自edit_user_path

4

3 回答 3

3

您可以使用以下方法.try(:something)

<% if @user.try(:errors).present? %>
  <%= render 'shared/error_messages' %>
<% else %>
  <%= @title %>
<% end %>
  • 如果@usernil.try(:errors)则不会引发错误。

  • .present?方法nil也适用于:

.

>> nil.present?
#=> false
>> false.present?
#=> false
>> [].present?
#=> false
>> ''.present?
#=> false
>> 'bonjour'.present?
#=> true
>> ['bonjour'].present?
#=> true
  • .present?.nil?AND的组合.empty?
  • .present?实际上是相反的结果.blank?
于 2013-06-03T16:51:47.170 回答
1

你可以改写成这样:

<header>
  <h2 class="float_left">
    <% if @user.try(:errors).try(:any?) %>
      <%= render 'shared/error_messages' %>
    <% else %>
      <%= @title %>
    <% end %>   
  </h2>
...
</header>

或添加errors_any?到模型:

class User
  def errors_any?
    self.try(:errors).try(:any?)
  end
end

对此:

<header>
  <h2 class="float_left">
    <% if @user.try(:errors_any?) %>
      <%= render 'shared/error_messages' %>
    <% else %>
      <%= @title %>
    <% end %>   
  </h2>
...
</header>
于 2013-06-03T17:03:56.327 回答
1

我强烈质疑@user在您的应用程序布局中呈现的部分内容的需要,因此在应用程序的每个页面中都需要它。我认为这根本不是一个好的设计,因为现在您在应用程序的所有视图中都依赖于一个全局变量。

我认为您真正要使用的是flash。在这种情况下,您希望在application.html.erb.

<% flash.each do |key, value| %>
  <%= content_tag :div, value, class: key %>
<% end %>

这应该在呈现视图之前在适当的控制器操作中设置,以便根据刚刚发出的请求显示错误消息。

If your error messages come from your models, then this should be part of what actually generates these error messages. Typically this is a call to either create or update actions in the controller. In which case you should have the error_messages partial rendered with the form when your validations do not pass and the form is rendered again with the model object.

<%= form_for @user do |f| %>
  <%= render 'shared/error_messages', :object => f.object %>
  <!-- and so on -->
<% end %>

This way you can be confident that the @user object is always available for the partial to render without any errors since we're explicitly passing the object to the partial itself, and the partial is being rendered with the correct context. Using @users in your partial itself is the equivalent of using a global variable, hence the entire application relying on that global variable to exist.

The @user object is now accessed with a local variable in the partial as object (or whatever your decide to end up naming it).

<% object.errors.full_messages.each do |message| %>
  <li>* <%= message %></li>
<% end %>
于 2013-06-03T17:20:19.557 回答