2016-10-03 8 views
0

私はユーザーが1日1回投稿を作成できるようにするプロジェクトに取り組んでいます。ユーザーがその日に既に投稿をしている場合は、表示しない投稿を送信するためのUI要素が必要です。これを行うには、私は使用しました:新しいアカウントでNoMethodErrorが発生するステートメント

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

私のhtml.erbファイル。しかし、この問題は、ユーザが投稿をしたことがない場合、nilの未定義のメソッドdate(Nilクラスエラー)が発生することです。私はこれを解決するために何をすべきか分からないのですか?

+0

ください。あなたの問題を解決したものを受け入れたものとして確認してください。これはSOの推奨動作です。 –

答えて

2

最速1は、Ruby 2.3.0で提示safe navigation演算子、使用することです:あなたはルビー< 2.3を使っているのであれば、あなたはtryに行くことができます

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

を:

<% 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? 
+0

これはエラーをスローしませんが、最後の投稿がない場合はnilを返します。 –

+1

最後の2つだけに '&.'や' try'を使う必要があるとします: '<%if current_user.posts.last&.data&.past? %> ' –

+0

@KimmoLehto correct、thx! :) –

0

チェックを日付をチェックする前に。

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

それが真の解決の最後のポストがない場合は、それ以外の場合は、過去の日付をチェックします。

+1

これは2つのクエリを実行する可能性があります。 '<%last_post = current_user.posts.last;もしlast_post && last_post.date.past? %> ' –

2

これはトラックでLaw of Demeterを繰り返し実行するようなものです。そのチェーンのどこかに、ユーザーが投稿を持っているかどうかを実際に確認する必要があります。

tryまたはsafe 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を返さない場合にのみ呼び出されます。

​​
+0

' .last'は本当に得意ですか? –

+0

は、 'current_user.posts.order(" created_at DESC ")。limit(1).each do | last_post |' –

+0

のようなものかもしれません。実際にはそうです。私はコンソールでそれを試しなければならなかったが、それは最後のレコードを生成する。 @KimmoLehto – max

0

をごUserモデルクラス内部:ビューで次に

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

:あなたがそうのようにそれを行うことができますので、また

.any?は、ブロックを取る

<% if current_user.has_past_post? %> 
+0

ここでメモ帳を使用すると、 '@post_post'が古くなる可能性があるため、レコードを更新するなどの場合に予期しない結果になる可能性があります。私は代わりにクエリをキャッシュするアクティブなレコードに頼っています。 – max

+0

@max:そうです。コードを更新しました。 – Surya

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 %> 
+1

Crafty - しかし、それは観客の関心を払い、それをモデルレイヤーに詰め込むような感じです。ブロックを使用するのはクールな方法ですが、モデルに属しているかどうかはわかりません。 – max

+1

同様に、すべての 'user.post_date_past'と' user.has_pas_post? 'の答えです。 –

関連する問題