morimotoyuuki111 / blog

0 stars 0 forks source link

更新機能を作ろうについて #14

Open morimotoyuuki111 opened 2 years ago

morimotoyuuki111 commented 2 years ago

前提 教材4-3を学習中なのですが更新がされません 更新した内容は更新ボタンを押してたら消えます。

実現したいことは 編集した内容を保存されるように反映したい

発生している問題 編集した内容が反映されない image

該当コード repository/article_repository.go

// ArticleUpdate ...
func ArticleUpdate(article *model.Article) (sql.Result, error) {
    // 現在日時を取得します
    now := time.Now()

    // 構造体に現在日時を設定します。
    article.Updated = now

    // クエリ文字列を生成します。
    query := `UPDATE articles
    SET title = :title,
            body = :body,
            updated = :updated
    WHERE id = :id;`

    // トランザクションを開始します。
    tx := db.MustBegin()

    // クエリ文字列と引数で渡ってきた構造体を指定して、SQL を実行します。
    // クエリ文字列内の :title, :body, :id には、
    // 第 2 引数の Article 構造体の Title, Body, ID が bind されます。
    // 構造体に db タグで指定した値が紐付けされます。
    res, err := tx.NamedExec(query, article)

    if err != nil {
        // エラーが発生した場合はロールバックします。
        tx.Rollback()

        // エラーを返却します。
        return nil, err
    }

    // エラーがない場合はコミットします。
    tx.Commit()

    // SQL の実行結果を返却します。
    return res, nil
}

handler/article_handler.go

// ArticleEdit ...
func ArticleEdit(c echo.Context) error {
    // パスパラメータから記事 ID を取得します。
    // 文字列型で取得されるので、strconv パッケージを利用して数値型にキャストしています。
    id, _ := strconv.Atoi(c.Param("articleID"))

    // 編集フォームの初期値として表示するために記事データを取得します。
    article, err := repository.ArticleGetByID(id)

    if err != nil {
        // エラー内容をサーバーのログに出力します。
        c.Logger().Error(err.Error())

        // ステータスコード 500 でレスポンスを返却します。
        return c.NoContent(http.StatusInternalServerError)
    }

    // テンプレートに渡すデータを map に格納します。
    data := map[string]interface{}{
        "Article": article,
    }

    // テンプレートファイルとデータを指定して HTML を生成し、クライアントに返却します。
    return render(c, "article/edit.html", data)
}

handler/article_handler.go

// ArticleUpdateOutput ...
type ArticleUpdateOutput struct {
    Article          *model.Article
    Message          string
    ValidationErrors []string
}
// ArticleUpdate ...

func ArticleUpdate(c echo.Context) error {
    // リクエスト送信元のパスを取得します。
    ref := c.Request().Referer()

    // リクエスト送信元のパスから記事 ID を抽出します。
    refID := strings.Split(ref, "/")[4]

    // リクエスト URL のパスパラメータから記事 ID を抽出します。
    reqID := c.Param("articleID")

    // 編集画面で表示している記事と更新しようとしている記事が異なる場合は、
    // 更新処理をせずに 400 エラーを返却します。
    if reqID != refID {
        return c.JSON(http.StatusBadRequest, "")
    }

    // フォームで送信される記事データを格納する構造体を宣言します。
    var article model.Article

    // レスポンスするデータの構造体を宣言します。
    var out ArticleUpdateOutput

    // フォームで送信されたデータを変数に格納します。
    if err := c.Bind(&article); err != nil {
        // リクエストのパラメータの解釈に失敗した場合は 400 エラーを返却します。
        return c.JSON(http.StatusBadRequest, out)
    }

    // 入力値のチェック(バリデーションチェック)を行います。
    if err := c.Validate(&article); err != nil {
        // エラー内容をレスポンスのフィールドに格納します。
        out.ValidationErrors = article.ValidationErrors(err)

        // 解釈できたパラメータが不正な値の場合は 422 エラーを返却します。
        return c.JSON(http.StatusUnprocessableEntity, out)
    }

    // 文字列型の ID を数値型にキャストします。
    articleID, _ := strconv.Atoi(reqID)

    // フォームデータを格納した構造体に ID をセットします。
    article.ID = articleID

    // 記事を更新する処理を呼び出します。
    _, err := repository.ArticleUpdate(&article)

    if err != nil {
        // レスポンスの構造体にエラー内容をセットします。
        out.Message = err.Error()

        // リクエスト自体は正しいにも関わらずサーバー側で処理が失敗した場合は 500 エラーを返却します。
        return c.JSON(http.StatusInternalServerError, out)
    }

    // レスポンスの構造体に記事データをセットします。
    out.Article = &article

    // 処理成功時はステータスコード 200 でレスポンスを返却します。
    return c.JSON(http.StatusOK, out)
}

main.go
ルーティングを追加
```go
 e.PATCH("/api/articles/:articleID", handler.ArticleUpdate)  // 更新

src/template/article/edit.html

  {% extends "../layout.html" %}

  {% block css %}
  <link rel="stylesheet" href="/css/article/edit.css" />
  <link rel="stylesheet" href="/css/vendor/prism.css" />
  <link rel="stylesheet" href="/css/article/_form.css" />
  <link rel="stylesheet" href="/css/article/_article.css" />
  {% endblock %}

  {% block js %}
  <script src="/js/article/edit.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/remarkable/2.0.0/remarkable.min.js"></script>
  <script src="/js/vendor/prism.js"></script>
  <script src="/js/module/parser.js"></script>
  <script src="/js/module/form.js"></script>
  {% endblock %}

  {% block title %}
  編集 | {{ block.Super }}
  {{ Article.Title }} | {{ block.Super }}
  {% endblock %}

  {% block content %}
  <p>{{ Message }}</p>
  <p>{{ Now }}</p>
  <p>{{ ID }}</p>
  <div class="l-col l-row l-v-padd">
    <div class="article-edit l-row">
      <div class="article-edit__form l-row">
        {% include "./_form.html" %}
      </div>
    </div>
  </div>
  {% endblock %}

試したこと 

{"time":"2022-08-07T23:02:07.977789+09:00","id":"","remote_ip":"::1","host":"localhost:8080","method":"GET","uri":"/articles/37/edit?title=%E8%A8%98%E4%BA%8B+aaa&body=%E8%A8%98%E4%BA%8B+aaa","user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36","status":200,"error":"","latency":6880997,"latency_human":"6.880997ms","bytes_in":0,"bytes_out":3039}

キャッシュを削除して再度試したが改善されず。 "status":200,"error"を検索したが解決につながるようなものはわからなかった。 latency":6880997は検索したら遅延時間と分かった。 latency_human"6.880997ms"で検索したら一致する情報は見つかりませんでした。となった。 latency_humanで検索したらミドルウェアの実装?と出てきた。 "bytes_in":0を検索したら分からなかったので bytes_in 0 golangと検索したら 一番上に Go Echo でミドルウェアを入れようとした時のつまずき
の記事が出てきたが解決につながるか現状わからない。 "bytes_out":3039で検索したら解決につながるようなものは見つからなかった。

totsumaru commented 2 years ago

自分で調べてここまで試すのは素晴らしいです! 原因はいくつか考えられるので1つずつ潰していきましょう。

考えられる原因

試すべきこと

更新ボタンを押したときに、goを起動しているコンソールで

"method":"PATCH",

のようなPATCHという文字列が表示されていればOKです。

※ちなみに、ここで記述したものです。

    // HTML ではなく JSON を返却する処理は "/api" で開始するようにします。
    // 記事に関する処理なので "/articles" を続けます。
    e.GET("/api/articles", handler.ArticleList)                 // 一覧
    e.POST("/api/articles", handler.ArticleCreate)              // 作成
    e.DELETE("/api/articles/:articleID", handler.ArticleDelete) // 削除
    e.PATCH("/api/articles/:articleID", handler.ArticleUpdate)  // 更新
morimotoyuuki111 commented 2 years ago

更新ボタンを押してコンソールを確認しました。

"method":"PATCH",はなく"method"は見つかりました。
totsumaru commented 2 years ago

PATCHが出ていないということは、HTML,JSからGoに正しくリクエストが送れていないということです。 どのような表示がされたか分かりませんが、おそらくそうかなと思っています。

現状、教材をコピペしただけだと思いますが、ボタンをクリックしたらどうなるのか?をコードを追ってみて、 原因をもう少し考えてみましょう。

もしかすると、教材に不備があるかもしれないです。 (プログラムの教材には、よく不備があるので。。。)

morimotoyuuki111 commented 2 years ago

すいません。 コードを確認のお願いできますでしょうか?

https://github.com/morimotoyuuki111/blog/tree/main/dev/go-tech-blog

morimotoyuuki111 commented 2 years ago

すいません。更新できました。