投稿ページを作ろう

HTMLのなかにrubyを入れていく
おさらい
<%□□□%>
rubyのコード(仕組み)だけ使いたいとき⇒定義づけなど出力しないやつ
<%=□□□%>
出力したい内容を書く
投稿ページなので.eschを使う
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ステータスとコメント一覧</title>
<link rel="stylesheet" href="index.css">
</head>
<body class="index-page">
<main class="index-main">
<section class="status-container">
<h1 class="status-title">自分のステータス</h1>
<div class="status-card">
<h2 class="status-name">ユーザー名</h2>
<p class="status-detail">レベル: 10</p>
<p class="status-detail">HP: 120/150</p>
<p class="status-detail">MP: 50/50</p>
<p class="status-detail">経験値: 1500/2000</p>
</div>
</section>
<% texts =
["今日は冒険に出て素晴らしいアイテムを手に入れました!",
"強敵に勝った!次はもっと強くなりたい!"]
%>
<section class="comments-container">
<h1 class="comments-title">コメント一覧</h1>
<% texts.each do |text|%>
<div class="comment-card">
<p class="comment-text">
<%= texts%>
</p>
</div>
</section>
</main>
</body>
</html>
/* 全体の設定 */
body.index-page {
font-family: 'Courier New', monospace;
background-color: #1e1e1e;
color: #f5f5f5;
margin: 0;
padding: 0;
}
/* メインコンテンツの設定 */
.index-main {
padding: 50px;
height: 1000px;
display: flex;
flex-direction: column;
align-items: center;
}
/* ステータスセクションの設定 */
.status-container {
width: 100%;
max-width: 600px;
margin-bottom: 30px;
text-align: center;
}
.status-title {
font-size: 2.5em;
color: #f5f5f5;
margin-bottom: 20px;
}
.status-card {
background: rgba(0, 0, 0, 0.8);
padding: 20px;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.6);
border: 2px solid white;
}
.status-name {
font-size: 2em;
margin-bottom: 10px;
}
.status-detail {
font-size: 1.2em;
margin: 5px 0;
}
/* コメントセクションの設定 */
.comments-container {
width: 100%;
max-width: 600px;
}
.comments-title {
font-size: 2.5em;
color: #f5f5f5;
margin-bottom: 20px;
text-align: center;
}
.comment-card {
background: rgba(0, 0, 0, 0.8);
padding: 15px;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.6);
margin-bottom: 15px;
border: 2px solid white;
}
.comment-author {
font-size: 1.1em;
font-weight: bold;
margin-bottom: 5px;
}
.comment-text {
font-size: 1em;
}
しかしエラー!!
「ActionView::SyntaxErrorInTemplate in PostsController」
と出てきた
⇓
Rails アプリケーションでビューテンプレートをレンダリングする際に、テンプレート内の構文エラーが発生したことを示すエラーです。具体的には、index アクションのビュー(app/views/posts/index.html.erb など)内に何らかの誤りがある場合にこのエラーが発生します。
2つの修正点
ERB タグの使用ミス:
1.<%= texts %> と書かれている部分は、変数 texts の内容を表示しようとしているようですが、
texts は配列であるため、各要素を表示するには text を使ってループ内で表示する必要があります。
<%= texts %> はループの外にあるため、正しく表示できません。
ERB タグの閉じ忘れ:
texts.each do |text| のループが閉じていないため、
<% texts.each do |text|%> の後に end が必要です。
修正後のコード
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ステータスとコメント一覧</title>
<link rel="stylesheet" href="index.css">
</head>
<body class="index-page">
<main class="index-main">
<section class="status-container">
<h1 class="status-title">自分のステータス</h1>
<div class="status-card">
<h2 class="status-name">ユーザー名</h2>
<p class="status-detail">レベル: 10</p>
<p class="status-detail">HP: 120/150</p>
<p class="status-detail">MP: 50/50</p>
<p class="status-detail">経験値: 1500/2000</p>
</div>
</section>
<% texts =
["今日は冒険に出て素晴らしいアイテムを手に入れました!",
"強敵に勝った!次はもっと強くなりたい!"]
%>
<section class="comments-container">
<h1 class="comments-title">コメント一覧</h1>
<% texts.each do |text|%>
<div class="comment-card">
<p class="comment-text">
<%= text%>
</p>
</div>
<%end%>
</section>
</main>
</body>
</html>
無事にeach対応した!

これまではビュー内で変数を定義していましたが、
Railsでは通常、アクション内で変数を定義するのが一般的です。
これからはコントローラのアクション内で変数を定義する方法を見ていきましょう。
つまり
<% texts =
["今日は冒険に出て素晴らしいアイテムを手に入れました!",
"強敵に勝った!次はもっと強くなりたい!"]
%>
これをアクション内に移動ってことです

通常、アクションで定義した変数はそのままではビューで使えない。
しかし、変数名の最初に「@」を付けると、その変数は特別なものになり、
ビューでも使えるようになるから・・・
ビューで使う変数には必ず「@」を付けることを忘れないようにする
class PostsController < ApplicationController
def index
@texts =[
"今日は冒険に出て素晴らしいアイテムを手に入れました!",
"強敵に勝った!次はもっと強くなりたい!"
]
end
end
移動が完了した!
HTMLのなかの変数を変更する
<% @texts.each do |text|%>
<div class="comment-card">
<p class="comment-text">
<%= text%>
</p>
</div>
<%end%>
最初は<% @texts.each do |text|%>のなかのtextを@textに変更したが
関係性が違うし、コントロールで定義した変数は「@texts」なので注意!

投稿の一覧ページは作成したので、
投稿の詳細を確認する画面と。新規投稿ページを作りたい

投稿の一覧を表示するには、「投稿のidを習得して並べる」
⇒すべての投稿に付けられている、共通したルールを使う的な感じ
ではどうやって??
「特定の投稿を取得するには、find_by メソッドを使用します。
find_by メソッドは、指定した条件に合うデータをデータベースから1つ取得するための方法です。
使い方は、「モデル名.find_by(カラム名: 値)」という形式です。
これによって、指定したカラムに特定の値を持つデータをデータベースから探し出します。
例えば、id が 1 の投稿を取得したい場合は、「Post.find_by(id: 1)」と書きます。
これにより、id が 1 の投稿が取得できます。」

各投稿の詳細ページを表示させるには
各投稿の詳細ページのurlに投稿のidを入れて特定させて表示させる
新しいページを作ることになるので、
ルーティング
アクション
ビュー
を作成していく
おさらい
①ルーティング
②コントローラ
③ビュー
①ルーティング
②コントローラ
③ビュー

ルーティング
各投稿のidに合わせてURLをルーティングに入れようとすると
get "posts/1" => "posts#show"
get "posts/2" => "posts#show"
get "posts/3" => "posts#show"
get "posts/4" => "posts#show"・・・・・・
無理じゃね?
ルーティングのURL部分に「:」を使って「posts/:id」と指定することで、
URLの一部が変わっても対応できます。
例えば、posts/:id と書くことで、「/posts/1」や「/posts/2」など、
idが異なるURLに対応できるようになります。
これにより、/posts/1 や /posts/2 などのURLがshowアクションに対応します。
idの部分は変数のように動的に変わるため、どんなidのURLでも処理が可能です。
ルートの例
URL /posts/1 にアクセスすると、id: 1の投稿を取得してshowアクションが実行されます。
同様に、/posts/2 にアクセスすると、id: 2の投稿が取得されます。
ポイント:
:idの部分がURL内の動的な要素を示していて、
ルーティングでidを使って適切なデータを取得できるようになっています。
~/posts/1
~/posts/2
どちらのURLでも
get "posts/:id" => "posts#show"
"posts/:id"これに当てはまって"post#show"へ行く
「posts/:id」というルーティングは「posts/index」より下に書く必要があります。
ルーティングは、定義された順番に従って上から順にマッチするURLを探します。
つまり、上に書かれているルートが優先されます。
具体的な理由
「posts/:id」は動的な部分(id)を持つため、
/posts/indexのようなURLも「id」として解釈されてしまう可能性があります。
例えば、もし「posts/:id」を「posts/index」より上に書いた場合、
localhost:3000/posts/index にアクセスした際、indexがidと解釈されてしまい、
showアクションが呼ばれてしまいます。
これでアクセスできるようになった!

ではどうやって
各投稿の詳細を上記のページに反映させる?
idの習得方法は?
コントローラのアクション内で、
ルーティングで設定したURLの「:id」の値を取得することができます。
ルーティングで「posts/:id」のように指定すると、
URLの「:id」部分が動的な変数として扱われます。
この変数の値は、コントローラ内で取得できます。
params ハッシュを使用する
params という変数は、リクエストに関する情報を含むハッシュです。
URLの「:id」の値もこのハッシュ内に格納されています。
具体的な使い方
コントローラのアクション内で、
URLの「:id」の値を取得するには、params[:id] と書きます。
class PostsController < ApplicationController
def show
@id = params[:id]
end
end
{id:1}というハッシュが変数paramsに入っているので
それが代入された@idにはidの値が入っている

詳細ページに
<%= "idが「#{@id}」の投稿詳細画面です" %>
※ Rubyでは#{ }を用いて変数の値を文字列中に表示することができます。
つまりshow内で定義した変数@idを表示させた
idに反映された表記になった!

つぎは投稿内容を反映させたい
ステップ 1:
コントローラで show アクションを定義する
PostsController の show アクションを設定し、
params[:id] を使ってデータベースから特定の投稿を取得します。
class PostsController < ApplicationController
def show
@post = Post.find_by(id: params[:id])
end
end
上記のコードでは、params[:id] を使ってURLの「:id」部分から投稿の id を取得し、
その id に対応する投稿をデータベースから取得しています。
取得した投稿は、@post というインスタンス変数に代入されます。
idカラムがparams[:id]である投稿を取得しているということ
ステップ 2: ビュー (show.html.erb) で投稿データを表示する
show.html.erb では、コントローラで設定した @post を使って、投稿のデータを表示します。
投稿内容を表示させたいので
<%=@post.comment %>
を記入
成功!

あとは、投稿一覧から、対象の投稿の詳細へ飛べるようにリンクを作成する!
⇒クリックしたリンク(投稿)が対象のidがURLに入力されていれば、対象の詳細へ飛べるはず
つまり!URLの末尾に#{post.id}が入るようにする!
<%= post.content %>
これは投稿内容だけ出力されている状態
そこにリンクを加える
<%=link_to(post.content, "/posts/#{post.id}")%>
おさらい
<%=link_to(○○○○ "/◆◆/◆◆")%>
○○○○は文字
/◆◆/◆◆はリンク
これにあてはめて考えるなら
すでに <%=comment.comment%>で正しく出力されているのでこれにリンクを加える
これで・・・どうだ?
だめでした
<%=link_to(comment.comment,"/posts/#{post.id}")%>
これが悪いって出てるけど・・・分からん
エラーメッセージによると、undefined local variable or method 'post'というエラーが発生しています。このエラーは、postという変数やメソッドが見つからないために発生しています。具体的には、index.html.erbの<%= link_to(comment.comment, "/posts/#{post.id}") %>の部分で問題が起こっています。
変数の誤り:
初めに<%= link_to(comment.comment, "/posts/#{post.id}") %>と記述していたため、commentという変数を使いながらpost.idを参照していました。
postという変数は定義されていないため、エラーが発生しました。
<% @posts.each do |post|%>
<div class="comment-card">
<p class="comment-text">
<%=link_to(post.comment,"/posts/#{post.id}")%>
</p>
</div>
<%end%>
変数を正しく指定した。
each内独自の変数の指定の仕方をしていたから
コントローラーで設定した変数を拾うことができなかった
無事にリンクが成功して飛べるようになった
あとは文字の設定を変えればOK

下線を消す
text-decoration: none;
文字の色を親要素に合わせる
color: inherit;
フォントスタイルの維持
font-family: inherit; /* 親要素のフォントファミリーを継承 */
font-size: inherit; /* 親要素のフォントサイズを継承 */
font-weight: inherit; /* 親要素のフォントウェイトを継承 */

これで
修正完了した
しかし
なんで.comment-text a {}はaなんだ?pではないのか?
.comment-index a のように指定できる理由は、HTML内の要素とCSSの関係にあります。
HTMLの構造
<p class="comment-index">
<%= link_to("エリートを見る", "/posts/index") %>
</p>
ここで、<p> タグ内に <a> タグ(リンク)が含まれています。
つまり、.comment-index は <p> タグのクラス名であり、<a> タグはその中に含まれています。
CSSのセレクタ
CSSでは、階層的に要素を選択することができます。
.comment-index a というセレクタは次のような意味を持ちます:
.comment-index: クラス名が comment-index の要素(ここでは <p> タグ)。
a: その中にある <a> タグ(リンク)。
どうして機能するのか
階層選択:
.comment-index a は
「クラス名が comment-index の要素の中にあるすべての <a> タグ」を意味します。
つまり、.comment-index クラスが適用された
<p> タグ内の <a> タグにスタイルを適用することができます。
HTMLの構造
<a> タグは <p> タグの子要素であり、
CSSセレクタ .comment-index a はこの関係を利用してスタイルを適用しています。
例
<!-- HTML -->
<p class="comment-index">
<a href="/posts/index">エリートを見る</a>
</p>
このように、<p class="comment-index"> 内の <a> タグに対して
特定のスタイルを適用するために .comment-index a というセレクタを使用します。
なるほど
link_toにaが入っているということ
link_toが<a href="">と同じ役割なら、無事に投稿の詳細ページにもリンクを作成できた