当@user为空时,如何使这个if语句工作?

时间:2013-06-03 16:48:23

标签: ruby-on-rails

我有一个标题链接到我的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

3 个答案:

答案 0 :(得分: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?.empty?
  • 的组合
  • .present?实际上是.blank?
  • 的相反结果

答案 1 :(得分: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>

答案 2 :(得分:1)

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

我认为你真正想要使用的是flash。在这种情况下,您需要application.html.erb中的类似内容。

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

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

如果您的错误消息来自您的模型,那么这应该是实际生成这些错误消息的一部分。通常,这是对控制器中的createupdate操作的调用。在这种情况下,当您的验证未通过时,您应该使用表单呈现error_messages部分,并使用模型对象再次呈现表单。

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

通过这种方式,您可以确信@user对象始终可用于部分呈现而没有任何错误,因为我们明确地将对象传递给部分本身,并且正在使用正确的呈现部分上下文。在部分中使用@users等同于使用全局变量,因此整个应用程序依赖于该全局变量存在。

现在使用部分中的局部变量@user访问object对象(或者您决定最终命名它的任何内容)。

<% object.errors.full_messages.each do |message| %>
  <li>* <%= message %></li>
<% end %>