如果语句导致新帐户出现NoMethodError

时间:2016-10-03 13:19:19

标签: ruby-on-rails ruby

我正在开展一个项目,我希望用户能够每天发帖一次。如果用户当天已有帖子,那么我希望UI元素用于提交不显示的帖子。要做到这一点我用过:

<% if current_user.posts.last.date.past? %> 

在我的html.erb文件中。然而,问题是如果用户从未发过帖子,那么它会导致nil:NilClass错误的未定义方法`date'。我不知道该怎么做才能解决这个问题?

5 个答案:

答案 0 :(得分:2)

最快的一个是使用{2.3}中的safe navigation运算符:

<% if current_user.posts.last&.date&.past? %>

如果您使用Ruby&lt; 2.3,您可以使用try

<% if current_user.posts.last.try(:date).try(:past?) %>

如果你想确保你只对那些有帖子的用户使用这个条件:

class User
  def post_date_past?
    return false unless posts.any?
    posts.last.date.past?
  end
end

并在视图中使用它:

if current_user.post_date_past?

答案 1 :(得分:2)

这就像用卡车反复跑过Law of Demeter一样。在该链的某处,你应该检查用户是否有任何帖子。

虽然您可以使用trysafe navigation运算符,但您的代码可能会从某些解耦中受益。

<% if current_user.posts.any? %>
 <% current_user.posts.last.tap do |post| %>
   <% if post.date.past? %>
     <% # ... %>
   <% end %>
 <% end %>
<% end %>

使用一些ActiveSupport冷却来实现此目的的另一种方法是将.try与块一起使用。

<% current_user.posts.try(:last) do |post| %>
  <% if post.date.past? %>
    <% # ... %>
  <% end %>
<% end %>

仅当.try(:last)未返回nil时才会调用该块。

同样.any?需要一个块,所以你可以这样做:

<% current_user.posts.any? do |posts| %>
  <% if posts.last.date.past? %>
    <% # ... %>
  <% end %>
<% end %>

答案 2 :(得分:0)

在检查日期之前检查最后一篇文章。

<% if current_user.posts.last.nil? || current_user.posts.last.date.past? %>

如果没有最后一个帖子,它会解析为true,否则会检查过去的日期。

答案 3 :(得分:0)

User模型类中:

def has_past_post?
  past_post = posts.last and past_post.date.past?
  !!past_post
end

然后在视图中:

<% if current_user.has_past_post? %> 

答案 4 :(得分:0)

既然每个人都在暗示,这是我的:

class User
  # Runs the supplied block with user's last post. If user
  # doesn't have a last post, then the block won't run.
  def with_last_post
    raise ArgumentError unless block_given?
    posts.last && yield posts.last
  end

  # Runs the supplied block only if the user has posts 
  def having_posts
    raise ArgumentError unless block_given?
    yield if posts.any?
  end

  # Runs the supplied block if the user has no posts
  def without_posts
    raise ArgumentError unless block_given?
    yield if posts.any?
  end
end

<% current_user.with_last_post do |last_post| %>
  <%= "last post in past!" if last_post.date.past? %>
<% end %>

<% current_user.having_posts do %>
  <%= "last post in past" if current_user.posts.last.date.past? %>
<% end %>

<% current_user.without_posts do %>
  You haven't posted anything!
<% end %>

这样做的正确方法是通过执行以下操作来收集控制器中视图所需的信息:

# FooController:
def show
  @last_post = current_user.posts.last
end

# views/foo/show.html.erb :
<%= render 'last_post', last_post: @last_post %>

# views/foo/_last_post.html.erb : 
<% if @last_post %>
  Last post: <%= @last_post.date %>
<% else %>
  You haven't posted anything ever.
<% end %>

或者使用助手:

# app/helpers/foo_helper.rb
module FooHelper
  def user_last_post_date
    last_post = current_user.posts.last
    if last_post
      last_post.date.past? "in the past" : "in the future(??!)"
    else
      "never"
    end
  end
end

# app/views/foo/show.html.erb
Last post date: <%= user_last_post_date %>