Closed13

投稿ページを作ろう

かいかい

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アクションが呼ばれてしまいます。


http://localhost:3000/posts/1

これでアクセスできるようになった!

かいかい

ではどうやって
各投稿の詳細を上記のページに反映させる?

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 href="">と同じ役割なら、
link_toにaが入っているということ

無事に投稿の詳細ページにもリンクを作成できた

このスクラップは2024/09/12にクローズされました