sharoa
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # 【第18週】パRails輪読会🚂 \(2023\-12\-18\~ 2023\-12\-22\) ###### tags: `パRails🚂` - [開催概要](https://hackmd.io/4A_8ahJtQNi5hz713N5Y7w?view) - [パRails輪読会 ノートまとめ](https://hackmd.io/jsgA8Pf_RVioOgSL_VOR4g) - サンプルコード・正誤表:[サポートページ:パーフェクトRuby on Rails【増補改訂版】:|技術評論社](https://gihyo.jp/book/2020/978-4-297-11462-6/support) - **サンプルコードをダウンロードしただけでは、すぐに`rails s`できない可能性が高い**です。 以下のページに環境構築の手順をまとめたので、ドライバーをやってくださるという方は、こちらに沿って環境構築をお願いします🙏 ⏩ [環境構築の手順 2022年版](https://hackmd.io/y7qb2BRMT2Wd4tAtKYObcQ) ⏩ [環境構築の手順 2023年版](https://hackmd.io/3_lnn8_QRD6wEjwFbWcBzQ) 💁‍♀️ [更新の手順 2章編](https://hackmd.io/pZAmF2EjSmyQ38lUtJ_CqA) ## 目次 [TOC] ------ ## 2023\-12\-18(月) ### ファシリ @motohiro-mm ### ドライバー @moegi ### 読んだところ 6-5-2 319p columnから 6-6-1 「イベント編集機能を作る」まで。 PR:https://github.com/PerfectRubyonRails-Rindoku/Perfect_Ruby_on_Rails_Ch6/pull/11 ### 次回 6-6-2 「イベント削除機能を作る」から。🚂 ### 学んだこと・感想 - @sharoa - コラムの名前が重要のところで、railsでは規約によってデフォルトの名前が自動的に決まるものもあるが、それが実態を表していないと感じた場合は積極的に変更していくことが大事、とのことだそうです。自分にその判断ができるのか正直微妙なところですが、判断ができるようになっていきたいな〜と思いました。 - イベント詳細ページに編集ボタンを追加するにあたって、`Event#created_by?` メソッドを使用して、イベントを作成したユーザーがイベントを詳細ページを閲覧した時のみリンクを表示できるようになる。 - Bootstrap では、コンテナを12個のグリッドに分割してレイアウトを制御しているそうで、hamlファイルの中の`.col-8`と`.col-4`を数値を変えることで表示が変更したのが確認できてよかった。 - @hiromisugie - Railsがデフォルトで決めた名前であっても、実態に合わせて変えていくことが必要になることもある。(`名前重要`という非常に重要そうなコラムを皆さんと確認できて良かった) - 以下のメソッドの中身は、1行目ではログインしてなかったら早期returnで即false、ログインしてたら2行目に移り、オーナーID(イベント作成者)とユーザーID(今閲覧している人)が一致しなかったらやはりfalse。一致したらtrueが返る(=viewの方で「イベント編集」ボタンを表示できる)、ということ。 早期returnも苦手、unlessも苦手で、早く慣れたい…!けど、パズルのようで楽しい。 ```ruby def created_by?(user) return false unless user owner_id == user.id end ``` - @moegi29 - コラムの名前重要のところを読んでlsコマンドのプラクティスのときに変数名のつけかたでも苦戦したのを思い出しました。 - current_userの関連を使わずowner_idで絞り込む場合、絞り込みがなくてもエラーにはならない。でも、忘れてしまうと誰でもイベント編集や更新が可能になってしまうというところは注意。 - SJRで実装。SJR:サーバサイドでJavaScriptのコードを生成しそれをレスポンスとして返すJavaScriptの実行方法 - @shodan - p322の「なるべく関連を利用してレコードを取得しましょう」というのは伊藤さんがFBCでも記事にしているやつかな〜と思いました。 - [【Rails】モデルの関連を活用してデータを取得しよう \| FJORD BOOT CAMP(フィヨルドブートキャンプ)](https://bootcamp.fjord.jp/articles/76) - 関連を使わないパターンで`Event.find_by!(...)`というビックリマークバージョンを使っているのは、レコードが見つからなかったときに例外を`raise`したいからっぽい? - `find_by`だとレコードが見つからなかったときの返り値は`nil`。 - @ayu-0505 - 「bootstrapが12分割を基本として考えられる」ことは知らなかったので勉強になりました!(他の参考書とかでも謎の数字と思っていた気がします) - コラムの名前重要について、確かに課題をしていく中で名前で分ける必要を感じて後から修正することが多いので(`id`→`mentioning_id`みたいに)、なるほどと思いました。 - @motohiro-mm - `created_events`が今後他の関連づけるときに名前が衝突するためにあえてその名前にした事がわかって納得しました。名前大事 - 自分のOOPプラクティスの提出物の名前付けが不安になってきました - bootstrapが`.col-`で12分割していることを初めて知りました!勉強になりました〜 - 「また、関連付けを使わずowner_idで絞り込む場合、絞り込みがなくてもエラーにはならないので時折忘れてしまいます」の部分が理解が曖昧… - 自分で出ていたエラーはsafariでもダメだったので、なんでエラー出てるのかこのあと調べます〜 - `localhost`と`127.0.0.1`の違いでした ------ ## 2023\-12\-19(火) ### ファシリ @sharoa ### ドライバー @sadanora ### 読んだところ 6-6-2 「イベント削除機能を作る」から 6-7-1 「イベント参加機能の作成」の途中まで。 PR: https://github.com/PerfectRubyonRails-Rindoku/Perfect_Ruby_on_Rails_Ch6/pull/12 ### 次回 6-7-1 329p 「イベント参加処理の作成」から。🚂 ### 学んだこと・感想 - @sharoa - イベント削除機能を作るにあたって、論理削除ではなく単純な物理削除を実装した。論理削除とは。。。削除フラグを追加して実際にはレコードを削除しない手法のこと。 - destroyメソッドではなくdestroy!メソッドを利用することで、想定外の事態が起きた時にすぐ気づけるようにしている。 - イベント参加機能の作成で、「コメントを正しく入力すると参加が完了する」とあったが、空文字やnilを許可としているのに少し、え?と思ったけど、ただの空欄でも参加はできるよってことでそういうのは普通にあるか、と気づきました! - @hiromisugie - 論理削除は、削除フラグを追加して削除したように見せているが実はレコードが残っている状態。物理削除は、レコードから削除する。 - ブログサービスとかで、投稿した記事をゴミ箱に入れると記事一覧からは消えるけどゴミ箱には残っている(一定期間でそこからも消える)みたいな機能があるけど、それも似たような仕組みなのかな…? - user_idカラムでnullを許可すると、イベントを作成したユーザーが退会してuser_idが無くなってもエラーにならずイベントだけは残る、みたいなことかなぁと思った。 - これまたブログとかSNSで、作成者がいなくなっても投稿だけ残ってるみたいな状況を見たことがある) - ユーザーが同じイベントに重複して参加できないようにするためにユニークインデックスを追加する。1つ1つの機能でエラーやおかしな状況が生まれないような細かい設定が必要なんだなと思った…! - ハッシュリテラルの種類、うろ覚えになっているのでチェリー本で復習しないと、、、 - @sadanora - `%button.{ "data-toggle": "modal", "data-target": "#createTicket" }`じゃなくて`%button.{ "data-toggle" => "modal", "data-target" => "#createTicket" }` - ~~`:`を使ってしまうとうまく動かないみたいなので、`=>`を使う~~ - 試したらどっちでも動いたのでそんなこともないみたい。書き方の好みの問題ってことでいいのかな? - @motohiro-mm - 論理削除:Webアプリ上は削除するが実際はレコードを削除しない方法。↔︎物理削除 - シンボルには`""`は使えるけど、シンボル自体に`""`も含まれてしまう - シンボルには`-`はそのままでは使えず(エラー)、`"-"`で囲ったりすれば一応使える - routes.rbの`as: :別名`で別名をつけられる - [Rails のルーティング \- Railsガイド](https://railsguides.jp/routing.html#%E5%90%8D%E5%89%8D%E4%BB%98%E3%81%8D%E3%83%AB%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0) - `×`:バツの特殊文字 - [HTMLの記号・特殊文字の文字コード表(文字実体参照、数値文字参照) \| GRAYCODE HTML&CSS](https://gray-code.com/html_css/list-of-symbols-and-special-characters/) ------ ## 2023\-12\-20(水) ### ファシリ @sharoa ### ドライバー @ayu-0505 ### 読んだところ 6-7-1 329p 「イベント参加処理の作成」 PR: https://github.com/PerfectRubyonRails-Rindoku/Perfect_Ruby_on_Rails_Ch6/pull/13 ### 次回 6-7-1 331p 「参加者一覧表示機能を作る」から。🚂 ### 学んだこと・感想 - @sharoa - `:`と`=>`について、昨日の話から、sadanoraさんが確認してくれて、:でも動くということがわかった。(本で2パターンで書かれているのが気になる。) - イベント参加処理を作って、その流れが見れたのがすごく良かった。 - 参加者が重複しないように設定していたところも確認できたのも良かった。sugieさんナイスな質問でした。 - 参加コメントでエラーがでた際に、その画面をリロード(遷移など)をしない限り、そのまま残っていた。消したい場合はそうなるようなコードを追加しないとダメそう。 - @moegi29 - [パーフェクトRuby on Rails【増補改訂版】サポートページの正誤表](https://gihyo.jp/book/2020/978-4-297-11462-6/support#supportApology)だとどちらも `=>` だったのでより謎が深まった。 - 参加コメント入力エラーのエラーメッセージのモーダルを閉じた後もそのまま残っている状況、ユーザーが重複して登録できないという挙動をHTMLとRailsからの視点でそれぞれみれて動きのイメージがつきました - 昨日帰宅が遅くそこから巨人を観てしまい寝不足なので終始ぼーっとしていました 睡眠大事だと思いました - @sadanora - Ticketモデル -  同じユーザーの参加表明ができないようにEventとUserにユニークインデックスを貼っている。 -  この状態で同じユーザーの参加表明をしようとすると[ActiveRecord::RecordNotUnique](https://api.rubyonrails.org/classes/ActiveRecord/RecordNotUnique.html)が発生する -  httpステータス的は500になっていた -  sugieさんの質問のおかげで細かい動きが確認できてよかったです。 - @ayu-0505 - ハッシュの記法である`=>` と`:`について、RailsとRubyでまた作法や挙動が違うかもしれないという可能性を知ることができた。 - モデルにユニーク制約をつけたことにより、画面上は特に変化がないように見えて、コンソール上ではロールバックしてエラーが出ていたので、ログを見ながら開発する必要性を感じた。 - 昨日休んだら、モーダルが出来上がっていてびっくりしました。モーダルの作り方は全然分からないので、また参考にして調べたいと思います。 - 久しぶりのドライバーで少し緊張しましたが、滞りなくCH6をクローンできてよかったです。 - @hiromisugie - ハッシュロケット(`=>`)というと、Rubyのハッシュと結びつけて考えてしまうけど、Railsのお作法で`=>`を使う場合にちょっとルールが違う場合があるかもしれない??なんというか難しいなと思いました。 - 前回のマイグレーションファイルでticketsにユニークインデックスをつけていたので同じユーザーが2度参加できない、というのを試せて良かった。ただ、コントローラやビューを何も設定してないので、今のままだと実用には耐えないこともわかった。 - モーダルを閉じてもエラーメッセージが残る問題。BootstrapでモーダルにしてJSでエラーを出しているが故に起こっていると思うので、変に洒落てモーダルとかJSとか使わなくてもいいなと個人的には思いました笑。(そうすると完了画面とか用意しないといけないから、どっちが手間なのかはちょっとわかりませんが) - 未ログイン状態でどうなるのかを次回確認したい - @motohiro-mm - 前回追加した`add_index :tickets, %i[event_id user_id],unique: true`がきちんと動作して、重複して参加登録されずにActiveRecord::RecordNotUnique(間違ってたらすいません)が出ているところを見れて良かったです! ----- ## 2023\-12\-21(木) ### ファシリ @sadanora ### ドライバー @shodan ### 読んだところ 6-7-1 331p 「参加者一覧表示機能を作る」から 335pまで。 PR: ### 次回 6-7-1 336p 冒頭から。🚂 ### 学んだこと・感想 - @sharoa - 昨日確認するのを忘れていた「未ログイン状態で『参加する』ボタンを押した時に実行されるアクション」を今日確認できて良かった。きちんと`authenticate`メソッドが呼ばれていました。 - `includes`は`preload`か`eager_load`のどちらかを選択して実行している。 - 実際の現場では`includes`は使わない。(どちらが実行されているかが不明でそれは良くないこと。) - `explain`も含めて、preload、eager_load、includesを調べてみたいと思います。 - @motohiro-mm - 未ログイン状態での参加する→ホームに戻るが確認できて良かったです! - N+1問題対策の`includes`は`preload`と`eager_load`をどちらかを選んで実行している - 実際の仕事ではどちらのパターンのSQLが実行されているかわからないのは良くないので、`includes`は使わない - `explain`を使うとDBのパフォーマンスとか速度とかそういうのを見ることができるので、それらを見て`preload`と`eager_load`のどちらが良いかを自分で判断する - ビューにロジックを書くと見辛くなるのでヘルパーにメソッドを追加する方が良い - 数が多くなるとヘルパーメソッドが見辛くなる&ヘルパーメソッドはオブジェクト指向的ではない - プレゼンター用gem(DraperやActiveDecoratorなど)を利用すると、モデルに紐づいた形でロジックを書けるので、分かりやすくなる - @ayu−0505 - N+1問題の`includes`メソッドは`preload`、`eager_load`の両メソッドのうちのどちらかをRailsが自動選択して行なっている。どのような挙動になるか分からないので、仕事においては基本使わない。 - `explain`メソッドを使用するとDBにおけるパフォーマンスを計測できるので、発行されるSQLとその結果を付き合わせながら、どちらのメソッドを使うか自身で選択した方が良い。 - 「ヘルパーメソッドは書き方がオブジェクト指向的ではない」が最初意味がよく分からなかったのですが、shodanさんが質問してくれたおかげで、なんとなく「どこにも所属していないように見えるから」ということがふわっと理解できました。 - @moegi29 - N+1問題対策の`includes`メソッドは`preload`か`eager_load`のどちらかを選択して実行してくれている - `explain`メソッドで発行されているSQLを計測できる。動くことが第一だけどパフォーマンスも気にかけられると良い。データが溜まっていくようなサービスを作る場合はパフォーマンスも考えたほうが良さそう。 - @sadanora - ActiveRecordの`includes`は`preload`か`eager_load`どちらかを選んでよしなに実行してくれる - どっちが高速かわかっているなら`includes`を使わずに明示的にそれぞれのメソッドを実行した方がよい - `explain`でSQLの実行結果を確認できる。 - [Active Record クエリインターフェイス \- Railsガイド](https://railsguides.jp/active_record_querying.html#explain%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B) - ↑はRailsのexplainメソッド。SQL自体のEXPLAINコマンドとは別。 - `Decorator` - デザインパターンの一種 - ヘルパーメソッドが増えすぎると見通しが悪くなるので、`ActiveDecorator`のようなgemを導入してDecorator層を設けるといいかも。 - @hiromisugie - `includes`メソッドは、`preload`と`eager_load`をよしなに選んでやってくれる。お仕事では、「よしなに」だと困るのでどちらが良いかを検証した上で`preload`と`eager_load`どちらかを選んで使う。SQLの読み込みを見比べるなどしてどちらが良いか確認する。(`explain`というのが使える??)→[Railsガイド:EXPLAINを実行する](https://railsguides.jp/active_record_querying.html#explain%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B) - N+1問題、まだまだピンとこない、、、が、ここはお仕事でも非常に重要なポイントとのことなので、ちゃんと理解しないといけないところ。 - ヘルパーメソッドは便利だけど多用しすぎるのも良く無いらしく、たくさん使いそうだったらプレゼンター用のgemを導入を検討すると良い - 「ヘルパーメソッドはオブジェクト指向っぽくない」とは?→ヘルパーメソッドだと何のメソッドかちょっと理解が難しくなる可能性があるけど、プレゼンターでhogeメソッドを作って`user.hoge.〜`となっていると、少なくともuserモデルの何かの状態だなとあたりをつけることができる。完璧に理解できたかちょっと不明ですが、なるほど!と思いました。 ----- ## 2023\-12\-22(金) ### ファシリ @motohiro-mm ### ドライバー @shodan ### 読んだところ P336 「実際のキャンセル処理を〜」 から P340 COLUMN「コントローラの粒度と名前付け」 まで PR:https://github.com/PerfectRubyonRails-Rindoku/Perfect_Ruby_on_Rails_Ch6/pull/15 ### 次回 P341 「6-8-2 退会処理の作成」から🚂 ### 学んだこと・感想 - @sharoa - find_by!やticket_destroy!のように感嘆符`!`をつけて例外を発生させるコードにしている。 - N+1問題を自分で察知できるか正直不安なので、この`bullet`をあとで入れてみようと思います。 - いつ入会したっけ?というmotohiroさんの質問に、確かに!と気付かされました。今よくあるサービスではこういった類のものが多く、それの理由がわかって良かったです。(めっちゃ端折ってすみません😅) - `resources`メソッドで紐づけられる基本の7つのアクション以外でアクションが新しく欲しくなった時には新設するのではなく、別のコントローラーを作る、という考え方もある。 - @hiromisugie - N+1を検知してくれるgemがある。これは便利そう…!導入必須ではと思ったが、毎回警告されてしつこいとかの事情もあるので、慣れてきたら必要に応じて使う、という感じで良さそう。自分としてはひとまずどこかで試してみたいなと思いました。 - とあるモデルでアクションするときに、必ずしも同名のコントローラで行うわけではない。7つの基本アクション以外のアクションが必要そうになったら、それはControllerを新設するタイミングかもしれないので、立ち止まって考えてみるべし。(「コントローラと仲良しなのはモデルではなくルーティング」) - このアプリでは、GitHubログインした時点でUserモデルがcreateされ、すなわち「入会」している。 - 「退会」とは、UserモデルがdestroyされてUser情報が無くなること。それはUserControllerでやりたくなるかもしれないが、RetirementControllerを別で作ってcreateすることで退会を実現する、というやり方がある。 - ちなみに、見返していたら「入会」もUserControllerではなくSessionControllerでcreateしていた!(必ずしもモデルと同名のコントローラーでアクションするわけではない、の例) - @ayu-0505 - `find_by!`のように意図的にエラーを発生させてユーザーに404画面を表示させる、というテクニックがまだ使いこなせないです。 - N+1問題のアラート用gemのBulletは実際の開発現場でも利用することがあり、初心者のうちにアプリ開発するなら入れておいた方が良いかも。 - ユーザー退会時に「退会済みユーザー」という表示をさせる場合はNOT NULL制約をつけない。(コメントプラクティスで同じようなことをしたくて、これを外すのに苦労しました) - 退会用の`retirements`コントローラーの作成は派生的でなかなか難しかったです。 - 大手サービスのログインを利用する方法は、セキュリティ面やユーザーの利点で広く活用され始めている。 - @shodan - p338の、将来退会ユーザが出てきた時に、関連するeventsテーブルのowner_idがnullになるようにするために、初めはNOT NULL制約を付けない、というのはプラクティスでやらかしてハマったことがあります。 - とりあえず先に、なんとなくNOT NULL制約を付けていたら、ユーザを消した時にDBのエラーになってしまった。 - N+1問題が起きたら教えてくれるgemは自作サービスに入れようと思いました👀 - コントローラに基本の7つ以外のアクションを生やしたくなったときは、立ち止まってコントローラやリソースの構成を考える。 - コントローラと強く結びついているものはモデルというよりかはルーティングという意識(コントローラはルーティングを通ってきたものの交通整理役)。 - @moegi29 - コントローラにおけるインスタンス変数はビューに渡すオブジェクトを表すので不必要にインスタンス変数を利用しないほうが可読性が高くなる。なるほど~と思いました - Rails6だとremote: trueオプションを追加することでAjaxを利用できる - bulletというgemがN+1でエラーを出してくれる、初心者のうちは便利そうだと思いました - @motohiro-mm - なにかを削除するときは、それに関連したmodelがないか注意する - 親を消した時に子も消す:`dependent: :destroy` - N+1問題対策のbulletというgemがある - `form_with`のときは`local: true`だったが、`link_to`は`remote: true`らしい… - rails-ujsでAjaxを利用する話 - コントローラの粒度の話はなかなか難しかったです - 最近のGoogle等を使ったログイン認証が多い理由 - ユーザー側がID,passwordをたくさん覚えずに済む - アプリ側がID,passwordを保管せずに済む -----

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully