IT技術にまつわる実験ノート

「長編を書くより、短編を数多く完成させてください。それが上達への近道です」 by 手塚治虫

自作Webアプリ「IT勉強会用 名刺ジェネレーター」を公開しました!ぜひご活用ください😀

https://it-benkyoukai-meishi.herokuapp.com/

Hacker News クローンアプリを作ってみる 【その2】

はじめに

ここでは、以下の動画を参考にして Hacker New クローンアプリを作成してくことにする。なお、その1はこちら

 

作ってみる

ユーザーを作成する

devise を使うため、gem のインストールを行う。

  • echo "gem 'devise'" >> Gemfile
  • bundle

 

devise のジェネレーターを実行してユーザーの機能を作成する。

 

application.html.erb を編集して、ログイン関係のリンクを作成する。Bootstrap4 を使っている場合は、以下のようになる。

f:id:matt-note:20190304183728p:plain

f:id:matt-note:20190304194843p:plain

 

Link モデルに user_id 属性を追加する。

  • bin/rails g migration AddUseridToLinks user:references
  • bin/rails db:migrate

f:id:matt-note:20190304195321p:plain

-> Link モデルに user_id 属性を追加することができた。

 

モデル間のアソシエーションを設定する。ユーザーは複数のリンクを投稿できる、リンクは一人のユーザーにのみ帰属する、という関係を設定する。

f:id:matt-note:20190304201823p:plain

f:id:matt-note:20190304201814p:plain

 

アソシエーションを使って、コントローラを修正する。

f:id:matt-note:20190304203417p:plain

f:id:matt-note:20190304203634p:plain

-> user_id の値はこのようにアソシエーションを使って設定することができる。この時に、Strong Parametersは修正しなくても動作した。user_id については、ユーザーが直接、値を操作しないので created_at などと同じ扱いで Strong Parameters で値を検証しなくても OK と考えて良いのかもしれない。

 

投稿時間を表示してみる。

f:id:matt-note:20190304204913p:plain

f:id:matt-note:20190304204937p:plain

-> link の created_at から投稿時間を表示できる。Rails の time_ago_in_words メソッドを使うと、「〜時間前」のように変換することができる。

 

ログインしたユーザーが、リンクの投稿者と同じ場合にだけリンクの変更・削除をできるようにする。これはリンクの user_id とログインユーザーの id を比較して判断できる。この点を show.html.erb に追加する。

f:id:matt-note:20190304221953p:plain

ログアウトして、新しくユーザーを作成してログインしてみる。

f:id:matt-note:20190304221157p:plain

-> リンク投稿者でないユーザーには、リンクの変更と削除できないようにできた。

デザインを修正する。application.html.erb とapplication.scss を編集する。

f:id:matt-note:20190305041804p:plain

f:id:matt-note:20190304224507p:plain

f:id:matt-note:20190304224609p:plain

-> ざっくりとデザインを作成できた。

 

コメント機能を作成する

コメントをDBで操作できるようにするため、Comment モデルを作成する。

  • bin/rails g model Comment content:text user:references link:references
  • bin/rails db:migrate

f:id:matt-note:20190305063445p:plain

-> Comment モデルの属性を設定できた。

 

モデル間のアソシエーションを設定する。モデル間の関係はざっくりと以下のようになる。この関係をモデルやルーティングに反映させる。

f:id:matt-note:20190305053755p:plain

 

app/models 内のファイルを編集する。

f:id:matt-note:20190305054011p:plain

f:id:matt-note:20190305054041p:plain

f:id:matt-note:20190305054105p:plain

 

ルーティングで、構造化したリソースの関係を設定する。リンクが複数のコメントを持つという構造でルーティングを作成する。

f:id:matt-note:20190305054301p:plain

 

コメントのコントローラを作成する。

  • bin/rails g controller Comments

 

コメントを投稿できるように、create アクションを作成する。 ここでは主に、①投稿されたコメントの値を検証して、②コメントの値を設定して、③コメントをDBに保存して、④リダイレクトする処理を設定する。

f:id:matt-note:20190305083424p:plain

-> ②の部分がないとうまく動作しない。@link は、リンクのアソシエーションからコメントを取得する時とリダイレクトする時に使うので、作成しておく。

 

ビューを作成する。

  • touch app/views/comments/_form.html.erb
  • touch app/views/comments/_comment.html.erb

 

_form.html.erb を編集する。コメントのフォームはリンクとのアソシエーションから作成する。これでリンクとコメントが関連付いたパスを作成できる。

f:id:matt-note:20190305083904p:plain

f:id:matt-note:20190305084120p:plain

-> これで /links/:id/comments へ POST リクエストするフォームを作成できる。

 

リンクの個別ページでコメントとフォームを表示したいので、部分テンプレートを render する。app/views/links/show.html.erb を編集する。

f:id:matt-note:20190305084930p:plain

f:id:matt-note:20190305084404p:plain

 

コメント表示用の _comment.html.erb を編集する。明示的に値をループさせる場合は、以下のようになる。

f:id:matt-note:20190305091309p:plain

-> link_comment_path(comment.link, comment) からは、/links/7/comments/5 といったパスが作成される。

 

コメント削除用に destroy アクションを作成する。ここでは、①削除するコメントをDBから探して、②そのコメントをDBから削除して、③リダイレクトする処理を設定する。

f:id:matt-note:20190305092050p:plain

 

コメント数を表示してみる。

f:id:matt-note:20190305095633p:plain

f:id:matt-note:20190305095700p:plain

-> pluralize メソッドを使うことで、単数形・複数形に対応できる。

 

フォームを微調整する。

f:id:matt-note:20190305095407p:plain

f:id:matt-note:20190305095445p:plain

-> simple_form では、label: false をオプションで渡すことで、ラベルを非表示にすることができる。

 

コメント削除リンクは、コメント投稿者にだけ表示されるようにする。これはコメントの user_id とログインユーザーの id を比較して判断できる。

f:id:matt-note:20190305100914p:plain

f:id:matt-note:20190305100710p:plain

-> ログアウトしてアクセスしてみる。コメント投稿者以外からはコメント削除用リンクを非表示にすることができた。

 

あとはデザインを追加する。