はじめに
先日、各ページに共通のヘッダーを持たせる処理を行ったところ、詳細ページで500エラーが...。
考えればすぐに分かることだったのですが解決に時間を要したためメモ。
共通ヘッダーを作る
今回はArticlesの公開日の新しい3件のタイトルと公開日をヘッダーに表示させます。
用意したmigrationファイルはこちら。
class CreateArticles < ActiveRecord::Migration
def change
create_table :articles do |t|
t.string :title
t.text :body
t.datetime :published_at
t.timestamps
end
end
end
modelには公開日の新しい3件を取得する処理を書く。
class Article < ApplicationRecord
def self.header
Article.where('published_at <= ?', Time.zone.now).limit(3).order(published_at: :desc)
end
end
ヘッダー用のviewファイルはこんな感じ。
@article
に3件のデータを入れて、each do
で回していく。
<div class ="header">
#もろもろ省略してArticles表示
<ul class="hoge">
<% @article = Article.header %>
<% @article.each do |article| %>
<li class="hoge-list"><a href="/article/<%= article.id%>"><span class="hoge-date"><%= article.published_at.strftime('%Y.%m.%d')%></span><%= article.title %></a></li>
<% end %>
</ul>
</div>
各ページのviewファイルに、<%= render partial: "common/header" %>
を追記して、ヘッダーを表示、ヘッダーの中には新しい3件のArtitlesを表示できました。
しかし、各Articleのページを表示しようとすると500errorが・・・!
エラー内容は、undefined method `title' for #<Article::ActiveRecord_Relation:xxxxxxxx>
でした。
viewとコントローラを確認してみる
まずはviewを確認。
#先程追記したヘッダー
<%= render partial: "common/header" %>
<div class="sample">
<h1><%= @article.title %></h1>
</div>
・・・なるほど、@articleにtitle
なんか無いよと。
@article
を設定したコントローラ、showアクションを見てみます。
class NewsInfoController < ApplicationController
#indexアクションとかは省略
def show
@article = Article.find(params[:id])
end
end
んー、@article
に中身が入ってない?と考え、pp @article
でターミナルに表示させてみると、データは取れている。
@article.title
も、データが取れる。何故・・・?
もう一度エラーを見直してみる
そうだ、エラー内容はundefined method `title' for #<Article::ActiveRecord_Relation:xxxxxxxx>
。
showアクションでは、@article
はfindメソッドで取っているのでActiveRecord_Relationでは無い。
一連でActiveRecord_Relationを使った--where使ったのは・・・
そうか、ヘッダーの処理だ!!
ヘッダーのviewファイルを見直す
#もろもろ省略
<% @article = Article.header %>
<% @article.each do |article| %>
<li class="hoge-list"><a href="/article/<%= article.id%>"><span class="hoge-date"><%= article.published_at.strftime('%Y.%m.%d')%></span><%= article.title %></a></li>
<% end %>
ここにも@article
と名前を付けていました。この@article
は、whereを使っているのでActiveRecord_Relation
ですね。
show.html.erb
でrenderしてきた、_header.html.erb
内の@article
が先に読み込まれたためエラーが出たのです。
なので、_header.html.erb
内の@article
を@articles
や@article_header
に名前を変えたところ、解決しました。
#もろもろ省略
<% @articles = Article.header %>
<% @articles.each do |article| %>
<li class="hoge-list"><a href="/article/<%= article.id%>"><span class="hoge-date"><%= article.published_at.strftime('%Y.%m.%d')%></span><%= article.title %></a></li>
<% end %>
初めから複数形にしておけばよかったのですが…実際は@news
だったので分かりづらかった・・・。
まとめ
・部分テンプレート内(呼び出される側)で変数を用いる場合は、呼び出すviewファイル内と同じ変数名を付けないよう注意する。
・whereには複数、findには単数を付けるなど、取得するレコードの数に応じて変数名を工夫する。
初心者ですので、間違っている点等あればご指摘いただけますと幸いです。