- 投稿日:2020-08-11T23:01:55+09:00
before_aciton と redirection_to の無限ループ
【結論】:無限ループしないように:exceptを使おう!
❶なぜ無限ループになるのか
1:def indexに行く前にbefore_aciton :goindexが行われます。
2:そうすると定義先に設定されている goindexにあるindexが行われます。
3:そうなるとredirection_toというのはroutes(ルーティング)に戻り、
ルーティングのアクションはindexになります。
4:そうなると、また1:が繰り返され無限ループとなります!無限ループすると、更新ボタンを押した際に
”リダイレクトが繰り返し行われました”とメッセージがでます。本来無限ループはプログラミング用語なので、まさにこの状況のことですね
❷いつ使うのか
パスワード等をもたないユーザーが
ログイン無しに勝手に投稿ができないよう際に必要です!❸どのようにつかうのか
before_aciton :goindexのあとにexcept:[:index]とすると
[:index]は省きますよ!ということなのでdef index しか行われません!❹ここから学んだこと
1:”リダイレクトが繰り返し行われました”とメッセージがでた際は
まっさきに無限ループを疑う癖がつきました!2:そもそもルーティングからコントローラーに行く際に
おかしいことがわかるのでMVCモデルがきちんとわかっていたことも
エラー解決の時間短縮につながりました!
- 投稿日:2020-08-11T23:01:55+09:00
before_aciton と redirection_to 〜リダイレクトが繰り返し行われることについて〜
【この記事の概要】
『結論:無限ループしないように:exceptを使おう』
❶なぜループになるのか
❷いつ使うのか
❸どのようにつかうのか
❹ここから学んだこと
❶なぜ無限ループになるのか
1:def indexに行く前にbefore_aciton :goindexが行われます。
2:そうすると定義先に設定されている goindexにあるindexが行われます。
3:そうなるとredirection_toというのはroutes(ルーティング)に戻り、
ルーティングのアクションはindexになります。
4:そうなると、また1:が繰り返され無限ループとなります!無限ループすると、更新ボタンを押した際に
”リダイレクトが繰り返し行われました”とメッセージがでます。本来無限ループはプログラミング用語なので、まさにこの状況のことですね
❷いつ使うのか
パスワード等をもたないユーザーが
ログイン無しに勝手に投稿ができないようにする際に必要です!❸どのようにつかうのか
before_aciton :goindexのあとにexcept:[:index]とすると
[:index]は省きますよ!ということなのでdef index しか行われません!❹ここから学んだこと
1:”リダイレクトが繰り返し行われました”とメッセージがでた際は
まっさきに無限ループを疑う癖がつきました!2:そもそもルーティングからコントローラーに行く際に
おかしいことがわかるのでMVCモデルがきちんとわかっていたことも
エラー解決の時間短縮につながりました!
- 投稿日:2020-08-11T23:01:55+09:00
before_aciton と redirection_to 〜リダイレクトが繰り返し行われないようにするには〜
【この記事の概要】
『結論:無限ループしないように:exceptを使おう』
❶なぜループになるのか
❷いつ使うのか
❸どのようにつかうのか
❹ここから学んだこと
❶なぜ無限ループになるのか
1:def indexに行く前にbefore_aciton :goindexが行われます。
2:そうすると定義先に設定されている goindexにあるindexが行われます。
3:そうなるとredirection_toというのはroutes(ルーティング)に戻り、
ルーティングのアクションはindexになります。
4:そうなると、また1:が繰り返され無限ループとなります!無限ループすると、更新ボタンを押した際に
”リダイレクトが繰り返し行われました”とメッセージがでます。本来無限ループはプログラミング用語なので、まさにこの状況のことですね
❷いつ使うのか
パスワード等をもたないユーザーが
ログイン無しに勝手に投稿ができないようにする際に必要です!❸どのようにつかうのか
before_aciton :goindexのあとにexcept:[:index]とすると
[:index]は省きますよ!ということなのでdef index しか行われません!❹ここから学んだこと
1:”リダイレクトが繰り返し行われました”とメッセージがでた際は
まっさきに無限ループを疑う癖がつきました!2:そもそもルーティングからコントローラーに行く際に
おかしいことがわかるのでMVCモデルがきちんとわかっていたことも
エラー解決の時間短縮につながりました!
- 投稿日:2020-08-11T23:01:55+09:00
before_aciton と redirection_to 〜リダイレクトが繰り返し行われないようにするには〜
【この記事の概要】
『結論:無限ループしないように:exceptを使おう』
❶なぜループになるのか
❷いつ使うのか
❸どのようにつかうのか
❹ここから学んだこと
❶なぜ無限ループになるのか
1:def indexに行く前にbefore_aciton :goindexが行われます。
2:そうすると定義先に設定されている goindexにあるindexが行われます。
3:そうなるとredirection_toというのはroutes(ルーティング)に戻り、
ルーティングのアクションはindexになります。
4:そうなると、また1:が繰り返され無限ループとなります!無限ループすると、更新ボタンを押した際に
”リダイレクトが繰り返し行われました”とメッセージがでます。本来無限ループはプログラミング用語なので、まさにこの状況のことですね
❷いつ使うのか
パスワード等をもたないユーザーが
ログイン無しに勝手に投稿ができないようにする際に必要です!❸どのようにつかうのか
before_aciton :goindexのあとにexcept:[:index]とすると
[:index]は省きますよ!ということなのでdef index しか行われません!❹ここから学んだこと
1:”リダイレクトが繰り返し行われました”とメッセージがでた際は
まっさきに無限ループを疑う癖がつきました!2:そもそもルーティングからコントローラーに行く際に
おかしいことがわかるのでMVCモデルがきちんとわかっていたことも
エラー解決の時間短縮につながりました!
- 投稿日:2020-08-11T23:01:55+09:00
before_aciton と redirect_to 〜リダイレクトが繰り返し行われないようにするには〜
【概要】
1.結論
2.ループになるのはどういう時か
3.なぜループになるのか
4.どのように解決し、使うのか
5.ここから学んだこと
1.結論
[:except]を使う。
2.ループになるのはどういう時か
I)def indexに行く前にbefore_aciton :goindexが行われます。
II)そうすると定義先に設定されている goindexにあるindexが行われます。
III)そうなるとredirection_toというのはroutes(ルーティング)に戻り、
ルーティングのアクションはindexになります。
IV)そうなると、また1:が繰り返され無限ループとなります!無限ループすると、更新ボタンを押した際に
”リダイレクトが繰り返し行われました”とメッセージがでます。本来無限ループはプログラミング用語なので、まさにこの状況のことですね
3.なぜループになるのか
ルーティングに設定されているアクション と
redirect_toのアクションが永遠と
繰り返されるために起こります!4.どのように解決し、使うのか
before_aciton :goindexの
あとにexcept:[:index]とすれば解決できます!
[:index]は”省きますよ!”という意味なので、
”def index”しか行われません!5.ここから学んだこと
I)”リダイレクトが繰り返し行われました”とメッセージがでた際は
まっさきに無限ループを疑う癖がつきました!II)そもそもルーティングからコントローラーに行く際に
おかしいことがわかるのでMVCモデルがきちんとわかっていたことも
エラー解決の時間短縮につながりました!
- 投稿日:2020-08-11T22:15:14+09:00
【Rails】いいね機能を非同期実装
1. はじめに
以下のデモ動画の様に、ユーザーが投稿した内容に対して"いいね"が出来る機能を実装していきます。
2. 前提条件
既にユーザー登録機能と投稿機能は実装されている前提で、そこに"いいね機能"を追加実装する。という流れで進めていきます。
下記の様なデータベース構造をイメージしてもらえたら分かりやすいと思います。
3. いいね機能の実装
■実装するまでの流れ
ざっくり説明すると、以下の流れで実装していきます。
・モデルの作成
↓
・ルーティングの追加
↓
・コントローラーの作成
↓
・ビューの作成それでは、早速いってみましょー。
3-1. Likeモデルの作成
まずはLikeモデルを作成します。
ターミナルで以下のコマンドを実行してください。ターミナル$ rails g model Like新しくマイグレーションファイルが作成されるので、以下の通りに編集してください。
db>migrate>xxxxxx_create_likes.rbclass CreateLikes < ActiveRecord::Migration[6.0] def change create_table :likes do |t| # ===追記部分=== t.references :tweet, foreign_key: true, null: false t.references :user, foreign_key: true, null: false # ===追記部分=== t.timestamps end end end上記の様にreferences型で保存すると、
tweet_id
とuser_id
を外部キーとして指定することが出来ます。
それではマイグレーションファイルを実行して、likesテーブルを作成しましょう。ターミナル$ rails db:migrate上記のコマンドを実行した後、likesテーブルが作成されたかどうか確認して下さい。
無事作成されている事が確認出来たら、次はアソシエーションの設定です。3-2. アソシエーションの設定
アソシエーションとは、2つのモデル同士の関連付けのことを指します。
UserモデルとLikeモデル、TweetモデルとLikeモデル、それぞれのアソシエーションを設定していきます。UserモデルとLikeモデルのアソシエーションの設定
まずはUserモデルとLikeモデルのアソシエーションを設定していきます。
2つのモデルの関係性は以下の通りです。
・ ユーザーは複数のいいねが可能
・ いいねAをしたユーザーは1人しかいないつまり、UserモデルとLikeモデルは「1対多」の関係になります。
それでは、実際にコードを書いていきましょう。Userモデルに以下の通りコードを追記して下さい。
app>models>user.rbclass User < ApplicationRecord has_many :tweets, dependent: :destroy # この行を追加 has_many :likes end
has_many
は、他のモデルとの間に「1対多」の関係があることを示します。次はLikeモデルに以下の通りコードを追記して下さい。
app>models>like.rbclass Like < ApplicationRecord # この行を追加 belongs_to :user end
belongs_to
はhas_many
の逆で、他のモデルとの間に「多対1」の関係があることを示しています。これで、UserモデルとLikeモデルのアソシエーション設定が出来ました。
TweetモデルとLikeモデルのアソシエーションの設定
同じ要領でTweetモデルとLikeモデルのアソシエーションも設定していきます。
2つのモデルの関係性は以下の通りです。
・ 1つの投稿に対して、複数のいいねがつく
・ いいねAに紐づく投稿は1つしかないつまり、TweetモデルとLikeモデルも「1対多」の関係になります。
それでは、実際にコードを書いていきましょう。Tweetモデルに以下の通りコードを追記して下さい。
app>models>tweet.rbclass Tweet < ApplicationRecord belongs_to :user # この行を追加 has_many :likes, dependent: :destroy end
dependent: :destroy
をつける事で、投稿が削除された時に、その投稿に紐づくいいねも削除されます。次はLikeモデルです。
app>models>like.rbclass Like < ApplicationRecord belongs_to :user # この行を追加 belongs_to :tweet end以上で、全てのモデルのアソシエーションの設定が完了しました。
3-3. バリデーションの設定
投稿Aに対して1人のユーザーがいいねを押せる回数は1回にしたいので、1回以上は押せない様にバリデーションを設定します。
Likeモデルに以下の通り追記して下さい。
app>models>like.rbclass Like < ApplicationRecord belongs_to :user belongs_to :tweet # この行を追加 validates :user_id, uniqueness: { scope: :tweet_id } end上記の様に書く事で、
user_id
とtweet_id
が重複しない様にする事が出来ます。
以上で、バリデーションの設定は完了です。3-4. ルーティングの追加
いよいよ本格的にいいね機能を実装していきます。
まずは、いいね機能で使うルーティングを追加しましょう。
以下の通りコードを追記して下さい。config>routes.rbRails.application.routes.draw do devise_for :users, controllers: { registrations: 'registrations' } resources :tweets, only: [:index, :new, :create, :show, :destroy] do # この行を追加 resources :likes, only: [:create, :destroy] end endいいね情報の保存と削除のルーティングを追加する必要があるので、likesコントローラーの
create
アクションとdestroy
アクションを定義しています。ルーティングをネストにする事で、いいねがどの投稿に紐づくかを明示できます。
コードを追加したら
rails routes
コマンドで、ルーティングの設定が問題ないか忘れずに確認しておきましょう。3-5. likesコントローラーの作成
次にlikesコントローラーを作成していきます。
ターミナルで以下のコマンドを実行してください。ターミナル$ rails g controller likes上記のコマンドを実行すると、likesコントローラーが作成できます。
それでは作成したlikesコントローラーに
create
アクションとdestroy
アクションを作成していきます。
以下の通りコードを追記して下さい。app>controllers>likes_controller.rbclass LikesController < ApplicationController # ===追記部分=== def create @like = current_user.likes.build(like_params) @tweet = @like.tweet if @like.save respond_to :js end end def destroy @like = Like.find_by(id: params[:id]) @tweet = @like.tweet if @like.destroy respond_to :js end end private def like_params params.permit(:tweet_id) end # ===追記部分=== endprivateメソッドやparamsは理解できているものとして、追加したコードについて簡単に説明していきます。
createアクション
まず
@like
には投稿に"いいね"をしたユーザーのuser_id
と、"いいね"された投稿のtweet_id
の情報が入っています。
このコードはbuildメソッドを使って、インスタンスを作成しています。次に
@tweet
には@like
に紐づく投稿の情報、つまり"いいね"された投稿の情報が入ります。
@tweet
はどの投稿に"いいね"を押したのかを判断するために、ビューを作成するところで使います。最後の
if @like.save
の部分は、"いいね"が押された時に返すレスポンスのフォーマットをrespond_to
メソッドで切り替えています。
"いいね"が押されたらリアルタイムでビューを反映させるために、JS形式のフォーマットでレスポンスを返すようにしています。destroyアクション
createアクションのところで説明した内容と重複している部分が多いので簡単に説明すると、受け取ったHTTPリクエストから
id
を判別し、@like
に指定のレコードの情報を入れています。こちらもリアルタイムでビューを反映させるために、JS形式のフォーマットでレスポンスを返すようにしています。
3-5. ビューの作成
いよいよビューの作成です。
まずは投稿一覧のビュー画面を編集していきましょう・・・と言いたいところですが、ビューで使うためのメソッドを先に定義しておきます。
Tweetモデルに以下の通りコードを追記して下さい。
app>models>tweet.rbclass Tweet < ApplicationRecord belongs_to :user has_many :likes, dependent: :destroy # 追加部分(liked_byメソッド) def liked_by(user) Like.find_by(user_id: user.id, tweet_id: id) end # 追加部分 end上記で追加した
liked_by
メソッドは、user_id
とtweet_id
が一致するlikeを探して、無ければnillを返します。それでは、
app/views/tweets/index.html.erb
に以下のコードを追記して下さい。app>views>tweets>index.html.erb<% @tweets.each do |tweet| %> # いいねボタンを表示したい部分に追加 <div class="content-like"> <ul class="content-like__icons"> <li id="<%= tweet.id.to_s %>"> <% if tweet.liked_by(current_user).present? %> <%= link_to (tweet_like_path(tweet.id, tweet.liked_by(current_user)), method: :DELETE, remote: true, class: "liked") do %> <i class="far fa-thumbs-up"></i> <% end %> <% else %> <%= link_to (tweet_likes_path(tweet), method: :POST, remote: true, class: "like") do %> <i class="far fa-thumbs-up"></i> <% end %> <% end %> </li> </ul> </div> # 追加部分はここまで <% end %>
liked_by
に引数としてcurrent_user
を渡すことで、現在ログインしているユーザーが投稿に"いいね"をしているかどうか判断しています。これでユーザーが"いいね"をしていない時に"いいねボタン"をクリックすると、先ほど作成した
create
アクションを実行、ユーザーが"いいね"をしている時はdestroy
アクションを実行と、条件分岐させる事ができました。リンクが押された時に
.js.erb
ファイルを呼び出す必要があるので、link_to
にremote: true
オプションを追加することを忘れないでください。なお"いいねボタン"のアイコンについては、Font Awesome を利用しています。
導入方法については、以下のqiita記事などが参考になるかと思います。
rails font-awesome-sass導入方法次は、createアクションが実行された時に出力するファイルを作成します。
app/views
フォルダ直下にlikes
フォルダを作成し、その中にcreate.js.erb
ファイルを作成してください。ファイルの作成ができたら、以下の通りコードを追記してください。
app>views>likes>create.js.erb$('#<%= @tweet.id.to_s %>'). html('<%= j render "tweets/liked", { tweet: @tweet } %>');上記のコードで、createアクションが実行されたら
tweets
フォルダ内の_liked.html.erb
ファイルを呼び出しています。
tweets
フォルダの中に_liked.html.erb
ファイルを作成し、以下のコードを追加してください。app>views>tweets>_liked.html.erb<%= link_to (tweet_like_path(tweet.id, tweet.liked_by(current_user)), method: :DELETE, remote: true, class: "liked") do %> <i class="far fa-thumbs-up"></i> <% end %>上記のコードで、"いいねボタン"を押したら"いいね"を取り消すHTMLを表示するようにしています。
同じ流れで、destroyアクションが実行された時に呼び出されるファイルも作っていきましょう。
app/views>likes
フォルダの中にdestroy.js.erb
ファイルを作成してください。ファイルの作成ができたら、以下の通りコードを追記してください。
app>views>likes>destroy.js.erb$('#<%= @tweet.id.to_s %>'). html('<%= j render "tweets/like", { tweet: @tweet } %>');
tweets
フォルダの中に_like.html.erb
ファイルを作成し、以下のコードを追加してください。app>views>tweets>_like.html.erb<%= link_to (tweet_likes_path(tweet), method: :POST, remote: true, class: "like") do %> <i class="far fa-thumbs-up"></i> <% end %>以上で非同期でいいね機能を実装する事ができました。
あとは見た目ですが、クラス名を、いいねされている時は
liked
されていない時はlike
としていますので、CSSで自分好みにカスタマイズしてみてください。私の場合は以下の様にして、いいねがされた時はレッド、されていない時はグレーにアイコンの色を変えています。
app>assets>stylesheets>tweets>_tweet.css.like { color: gray; } .liked { color: red; }4. さいごに
今回がはじめての投稿になりますが、記事を書くのって想像していたよりも大変ですね。
もし分かりにくい部分や、間違っている部分がある場合はご指摘いただけると嬉しいです。最後まで読んでいただき、ありがとうございました☺️
- 投稿日:2020-08-11T21:16:16+09:00
独学未経験エンジニアがweb系自社開発企業でアルバイトを2ヶ月してみて感じたこと
簡単な自己紹介
- 大学では機械工学を専攻
- プログラマに魅力を感じ2019年新卒でメーカー子会社のIT会社に入社
- 入社してから10ヶ月で会社を退職
- そこから4ヶ月間独学で勉強し、現在web系の自社開発企業でアルバイト中
ニートになって独学していた時代
新卒で入社したときに感じたことや退職理由はまた今度別の記事で書いてみたいと思います。
勉強したこと一覧
progate(HTML,CSS,Javascript,Ruby,RubyonRails)
railsチュートリアル解説動画
2周はした。1周目は動画を見るだけで、2周目は手を動かしながらでした。
かなりお世話になり、railsチュートリアルとは友達になった気がするRuby on Rails5 超入門
amazonリンク
読んだのは3割ぐらいだけRuby on Rails5 速習実践ガイド
amazonリンク
辞書的な感じで使ったりした。暇なときに読んでみてもためになることが多い。Gitが、おもしろいほどわかる基本の使い方33
amazonリンク
gitの操作の基礎を学んだ。すぐに読み終わる内容なので、読みやすいキタミ式イラストIT塾 基本情報技術者
amazonリンク
コンピュターの基礎を理解するのにはちょーど良かった。時間をかけてちょっとずつ読んだwebを支える技術
amazonリンク
何を書いているのか全然分からなかった。kindle版で技術書は読みにくい。図解即戦力 AWSのしくみと技術がしっかりわかる教科書
amazonリンク
AWSのサービスの概要は大体理解したけど、実装まではできずプログラミングスクール受講(ポテパンキャンプ)
ポテパンのリンク
gitの操作、N+1問題、Rspecの書き方はここで自主的に学んだEveryday Rails - RSpecによるRailsテスト入門 購入リンク
ちょくちょく参考にできた。これも詰まったときに検索する用。ポートフォリオ作成
当時はAWS,Docker, CI/CD, Kubernetes等についてはほぼほぼ理解できずに、断念していました。
開発環境なんかはrailsチュートリアルで使っていたcloud9を使っていました。
まずはHerokuに自分が一生懸命作成したアプリケーションをデプロイし、公開できるようにしました。
一応独自ドメイン,SSL化程度は行っておき、Herokuは有料プランを使用し、少しでも応答速度が早くなるようにしておきました。
一応当時のポートフォリオのソースコードのリンクを貼っておきます。
https://github.com/ak2-lucky/clothes-app
ファッションが好きだった僕は洋服のレビューサイトを作りました。この記事を見ている駆け出しエンジニアの日々勉強されている方々はこう思っているかもしれません。
AWSにデプロイすらできないのに、webエンジニアになれるの?
Dockerで開発環境も構築できないの?
自動テストぐらいはやっといたら?現役のwebエンジニアも同じことを思うでしょう。
ポートフォリオも作りきれないような奴はエンジニアになる資格なんかないよって。
なぜならポートフォリオだけは運にも左右されない自分の努力だけで100パーセント作りきれる成果物だからです。確かにそうです。
僕の努力不足です。何の異論もありません。
認めます。そして就職活動をはじめます。
就職活動時代
結果からゆうとほぼ全落ち。
面接までいったのは1.2回でした。
面談してくれた会社で研究開発で人材を募集しているからそこに来ないか?と言ってくれた企業もありました。(結局いかず)
コロナの影響とかいう言い訳はしません。
全て自分の実力不足。
アルバイトも採用している企業に応募し,1社だけ何とかアルバイトとして採用していただきました。今回で自分の市場価値を知りました。
大学は何も考えずに過ごし、新卒で入社した会社を何の成果も残さず10ヶ月で退職。
世間はそんな奴のことを評価はしてくれません。
もちろん当然の評価です。アルバイトとしてweb系自社開発企業で働く(今)
技術スタック:AWS,Docker,Laravel+vue.js
働いてみるまでLaravelはおろかPHPも触ったことありませんでした。vue.jsもですが。
詳細は省きますが、実際に働いてみて感じるのは、プログラムを書く以外のことです。
技術のキャッチアップ云々の話ではなくて、組織作り、開発の体制やフローなどの重要さについてです。
自分はプログラミングが苦ではありません。
しかし、プログラミング業務以外の部分でストップすることが多い場合があります。(例えば、なぜこの変更を加えられたのかというコメントがないandコードを見ても分からない)
連携がうまく取れなくて、個々の意思で変更が加えられたりするので、デザインがバラバラ。
issue作成者等に確認もしないで変更を進められていたり。
CI/CDもそのうちの一つですが、issueを作成するのは誰なのか、誰の判断を最終的に仰ぐのか、UIのデザインは好きに決めていいのか、プルリクではどこを見ればいいのか、など他にもいろいろありますが。。。会社によって開発の進め方などは違うと思うので、一概にあれが悪い、これが悪いというわけではありませんが、開発体制や組織作りはサービス開発にかなり大きく影響するように感じました。
開発言語や技術以前にこういった根本的な開発の導線を確保する重要性を学びました。
最後に
ここまで読んでいただいた方には、いろいろ思うことがあると思います。
2ヶ月しか働いていない、しかもアルバイト如きが何を偉そうなこと言ってるんだ!
とか思ってる方いるかもしれません。ですが、これは個人の一意見であります。
ただ同じように駆け出しエンジニアの方の参考になればいいなと思って書きました。webエンジニアへの道は高く険しいように感じます。
しかし、自分にとって登りたい山がどれだけ高かろうが、険しかろうが、関係ありません。
ただ登るだけ
毎日頑張って積み上げて、疲れたら一緒にサボりましょう。長くなりましたが、初投稿は以上になります。
ここまで読んでいただきありがとうございました。
- 投稿日:2020-08-11T20:12:25+09:00
RailsをAWS ECS(Fargate)でホストする環境構築のすべて【1. 前談、N/W+α】
本記事シリーズの構成(予定)
- 前談、N/W+α(これ)
- Docker定義、ECRの設定
- ECSの設定、デプロイ
- SSMの設定
構築環境全体像
実現したいポイント
* Docker環境で開発を行っているRailsプロジェクトを、Fargate起動のECSでホストします。
* ECSタスクは複数設け、負荷分散します。
* AWS System Manager セッションマネージャを使用してECSに「接続し、CUIで操作可能にします。ネットワーク+ALB+RDSの環境構築
VPC
作成した後、VPC一覧右上のアクション>DNSホスト名の編集から有効化をしておきます。
サブネット
下記の通り、わかりやすくサブネットを切っておきます。
subnet CIDR public-subnet-a 10.0.10.0/24 public-subnet-c 10.0.20.0/24 public-subnet-d 10.0.30.0/24 インターネットゲートウェイ
作成したら、右上のアクション>VPCにアタッチから、
sample-vpcにアタッチするのを忘れずに。エンドポイント
この後設定していくサービスを利用するために、4つのエンドポイントを設けます。
- com.amazonaws.ap-northeast-1.ecr.api
- com.amazonaws.ap-northeast-1.ecr.dkr
- com.amazonaws.ap-northeast-1.s3
- com.amazonaws.ap-northeast-1.ssm
エンドポイントを選択して、
アタッチしたいサブネットはpublic-subnet-a,public-subnet-cの2つのみ指定。
Interfaceタイプのエンドポイントには、セキュリティグループを適用する。
エンドポイント用のセキュリティグループとして、443ポートを開けたセキュリティグループを作っておきましょう。
S3はGatewayタイプなのでセキュリティグループではなく、ルートテーブルに従います。
ルートテーブル
VPC作成時に自動作成されているものを編集します。
ルート一覧に、先ほど追加したエンドポイントの設定が加わっています。
ルートの編集ボタンを押下します。
ここにインターネットゲートウェイへのルーティングを加えます。
編集したルートテーブルにサブネットを関連づけます。
インターネットゲートウェイのルーティングを設定したルートテーブルに、サブネットを関連づけることで、
いわゆるpublic subnetになります。
public-subnet-a,cはSSMを利用した接続時にパブリックでないとうまくできなかったため、セキュリティグループでIP、ポート制限をかけつつパブリック化する判断にしました。
public-subnet-dはデータベース用に取っていますが、データベースに外部からクライアント接続したいのでパブリックにしています。ここをパブリックにするかどうかは任意です。
ALB
アプリケーションロードバランサーを選択して作成していきます。
実用するときには、SSL証明書を適用して443ポート開けることになると思いますが、
今回は検証なので、80ポート開けておきます。
ルーティング先はECSをおくサブネットに絞って設定しています。
セキュリティグループはここでついでに新規作成しています。
80ポートのインバウンドを設定しています。検証なのでマイIPのみにしたほうがよかったかも。
ターゲットグループをここで一緒に新規作成します。
ターゲットの種類はIPにします。
ヘルスチェックはアプリケーションに用意したヘルスチェック用のパスを指定してください。
RDS
作成内容は完全に任意です。
MySQL 8.0.19でインスタンスをパブリックアクセスありで作成しました。
このときに適用したセキュリティグループは以下の通りです。
3306ポートをマイIPからのみアクセス可能にしています。
まとめ
ここまででこんな感じの大枠まで作りました。
次の記事で、Dockerの定義と、コンテナイメージをECRにプッシュするまでを記載したいと思います。
- 投稿日:2020-08-11T20:07:21+09:00
削除機能の追加方法
- 投稿日:2020-08-11T20:02:09+09:00
docker buildするとextconf failedout of memoryエラーが発生した話
使用技術
- amazon linux2
- Docker 19.03.6
エラーが発生した状況
イメージをbuildしようとして
docker build
コマンドを実行すると下記エラーdocker extconf failedout of memoryその下に赤字でnokogiriがインストール出来ないと書いてあり指定されたコマンドを走らせ再度buildしてもエラーが直らず...。
(目立つ方ばかり気にしていて上記エラーに気づくのが遅れてしまった)上記エラー文で検索するとAWSの無料枠内のEC2インスタンスタイプ、t2.microでは容量が足りないため課金しなくてはいけないとの記事を見つけ驚き。しかも月2000円ですと...。
課金しなくて済む方法が知りたい!調べて判明した原因
dockerのvolumeが膨れ上がっていました。
以前もEC2のメモリが足りなくなり増設したのにまた!?と思いつつディスクの空き容量を調査
$ df -h devtmpfs 474M 0 474M 0% /dev tmpfs 492M 0 492M 0% /dev/shm tmpfs 492M 436K 492M 1% /run tmpfs 492M 0 492M 0% /sys/fs/cgroup /dev/xvda1 32G 13G 20G 40% / tmpfs 99M 0 99M 0% /run/user/1001大丈夫そう。
お次はディスクの使用量を調査
$ du -hs /* . . . 4.4G /usr 6.9G /var6.9Gも使っていました。
ここがdockerコンテナの居場所なので原因はdockerですね。
ここまで分かると使えるキーワードも増えて検索がしやすいです(嬉しい)ついにvolumeを減量していきましょう
$ docker system prune -a --volumes
docker system
は後ろにオプションをつけて、未使用のコンテナ、イメージ、ネットワーク、ボリュームを削除するコマンドです。
--volumes
オプションはdocker17.06.1から追加されたようですのでそれ以前のバージョンでは使用できません。これで再度使用量を調べると
$ du -hs /* . . . 4.4G /usr 2.9G /var減りました。よし。
参考
https://qiita.com/shione/items/dfa956a47b6632d8b3b3
https://qiita.com/381704/items/5d526e34da95fd307480
https://docs.docker.com/engine/reference/commandline/system_prune/
- 投稿日:2020-08-11T19:10:19+09:00
Secretsantasができるまで③ post機能(CRUD)
更新予定
memo
- index
- new
- show
- destroy
- edit
- 投稿日:2020-08-11T18:02:59+09:00
【Ruby on Rails】アプリケーション作成〜サーバー起動まで&ポート番号って何?
Ruby on Railsの初歩中の初歩ですが、まとめです。
1.アプリケーションを作成する。
ターミナルを起動します。
$ rails new アプリケーション名上記コマンド実行により、入力したアプリケーション名と同名のフォルダが作成され、その中に開発に必要なフォルダやファイルが用意されます。
アプリケーション名/ ├ app/ アプリケーションのメインフォルダ ├ config/ 設定情報に関するフォルダ ├ db/ データベースに関するフォルダ └: その他2.サーバーを起動する。
ターミナルに入力
$ rails serverGoogle ChromeやSafariなどのブラウザでlocalhostを3000番ポートで開きます。
localhost:3000参考: Ruby on Rails5 学習コース I | プログラミングの入門なら基礎から学べるProgate[プロゲート]
ポート番号とはなんでしょうか?
今回、3000番ポートと出てきましたが、ポート番号という言葉は、インフラ関係の知識としては必須です。
インターネット用語1分解説~ポート番号とは~ - JPNICには、以下のように説明されています。
ポート番号とは、TCP/IP通信において、 コンピュータが通信に使用するプログラムを識別するための番号です。 ポート番号は16ビットの整数であり、 0番~65535番まであります。
更に深いところで、ポート番号には大きく分けて3種類あり
* ウェルノウンポート番号(0番~1023番) - 使用目的が定められたポート番号
* 登録ポート番号(1024番~49151番) - IANAが登録を受け付け、 公開
* ダイナミック/プライベートポート番号(49152番~65535番) - 誰でも自由に使用できるポートとして開放上記のように分類されます。
ちなみに、今回は、Ruby on Railsだと3000番ポート、Djangoだと8000番ポートがデフォルトで使われていますが、この3000番と8000番は登録ポート番号(1024番~49151番)に該当する為、IANAが登録を受け付け、 公開できるようになっています。
IANAとは?
Internet Assigned Numbers Authorityの略称。
ドメイン名、IPアドレス及びAS番号、各プロトコルで使われるプロトコル名及び番号といったインターネット資源を管理する機能です。
IANAは、南カリフォルニア大学情報科学研究所(ISI)の故ジョン・ポステル(Jonathan Bruce Postel)氏が中心となり、1988年に設立されました。IANAはインターネットに関する最も古い機関の一つであり、その活動は1970年代にまで遡ることができます。
その後、1998年10月にICANNが設立され、IANAが行っていた各種資源のグローバルな管理・調整の役割は ICANNの一部局として引き継がれました。そのような経緯から、歴史的なことも含めインターネット資源を管理する機能を表す意味で使用されています。 引用:JPRS用語辞典|IANA(アイアナ)TCP/IP通信やHTTPなどは、更に深掘りできるので機会があったら記事にする予定です。
- 投稿日:2020-08-11T18:02:59+09:00
【Ruby on Railsの手順】アプリケーション作成〜サーバー起動まで&ポート番号って何?
Ruby on Railsの初歩中の初歩ですが、まとめです。
1.アプリケーションを作成する。
ターミナルを起動します。
$ rails new アプリケーション名上記コマンド実行により、入力したアプリケーション名と同名のフォルダが作成され、その中に開発に必要なフォルダやファイルが用意されます。
アプリケーション名/ ├ app/ アプリケーションのメインフォルダ ├ config/ 設定情報に関するフォルダ ├ db/ データベースに関するフォルダ └: その他2.サーバーを起動する。
ターミナルに入力
$ rails serverGoogle ChromeやSafariなどのブラウザでlocalhostを3000番ポートで開きます。
localhost:3000参考: Ruby on Rails5 学習コース I | プログラミングの入門なら基礎から学べるProgate[プロゲート]
ポート番号とはなんでしょうか?
今回、3000番ポートと出てきましたが、ポート番号という言葉は、インフラ関係の知識としては必須です。
インターネット用語1分解説~ポート番号とは~ - JPNICには、以下のように説明されています。
ポート番号とは、TCP/IP通信において、 コンピュータが通信に使用するプログラムを識別するための番号です。 ポート番号は16ビットの整数であり、 0番~65535番まであります。
更に深いところで、ポート番号には大きく分けて3種類あり
* ウェルノウンポート番号(0番~1023番) - 使用目的が定められたポート番号
* 登録ポート番号(1024番~49151番) - IANAが登録を受け付け、 公開
* ダイナミック/プライベートポート番号(49152番~65535番) - 誰でも自由に使用できるポートとして開放上記のように分類されます。
ちなみに、今回は、Ruby on Railsだと3000番ポート、Djangoだと8000番ポートがデフォルトで使われていますが、この3000番と8000番は登録ポート番号(1024番~49151番)に該当する為、IANAが登録を受け付け、 公開できるようになっています。
IANAとは?
Internet Assigned Numbers Authorityの略称。
ドメイン名、IPアドレス及びAS番号、各プロトコルで使われるプロトコル名及び番号といったインターネット資源を管理する機能です。
IANAは、南カリフォルニア大学情報科学研究所(ISI)の故ジョン・ポステル(Jonathan Bruce Postel)氏が中心となり、1988年に設立されました。IANAはインターネットに関する最も古い機関の一つであり、その活動は1970年代にまで遡ることができます。
その後、1998年10月にICANNが設立され、IANAが行っていた各種資源のグローバルな管理・調整の役割は ICANNの一部局として引き継がれました。そのような経緯から、歴史的なことも含めインターネット資源を管理する機能を表す意味で使用されています。 引用:JPRS用語辞典|IANA(アイアナ)TCP/IP通信やHTTPなどは、更に深掘りできるので機会があったら記事にする予定です。
- 投稿日:2020-08-11T18:02:06+09:00
【Rails】RSpecでテストしたい。そんなあなたの一歩を応援します【導入手順】
参考対象者
- Rails6.0で、RSpecでテストしたいなと考えている方
環境
$ rails -v Rails 6.0.3.1$ ruby -v ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-darwin19]RSpecを導入する
Gemfilegroup :development, :test do gem 'rspec-rails' end$ bundle install $ rails g rspec:installgemをインストールし、設定ファイルをジェネレータで作成する。
.rspec--require spec_helper --format documentationテストをドキュメント形式に設定する。
System Specを導入する ブラウザテスト
Gemfilegroup :test do gem 'capybara', '>= 2.15' gem 'webdrivers' end$ bundle installまずは、gemをインストールする。
spec/rails_helper.rbRSpec.configure do |config| # 一番下の直前に追加 config.before(:each) do |example| if example.metadata[:type] == :system driven_by :selenium, using: :headless_chrome, screen_size: [1400, 1400] end end endブラウザテストが機能するように、RSpecの設定を変更する。
- 投稿日:2020-08-11T15:35:29+09:00
[Rails] 画像の投稿機能を実装する
はじめに
初心者なので間違ってるところがあれば教えてください(>_<)
掲示板サイトのpostに画像投稿機能をつけました。
難しかったので再確認の為に記事を書きます。今回はpostに対して複数の画像を投稿出来るようにしたかったのでpostに対して1対多の関係になるようにimageモデルを作りました。
1. Imageモデルの作成
Modelとマイグレーションファイルを作成します!
$ rails g model Image image_url:string post:references作成されたマイグレーションファイル開いて確認をします!
db/migrate/年月日時_create_images.rbclass CreateImages < ActiveRecord::Migration[5.0] def change create_table :images do |t| t.string :image_url t.references :post, foreign_key: true t.timestamps end end特に変更する所はありません。
カラムが合っているか確認します。マイグレーションの実行
$ rails db:migrateImage Modelを開きます
app/model/image.rbclass Image < ApplicationRecord belongs_to :post end既にbelongs_to :postが書かれています。
Post Modelを開きます
app/models/post.rbclass Post < ApplicationRecord belongs_to :user validates :content, presence: true, length: { maximum: 255 } has_many :favorites has_many :likeds, through: :favorites, source: :user endhas_many :imagesを書き足します!
app/models/post.rbclass Post < ApplicationRecord belongs_to :user validates :content, presence: true, length: { maximum: 255 } has_many :favorites has_many :likeds, through: :favorites, source: :user has_many :images #この行を追加 endこれでとりあえず1対多の関係はできました。
2. accepts_nested_attributes_forとfields_forを使ってhas_many関連の子レコードを作成/更新するフォームを作成
今回は、postを投稿した時にimageも同時に投稿出来るように一つのフォームで複数のフィールドの登録をまとめて行うようにします。
その為に必要なのが・accepts_nested_attributes_for
・fields_forです!
これを使うとhas_many関連の子レコードをまとめて登録出来るようになります!入れ子のフォームを扱う為の下準備
テーブルをまとめて登録するために入れ子のフォームを作成することになります。それを可能にするためにaccepts_nested_attributes_forというメソッドを使いましょう。
それでは、accepts_nested_attributes_forの設定を行ます。
post.rbに追記していきましょう。app/models/post.rbclass Post < ApplicationRecord belongs_to :user validates :content, presence: true, length: { maximum: 255 } has_many :favorites has_many :likeds, through: :favorites, source: :user has_many :images accepts_nested_attributes_for :images #この行を追加 endposts_controller.rbの追記
posts_controller.rbにも追記していきます。
app/controllers/posts_controller.rbclass PostsController < ApplicationController def new @post = Post.new @post.images.build #この行を追加 end def create @post = current_user.posts.build(post_params) if @post.save flash[:success] = 'メッセージを投稿しました。' redirect_to root_url else @posts = current_user.feel_posts.order('created_at DESC').page(params[:page]).per(10) flash.now[:danger] = 'メッセージを投稿に失敗しました。' render 'posts/new' end end private def post_params params.require(:post).permit(:content, :security, images_attributes: [:image_url]) #この行を追加 end@post.images.build
とparams内の
images_attributes: [:image_url]
を追記しました。
nested modelの許可するパラメーターの値はparams内images_attributes:を使って記述します。fields_forを使ってフォームの中に入れ子を作る
views/posts/new.html.erb<%= form_for(@post) do |f| %> <div class="form-group"> <%= f.label :content, 'コメント' %> <%= f.text_area :content, class: 'form-control', rows: 5, placeholder: 'コメントを入力してください' %> </div> <div class="form-group"> <%= f.label :security, 'Security_Level' %> <%= f.number_field :security, class: 'hoge', min: 0, max: 100 %> </div> <%= f.fields_for :images do |i| %> #この行に追加しました。 <%= i.file_field :image_url %> <% end %> <div class="text-right"> <%= f.submit 'Post', class: 'btn btn-primary' %> </div> <% end %>さて、これで一つのフォームで複数のフィールドの登録をまとめて行うよにはできましたがまだ画像をアップロードできません(+_+)
次は、CarrierWaveというgemを使って画像をアップロード出来るようにしていきます!!
3. CarrierWaveをインストールして画像をアップロードできるようにする
Gemfileにgemを追加します。
Gemfilegem 'carrierwave' #画像アップロード$ bundle installコマンドを実行します!
アップローダーの作成
$ rails g uploader imageimageのところは、適当な名前を記入してください。今回は、imageと名付けました。
コマンドを実行すると、create app/uploaders/image_uploader.rbとなり、アップローダーが作成されました。
モデルの関連付け
/models/image.rbに以下を追記し、カラムの名前をmount_uploaderに指定します。
app/models/image.rbclass Image < ApplicationRecord belongs_to :post mount_uploader :image_url, ImageUploader #この行に追加 endimageモデルにはimage_urlというカラムがあり、そこに画像のURLを格納するような仕様になっています。
Viewに表示
view/posts/_posts.html.erb<div> <%= link_to post.user.name, user_path(post.user) %><span class="text-muted">posted at<% post.created_at %></span> </div> <div> <p><%= post.content %></p> </div> <div> <% post.images.each do |image| %> <%= image_tag image.image_url.url %> #ここに表示 <% end %> </div> <div> <p>Security_Level <%= post.security %></p> </div> <div class="batton"> <%= render 'favorites/favorite_button', post: post %> <% if current_user == post.user %> <%= link_to "Delete", post, method: :delete, data: { confirm: "本当に削除しますか?" }, class: 'btn btn-danger btn-xs' %> <% end %>以上で画像投稿機能終わりです!!
終わりに
今回複数の画像を投稿出来るようにしたかったのですが、今のままだと画像を一つしか投稿できませんでした。
勉強不足です。すみません。(>_<)また複数画像を投稿出来るやり方がわかったら記事を書こうと思います!!!
- 投稿日:2020-08-11T15:35:29+09:00
画像の投稿機能
はじめに
初心者なので間違ってるところがあれば教えてください(>_<)
掲示板サイトのpostに画像投稿機能をつけました。
難しかったので再確認の為に記事を書きます。今回はpostに対して複数の画像を投稿出来るようにしたかったのでpostに対して1対多の関係になるようにimageモデルを作りました。
1. Imageモデルの作成
Modelとマイグレーションファイルを作成します!
$ rails g model Image image_url:string post:references作成されたマイグレーションファイル開いて確認をします!
db/migrate/年月日時_create_images.rbclass CreateImages < ActiveRecord::Migration[5.0] def change create_table :images do |t| t.string :image_url t.references :post, foreign_key: true t.timestamps end end特に変更する所はありません。
カラムが合っているか確認します。マイグレーションの実行
$ rails db:migrateImage Modelを開きます
app/model/image.rbclass Image < ApplicationRecord belongs_to :post end既にbelongs_to :postが書かれています。
Post Modelを開きます
app/models/post.rbclass Post < ApplicationRecord belongs_to :user validates :content, presence: true, length: { maximum: 255 } has_many :favorites has_many :likeds, through: :favorites, source: :user endhas_many :imagesを書き足します!
app/models/post.rbclass Post < ApplicationRecord belongs_to :user validates :content, presence: true, length: { maximum: 255 } has_many :favorites has_many :likeds, through: :favorites, source: :user has_many :images #この行を追加 endこれでとりあえず1対多の関係はできました。
2. accepts_nested_attributes_forとfields_forを使ってhas_many関連の子レコードを作成/更新するフォームを作成
今回は、postを投稿した時にimageも同時に投稿出来るように一つのフォームで複数のフィールドの登録をまとめて行うようにします。
その為に必要なのが・accepts_nested_attributes_for
・fields_forです!
これを使うとhas_many関連の子レコードをまとめて登録出来るようになります!入れ子のフォームを扱う為の下準備
テーブルをまとめて登録するために入れ子のフォームを作成することになります。それを可能にするためにaccepts_nested_attributes_forというメソッドを使いましょう。
それでは、accepts_nested_attributes_forの設定を行ます。
post.rbに追記していきましょう。app/models/post.rbclass Post < ApplicationRecord belongs_to :user validates :content, presence: true, length: { maximum: 255 } has_many :favorites has_many :likeds, through: :favorites, source: :user has_many :images accepts_nested_attributes_for :images #この行を追加 endposts_controller.rbの追記
posts_controller.rbにも追記していきます。
app/controllers/posts_controller.rbclass PostsController < ApplicationController def new @post = Post.new @post.images.build #この行を追加 end def create @post = current_user.posts.build(post_params) if @post.save flash[:success] = 'メッセージを投稿しました。' redirect_to root_url else @posts = current_user.feel_posts.order('created_at DESC').page(params[:page]).per(10) flash.now[:danger] = 'メッセージを投稿に失敗しました。' render 'posts/new' end end private def post_params params.require(:post).permit(:content, :security, images_attributes: [:image_url]) #この行を追加 end@post.images.build
とparams内の
images_attributes: [:image_url]
を追記しました。
nested modelの許可するパラメーターの値はparams内images_attributes:を使って記述します。fields_forを使ってフォームの中に入れ子を作る
views/posts/new.html.erb<%= form_for(@post) do |f| %> <div class="form-group"> <%= f.label :content, 'コメント' %> <%= f.text_area :content, class: 'form-control', rows: 5, placeholder: 'コメントを入力してください' %> </div> <div class="form-group"> <%= f.label :security, 'Security_Level' %> <%= f.number_field :security, class: 'hoge', min: 0, max: 100 %> </div> <%= f.fields_for :images do |i| %> #この行に追加しました。 <%= i.file_field :image_url %> <% end %> <div class="text-right"> <%= f.submit 'Post', class: 'btn btn-primary' %> </div> <% end %>さて、これで一つのフォームで複数のフィールドの登録をまとめて行うよにはできましたがまだ画像をアップロードできません(+_+)
次は、CarrierWaveというgemを使って画像をアップロード出来るようにしていきます!!
3. CarrierWaveをインストールして画像をアップロードできるようにする
Gemfileにgemを追加します。
Gemfilegem 'carrierwave' #画像アップロード$ bundle installコマンドを実行します!
アップローダーの作成
$ rails g uploader imageimageのところは、適当な名前を記入してください。今回は、imageと名付けました。
コマンドを実行すると、create app/uploaders/image_uploader.rbとなり、アップローダーが作成されました。
モデルの関連付け
/models/image.rbに以下を追記し、カラムの名前をmount_uploaderに指定します。
app/models/image.rbclass Image < ApplicationRecord belongs_to :post mount_uploader :image_url, ImageUploader #この行に追加 endimageモデルにはimage_urlというカラムがあり、そこに画像のURLを格納するような仕様になっています。
Viewに表示
view/posts/_posts.html.erb<div> <%= link_to post.user.name, user_path(post.user) %><span class="text-muted">posted at<% post.created_at %></span> </div> <div> <p><%= post.content %></p> </div> <div> <% post.images.each do |image| %> <%= image_tag image.image_url.url %> #ここに表示 <% end %> </div> <div> <p>Security_Level <%= post.security %></p> </div> <div class="batton"> <%= render 'favorites/favorite_button', post: post %> <% if current_user == post.user %> <%= link_to "Delete", post, method: :delete, data: { confirm: "本当に削除しますか?" }, class: 'btn btn-danger btn-xs' %> <% end %>以上で画像投稿機能終わりです!!
終わりに
今回複数の画像を投稿出来るようにしたかったのですが、今のままだと画像を一つしか投稿できませんでした。
勉強不足です。すみません。(>_<)また複数画像を投稿出来るやり方がわかったら記事を書こうと思います!!!
- 投稿日:2020-08-11T14:36:00+09:00
RailsアプリをAWSにあげるために必要な知識
はじめに
プログラミング未経験の筆者がRailsアプリをAWSにあげるのに、必要となった最低限の知識をざっくりとまとめました。
まとめた内容は以下の通りです。
・AWS
・VPC
・EC2
・RDSAWSのネットワークサービス
まずはじめにAWSのネットワークについてです。
AWSを使うときにはじめに触れるのがリージョンとアベイラビリティーゾーン(AZ)です。リージョン
リージョンはAWSがサービスを提供している拠点(国と地域)のことを指しています。
遠いリージョンをを使うとネットワーク遅延が発生してしまう可能性があるので、基本的には東京リージョンを使いましょう。アベイラビリティーゾーン(AZ)
アベイラビリティーゾーン(AZ)はデータセンター(サーバー機などのIT機器を設置・収容する場所を提供し、安定的に運用できるようさまざまなサービスを提供する施設)とほぼ一緒です。
AZはリージョンごとに用意されていて、東京リージョンでは4つのAZが用意されています。AWSでは複数のAZを利用すること(マルチAZ構成)が推奨されています。
マルチAZ構成であれば、もし一つのAZに障害が起きても、別のAZを利用することでネットワーク障害を回避できるからです。続いてAWSのサービスについて説明していきます。
VPC(Virtual Private Cloud)
参照:VPC とサブネット
VPCはネットワークを作成するサービスです。
上図の通りAWSのネットワークの中にVPCのネットワークを作成します。
そしてVPCはサブネットを作成することで分割できます。ざっくり言うと
大きな箱(AWS)の中にそこそこ大きい箱(VPC)があって、その中に小さな箱(サブネット)があるイメージですね。そして、この小さな箱(サブネット)の中にこれから説明するEC2やRDSが入っていきます。
EC2(Elastic Compute Cloud)
参照:インスタンスの開始方法
EC2は仮想サーバ(インスタンス)、ファイアウォール(セキュリティグループ)などを利用できるサービスです。
知らない単語が出てきましたね...
ざっくり説明していきます。
インスタンス
インスタンスは従来のオンプレミス環境上のサーバに相当します。
インスタンスはOS、CPU、メモリ等の情報を持っています。
つまり「インスタンスを作成する」というのは
「OS、CPU、メモリ等の条件を選択し、自分が求めるサーバーを作成する」ことです。セキュリティグループ
セキュリティグループはAWS標準のファイアウォール機能です。
EC2インスタンスへのアクセスを許可したり、トラフィックを制御することができます。デフォルトでは全ての通信が遮断してあります。(重要)
そのため特定の通信を許可する必要があります。アクセスの許可は通信の方向で分けられ、インバウンドとアウトバウンドに分けられています。
インバウンド: 外部からインスタンスへの通信を許可(外側→インスタンス)
アウトバウンド: インスタンスから外部への通信許可(インスタンス→外側)初心者がAWSを扱う上で一番エラーが発生しやすい部分がこのセキュリティグループだと思います。
複数のサービスを紐づけるためにセキュリティグループは必須なのでよく理解しておきましょう。
RDS(Relational Datebase Service)
RDSはクラウド上でリレーショナルデータベース(RDBMS)を利用できるサービスです。
AWS上でRDBMSを利用する方法は2種類あります。(重要)
1. EC2インスタンスにRDBMSをインストールする方法
2. RDSを利用する方法RDSではデータベース用のインスタンス(仮想サーバー)が作成され、その上にOSやデータベースエンジンが構築されます。そのため、利用者はサーバやミドルウェアのメンテナンスが不要となります。
基本的にはRDSを利用した方が構築・運用のコスト削減できるため、RDBMSを運用する場合はRDSを選択されることが多いです。
まとめ
かなりざっくりですがAWSに関する知識をまとめました。
以下の記事を参考にしながら実際にAWSを触れば、詳細についての理解も深まると思います。
参照
・世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで
・【画像付きで丁寧に解説】AWS(EC2)にRailsアプリをイチから上げる方法【その1〜ネットワーク,RDS環境設定編〜】
- 投稿日:2020-08-11T14:21:48+09:00
Rails 画像投稿機能作成
概要
※自分用メモです。
carrierwave,miimagickを使って画像投稿機能を作成手順について説明します。使用イメージ
DockerfileFROM ruby:2.5 RUN apt-get update -qq && apt-get install -y \ build-essential \ libpq-dev \ node.js \ postgresql-client \ yarn \ vim \【参考】
以下の記事を参考にしました。Rails 画像アップロード機能の実装方法 メモ
https://qiita.com/STHEXA/items/05a492bd9cf4cf31ba98【Rails】CarrierwaveとMiniMagickを使って画像を投稿する方法
https://techtechmedia.com/carrierwave-minimagick-image/Gemの紹介
・Carrierwave
画像をアップロードするためのgem
・Minimagick
画像を加工してくれるgem
※MiniMagickを使うにはImageMagickというものをインストールする必要があるので注意しましょう。
ImageMagickは、画像処理ライブラリです。
・画像サイズ変更
・画像反転
・画像回転
・画像フォーマット変換
・色調整
・グラデーションといった様々な画像処理を行うことができます。
1.Dockerfile編集
参考にした記事によるとCarrierwaveの導入には「ImageMagick」がインストールされている必要があるみたいでしたので
DockerfileにImageMagickをインストールする記述を追記します。DockerfileFROM ruby:2.5 RUN apt-get update -qq && apt-get install -y \ build-essential \ libpq-dev \ node.js \ postgresql-client \ yarn \ vim \ imagemagick #←追記2.Gemfile編集
GemfileにCarrierwaveとMinimagickを追記します
gemfilegem 'carrierwave' gem 'mini_magick'3.docker-compose build 及び bundle installを実行
※dockerfileに
RUN bundle install
を記述してあればdocker-compose build
を行えば
gemもインストールすることができます。$ docker-compose build4.アップローダーの作成
carrierwaveを利用するためのアップローダーを作成します。
※carrierwaveを導入したことで以下のコマンドが使えるようになります。$ docker-compose exec web rails g uploader imageもしくは
$ docker-compose exec web bash $ rails g uploader image上記のどちらかのコマンドで作成できます。
出力結果# rails g uploader image create app/uploaders/image_uploader.rb5.画像アップロードのフォームを作成(モデル,ビュー,コントローラー)
・モデル編集
app/models/post.rbclass Post < ApplicationRecord mount_uploader :image, ImageUploader end・コントローラー編集
app/controllers/posts_controller.rbdef create @post = Post.new(post_params) end private def post_params params.require(:post).permit(:image) end・ビュー編集
app/views/posts/new.html.erb<%= form_with model: @post, local: true do |f| %> <div class="form-group"> <%= f.label :image, '画像' %> <%= f.file_field :image, accept: 'image/jpeg,image/gif,image/png' %> </div> <%end%>※ここで以下のようなエラーが出ました。
uninitialized constant Post::ImageUploaderコンテナを一旦落として再度コンテナを立ち上げ直すと解消されました。
いろいろ調べていると再起動すればうまくいく?
とのことが書かれていたので試してみたところうまくいきました。6.アップロードされたときのサイズを設定
標準でアップロードされると大きいサイズの画像がアップロードされるのでサイズを変えるように設定します。
app/uploaders/image_uploader.rbに設定していきます。
app/uploaders/image_uploader.rbclass ImageUploader < CarrierWave::Uploader::Base # Include RMagick or MiniMagick support: # include CarrierWave::RMagick # ↓コメントアウト外す。 include CarrierWave::MiniMagick # アップロードできるファイルの種類を制限 def extension_whitelist %w(jpg jpeg gif png) end # アップロードするサイズの制限 process resize_to_fit: [700, 700] # サムネイルサイズの設定 version :thumb do process resize_to_fill: [100, 100] end補足
アップロードされた画像はどこへ保存されるの?
app/uploaders/image_uploader.rbに記述されています。
app/uploaders/image_uploader.rbdef store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" endこれはuploadeの中に保存されるという意味です
publicの中にuploadeのフォルダが作成されて保存されます。
- 投稿日:2020-08-11T13:48:49+09:00
ポートフォリオ投稿型プラットフォーム Techfollioをリリースしました。
開発に至った経緯
プログラミングスクールが流行り駆け出しエンジニアは増えてきているはずなのにポートフォリオが少ないのが不思議に思いました。転職でもポートフォリオは求められることが多いですしね。それをまとめたプラットフォームを作れば見た人がモチベーションも高まるし面白そうだと思い開発に至ります。
PCサイズ
スマートフォンサイズ
開発環境
ruby 2.6.3
rails 5.0.7.2
capistrano 3.11.1
nginx 1.16.1機能紹介
Techfollioはまだ開発最中ですが現時点での機能を紹介します。(随時更新します)
ログイン機能
gem deviseを使用
ログインしていなくてもみんなのポートフォリオを見ることができます。
当たり前ですが、ログインしているユーザーのみポートフォリオ作成,編集、削除可能。メール認証にはSendgridを利用しており、登録したメールアドレスに確認メールが届きます。
Twitter連携機能
コメント機能
ポートフォリオにコメントを書くことができます。(ログインしないとコメントできません)
ポートフォリオ検索
プログラミング言語ごとポートフォリオを見やすくするために検索機能を実装しました。
SNSシェア
ポートフォリオをFacebook,Line,Twitterにシェアできます。
最後に
より多くの人に利用してもらうために今後も改善続けていきます。
ポートフォリオを投稿して繋がろう!
Techfollio
- 投稿日:2020-08-11T13:47:00+09:00
RailsのRoutesをcsvで出力
何を書いた記事か
Railsのroutes一覧をcsv形式で出力する方法
→ 新しい組織でシステムキャッチアップする際、ルーティングから辿って全体を俯瞰したい、その情報を体系的にSpreadSheetなどにまとめたい場合に利用できる
どうやるか
参考になるソース
railsのroutesの実装を参照
https://github.com/rails/rails/blob/5ccdd0bb6d1262a670645ddf3a9e334be4545dac/railties/lib/rails/tasks/routes.rake
-inspector
に全てのRoute情報を詰めて、.format()
で整形すれば良さそう
-ConsoleFormatter
の実装を真似て独自のFormatterを作れば良さそう実践
適当なブランチを切る
- 個人的な理解のために出力する情報なので、本番ソースに影響ださないよう、ローカルで適当なブランチを切る
taskを作成
$ bundle exec rails g task route_formatter csvlib/tasks/route_formatter.rakenamespace :route_formatter do desc "get route as csv format" task csv: :environment do |t| class CSVFormatter def initialize @buffer= [] end def result @buffer.join("\n") end def section_title(title) end def section(routes) routes.each do |r| @buffer << [r[:name], r[:verb], r[:path], r[:reqs]].join(",") end end def header(routes) @buffer << %w"Prefix Verb URI_Pattern Controller#Action".join(",") end def no_routes @buffer << "" end end require "action_dispatch/routing/inspector" all_routes = Rails.application.routes.routes inspector = ActionDispatch::Routing::RoutesInspector.new(all_routes) puts inspector.format(CSVFormatter.new, ENV['CONTROLLER']) end end実行
bin/rails route_formatter:csv
- MacでClipboardに入れたい場合は下記
bin/rails route_formatter:csv | pbcopy
- あとはExcelとかSpreadSheetで処理
参考リンク
- 投稿日:2020-08-11T12:34:08+09:00
【Rails5】gem gonの使い方 ~RailsからJSに変数を渡す方法~
実装した機能
開発環境
ruby > 2.6.5 rails > 5.2.4.2 gon > 6.3.2今回はシンプルに、RailsのControllerで定義した変数をJSに渡してhtmlに表示します。
Railsに標準搭載されているhoge.js.erb
形式やcoffeescript
で書いたほうがスムーズだったりしますが、うまく表示できないときの回避策としても使えるGemかなと思ったのでご紹介します。※注意
Gemの仕様上、htmlソース内に変数自体が表示されるので、セキュリティ的に隠す必要があるものには使わないほうが良いです。導入方法
まずは、Gemfileに追加
Gemfilegem 'gon'そして、インストール
Terminal$ bundle installRailsのView内にコードを記述
今回は全ページで使う想定ですが、必要なviewに記述されていればOKです。
JSを読み込むのと同じく、読み込みのタイミングによって挙動が異なるので読み込み順には注意しましょう。application.html.erb・・・ <%= include_gon %> <%= javascript_include_tag "application" %> ・・・ </body>これで準備完了です。
変数を渡す
RailsのControllerでGon用の変数を定義します。
といっても、変数の頭にgon.
をつけるだけです。Users.erbdef show @user = User.find(1) gon.username = @user.name #これをJSに渡します endJSに変数を渡してhtmlに表示します。
index.html.erb・・・ <p id="name"></p> ・・・application.js・・・ let name = gon.username $('#name').html(name); ・・・このように表示されればOKです。
index.html・・・ <p id="name">こうへい</p> ・・・html内の表示について
冒頭で「html内に変数が見えちゃう」という話をしましたが
実際にはこのように読み込まれています。
良くも悪くもわかりやすい構造になっていますね笑index.html・・・ <script> //<![CDATA[ window.gon={};gon.username="こうへい"; //]]> </script> </body> ・・・その他機能
単純に変数を渡す以外にも
- 配列、ハッシュを渡す
- 変数をすべて読み込む
などの使い方もできるようです。
むしろ、Gemの役割としてはこっちのほうが大きいのかもしれませんね。
詳しくは公式ページをご確認ください。
- 投稿日:2020-08-11T11:57:58+09:00
[Rails]コントローラでUserAgentを取得する
UserAgentとは?
UserAgentとはHTTPリクエストヘッダーに含まれるWEBの使用環境に関する情報です。
ブラウザの種類、ブラウザのバージョン、端末のOSの種類などの情報が含まれています。HTTPリクエストヘッダーとは?
HTTPリクエストヘッダーとはWEBサイトにアクセスされた時にブラウザからWEBサイト側に送られるリクエスト情報と一緒に送られる付加的な情報です。
UserAgent、Referer(リンク元URL)、Authorization(認証情報)などの情報があります。RailsにおけるUserAgentの取得方法
Railsのコントローラにはrequestオブジェクトを指すアクセサメソッドが用意されており、
それを利用することでコントローラにおいて、以下のように簡単にUserAgentを取得することができます。request.user_agentUserAgent以外にも色々と取得できるrequestオブジェクト
requestオブジェクトを利用すると以下のようにリクエスト情報を簡単に取得することができます。
request.url # リクエストで使われるURL全体 request.remote_ip # クライアントのIPアドレス request.query_string # URLのクエリ文字
- 投稿日:2020-08-11T11:41:32+09:00
【Rails6】Devise + OmniAuthでGitHub認証を実装する【初学者向けチュートリアル】
はじめに
Omniauthを勉強してRails何もわからない? 状態になりましたw Rails最初はとても分かりやすかったのですが、OmniAuthがとても難しくてかなり苦労しました。やっと理解できたので、過去の自分が見たら泣いて喜ぶくらいにまとめます!!なおこの記事ではomniauthをメインに解説するのでdeviseの説明は少なめです。
アプリを作る
0からアプリを作って説明します。
ターミナル➜ rails new report_app ➜ rails g scaffold report title:string content:text ➜ rails db:migrate
➜ rails server
で
http://localhost:3000/reports にアクセスしてレポートの保存や削除をできることを確認してみましょう。Deviseを導入する
1. Gemfileに追記して
bundle install
Gemfilegem 'devise'2. Deviseの設定
ターミナル➜ rails generate devise:installするとこんなメッセージが出ます。この手順にしたがって設定していきます。このようなメッセージは超重要なので英語だからといって逃げてはダメです。
=============================================================================== Depending on your application's configuration some manual setup may be required: 1. Ensure you have defined default url options in your environments files. Here is an example of default_url_options appropriate for a development environment in config/environments/development.rb: config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } In production, :host should be set to the actual host of your application. * Required for all applications. * 2. Ensure you have defined root_url to *something* in your config/routes.rb. For example: root to: "home#index" * Not required for API-only Applications * 3. Ensure you have flash messages in app/views/layouts/application.html.erb. For example: <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> * Not required for API-only Applications * 4. You can copy Devise views (for customization) to your app by running: rails g devise:views * Not required * ===============================================================================1. デフォルトURLの設定
どこに書いてもいいと思いますが自分は最後に書きました。(endの前です)
config/environments/development.rbconfig.action_mailer.default_url_options = { host: 'localhost', port: 3000 }2. ルートパスの指定
どこでもいいですが今回は
/reports
をルートにします。config/routes.rbRails.application.routes.draw do resources :reports root to: "reports#index" end3. フラッシュメッセージの作成
Viewを編集の時にやります。
4. Viewを作成
これをしないとビューをカスタマイズできないのでこれはやります。
ターミナル➜ rails g devise:viewsDeviseの機能が使えるUserモデルを作る
Deviseの機能が使えるUserモデルを作成します。すでにUserモデルがある時はdevise導入時、既にUserモデルがある場合の対応を参考にしてみてください。
ターミナル➜ rails g devise User ➜ rails db:migrateルーティングを確認する
ルーティングを確認しましょう。
devise_for :users
が追加されています。config/routes.rbRails.application.routes.draw do devise_for :users resources :reports root to: "reports#index" endこの
devise_for :users
によって以下のルートが追加されます。これはとても大事なので自分で適当なURLを入力してRouting Error
を発生させてじっくりと見てみてください。注目すべきはコントローラーとアクションです。(ここを理解できないとomniauthで詰みます!)
例えば一番上のパスを見てみましょう。
| GET | /users/sign_in(.:format) | devise/sessions#new
とありますがこのdevise/sessions
コントローラのnewアクションはどこにあるのでしょうか??答えはhttps://github.com/heartcombo/devise/blob/master/app/controllers/devise/sessions_controller.rb です。下の画像の一番上にある階層を確認してください。
app/controllers/devise/sessions_controller.rb
ですね!!omniauthを使う時はこのGemのコントローラーをカスタマイズしなければいけません。ここが超難しいのですが、とりあえず前に進みましょう。
Viewを編集
application.html.erb<!DOCTYPE html> <html> <head> <title>ReportApp</title> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> </head> <body> <!-- 追加 --> <nav> <% if user_signed_in? %> <%= link_to 'プロフィール変更', edit_user_registration_path %> <%= link_to 'ログアウト', destroy_user_session_path, method: :delete %> <% else %> <%= link_to 'サインアップ', new_user_registration_path %> <%= link_to 'ログイン', new_user_session_path %> <% end %> </nav> </header> <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> <!-- 追加 --> <%= yield %> </body> </html>サーバーを再起動してからhttp://localhost:3000/users/sign_up にアクセスしてユーザーを登録してログインしてみましょう。このように表示されればログイン成功です。なお
reports/index.html.erb
にもフラッシュを表示する記述があるのでフラッシュメッセージが2つ表示されています。お疲れ様でした!これでログイン機能は完成です!
GitHubの設定
ここからomniauthの設定をしてきます。まずGitHubにログインしてください。そして右上のアイコンをクリックしてSettings → Developer settingsと進んでください。
そしてOAuth Apps → New OAuth Appを押してください。
最後にアプリ名、ホームページのURL、認証コールバックURLを入力してRegister applicationを押しましょう。Client ID と Client Secretをメモしておきましょう。(無くしてもGitHubのSettings/Developer settingsで見ることができます。)
アプリ名:任意
ホームページのURL:今回はローカルなのでhttp://localhost:3000/
認証コールバックURL:http://localhost:3000/users/auth/github/callback
このURLは任意ですが、このURLにGitHubからユーザー名やメアドなどの情報が送られてきます。よって極めて重要です。このURLに対応するルーティングとコントローラーを自作する必要があります。環境変数の設定
さっきのClient ID と Client SecretはGitHubにpushするとまずい情報です。なので環境変数に保存しておいてファイルから使います。
.zshrcexport GITHUB_ID=メモしたClient ID export GITHUB_SECRET=メモしたClient SecretこれでRubyの文法で
ENV["GITHUB_ID"]
のように自分のClient IDを参照することができます。
設定を読み込むためにターミナルを再起動しておきましょう。
irb
やpry
でENV["GITHUB_ID"]
の中身を確認しておきましょう。ここが原因でハマることがあるので?Gemとカラムの追加
Gemの追加
Gemfileに
gem 'omniauth-github'
を追記してbundle install
してください。カラムの追加
Userモデルに
uid
とprovider
という名前のカラムを追加します。ターミナル→ rails g migration AddColumnsToUsers uid:string provider:string作成されたマイグレーションファイルを開いて
not null
制約とunique index
を追加しておきます。db/migrate/xxxxxxxxxx_add_columns_to_users.rbclass AddColumnsToUsers < ActiveRecord::Migration[6.0] def change add_column :users, :uid, :string, null: false add_column :users, :provider, :string, null: false, default: "" # uidとproviderの組み合わせを一意にする add_index :users, [:uid, :provider], unique: ture end endマイグレーションファイルを適応します。
ターミナルrails db:migrateもしusersテーブルにデータが入っているとエラーになります。
StandardError: An error has occurred, this and all later migrations canceled: SQLite3::ConstraintException: NOT NULL constraint failed: users.uidその時は
rails db:reset
で全てのテーブルを削除し、"db/schema.rb"を元にテーブルの再作成を行います。先ほどのマイグレートがエラーになっているので、そのあともう一回rails db:migrate
をする必要があります。ターミナル→ rails db:reset → rails db:migrateDeviseの設定
deviseの設定ファイルにさっき環境変数に設定したGithubの情報を記述します。
270行目くらいにOmniAuthの設定を書きましょう。
config/initializers/devise.rb# ==> OmniAuth # Add a new OmniAuth provider. Check the wiki for more information on setting # up on your models and hooks. # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo' config.omniauth :github, ENV["GITHUB_ID"], ENV["GITHUB_SECRET"], scope: "user:email"
scope:
には自作のアプリにGitHubの情報をどこまで与えるかを記述します。今回はGitHubからメアドと名前をもらいます。(他の情報もたくさん来ます)詳しくはAvailable scopesを見てみてください。
Userモデルを編集
Userモデルにバリデーションをつけて、Deviseのモジュールを追加します。そしてGitHubからもらったデータでユーザー登録するメソッドを作ります。最後にGitHub以外でアカウント登録した人のuidを埋めるためのメソッドを作ります。
app/models/user.rbclass User < ApplicationRecord validates :email, presence: true, uniqueness: true # uidとproviderカラムの組み合わせを一意にする validates :uid, presence: true, uniqueness: { scope: :provider } # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable, :omniauthable, omniauth_providers: [:github] # authの中身はGitHubから送られてくる大きなハッシュ。この中に名前やメアドなどが入っている。 # providerカラムとuidカラムが送られてきたデータと一致するユーザーを探す。 # もしユーザーが見つからない場合は新規作成する。 def self.find_for_github_oauth(auth) where(provider: auth.provider, uid: auth.uid).first_or_create! do |user| # 名前を取得するときはこのように書く(今回はUserモデルにname属性がないのでエラーなる) # user.name = auth.info.name user.email = auth.info.email # 任意の20文字の文字列を作成する user.password = Devise.friendly_token[0, 20] end end # 最後に使います。 def self.create_unique_string SecureRandom.uuid end endルーティングを変更する
ここから一気に難しくなります。ルーティングを確認するの理解はバッチリですか?
devise_for :users
と書くことでgemのコントローラーとアクションが設定されるんでしたね。ルーティングを次のように変更します。これは
deviser_for :users
で決まるコントローラーを一部変更しています。つまりdevise/omniauth_callbacks
コントローラーの代わりに、自作のusers/omniauth_callbacks
コントローラーを使う。devise/registrations
コントローラの代わりに、自作のusers/registrations
コントローラーを使うということです。ruoutes.rbRails.application.routes.draw do devise_for :users, controllers: { omniauth_callbacks: "users/omniauth_callbacks", } resources :reports root to: "reports#index" end変更前(右のコントローラーとアクションをみてください)
変更後(右のコントローラーとアクションをみてください)
自作のコントローラーを作る
けっこう長いですね? ですがもうちょっとです!
先ほどルーティングで設定したコントローラーを作っていきます。
app/controllers/users/omniauth_callbacks_controller.rb# Deviseのコントローラーを継承することでDeviseのコントローラーと同じメソッド(つまりアクション)が使える class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController def github # request.env["omniauth.auth"]にGitHubから送られてきたデータが入っている # binding.pryで確認してみましょう @user = User.find_for_github_oauth(request.env["omniauth.auth"]) if @user.persisted? # データベースに保存されていればログイン成功 sign_in_and_redirect @user, event: :authentication set_flash_message(:notice, :success, kind: "Github") if is_navigational_format? else # ログイン失敗 session["devise.github_data"] = request.env["omniauth.auth"] redirect_to new_user_registration_url end end end一応ログイン成功!! だが・・・
ですがまだいろいろ問題があります?
問題その1. プロフィール編集ができない
例えばプロフィール編集に現在のパスワードが必要になっています。しかし現在のパスワードはGitHubのパスワードではなくこのメソッドで作ったランダムのパスワードです。つまりGitHubでログインしたユーザーはプロフィール編集できない仕様になっています。
app/models/user.rbdef self.find_for_github_oauth(auth) where(provider: auth.provider, uid: auth.uid).first_or_create! do |user| user.email = auth.info.email user.password = Devise.friendly_token[0, 20] end end問題その2. GitHubを使わないアカウント登録ができない
db/schema.rb
を見てください。t.string "uid", null: false
とあると思います。uidカラムにはGitHubからのデータが格納されるのですが、GitHubを使わない場合このuidカラムが埋まりません。ですのでここを埋める必要があります。原因
なぜこのような問題が発生するのでしょうか? 読み進める前に自分で考えてみましょう。この記事の中(今まで読んだ部分)に答えは書いてあります。自分の頭で考えて死ぬほど苦労することが重要です!
はい。答え合わせをします。答えはGem(Devise)のコントローラーをそのまま使っているからです。コントローラーとアクションを見てみてください。
解決策
二つの問題をまとめて解決します!Gemのコントローラーのアクションを少しカスタマイズしてあげれいいです。モンキーパッチってやつですね。まず本家のユーザー登録・編集をするためのコントローラーを見てみましょう。
https://github.com/heartcombo/devise/blob/master/app/controllers/devise/registrations_controller.rb
app/controllers/devise/registrations_controller.rbclass Devise::RegistrationsController < DeviseController prepend_before_action :require_no_authentication, only: [:new, :create, :cancel] prepend_before_action :authenticate_scope!, only: [:edit, :update, :destroy] prepend_before_action :set_minimum_password_length, only: [:new, :edit] # GET /resource/sign_up def new build_resource yield resource if block_given? respond_with resource end # POST /resource def create build_resource(sign_up_params) resource.save yield resource if block_given? if resource.persisted? if resource.active_for_authentication? set_flash_message! :notice, :signed_up sign_up(resource_name, resource) respond_with resource, location: after_sign_up_path_for(resource) else set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}" expire_data_after_sign_in! respond_with resource, location: after_inactive_sign_up_path_for(resource) end else clean_up_passwords resource set_minimum_password_length respond_with resource end end def update self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key) prev_unconfirmed_email = resource.unconfirmed_email if resource.respond_to?(:unconfirmed_email) resource_updated = update_resource(resource, account_update_params) yield resource if block_given? if resource_updated set_flash_message_for_update(resource, prev_unconfirmed_email) bypass_sign_in resource, scope: resource_name if sign_in_after_change_password? respond_with resource, location: after_update_path_for(resource) else clean_up_passwords resource set_minimum_password_length respond_with resource end end def update_resource(resource, params) resource.update_with_password(params) end # Build a devise resource passing in the session. Useful to move # temporary session data to the newly created user. def build_resource(hash = {}) self.resource = resource_class.new_with_session(hash, session) endこのコントローラーを継承したコントローラーを自作します。そして2つのメソッドをオーバーライドします。
users/配下に新規コントローラーを作成してください。app/controllers/users/registrations_controller.rbclass Users::RegistrationsController < Devise::RegistrationsController def build_resource(hash = {}) # 自作したメソッドを使いuidを必ず埋める hash[:uid] = User.create_unique_string super end protected def update_resource(resource, params) return super if params["password"]&.present? # 現在のパスワードなしでアカウントの更新をする resource.update_without_password(params.except("current_password")) end end最後に今作ったコントローラーを使えるようにルーティングを変更しましょう!
routes.rbRails.application.routes.draw do devise_for :users, controllers: { omniauth_callbacks: "users/omniauth_callbacks", registrations: "users/registrations" } resources :reports root to: "reports#index" endようやくできた!!
メアドとパスワードでのログイン成功!
パスワードなしでアカウント編集成功!
おわりに
お疲れ様でした! 最初は一般的なログイン機能(ログインしていないと投稿できない、自分の投稿のみ削除や編集ができるなど)もやるつもりだったのですが、そこまでの時間を裂くことができませんでした? とはいえそれらの情報はたくさんあるので問題ないかと思います。
omniauthは自分にとってRails最強の敵でした。ユーザーフォロー、コメント機能など一般的な機能はググれば出てきたのですがomniauthはググってもほとんどヒットせず、かなり大変でした。正確にはヒットしてもコードが書いてあるだけで何をやっているのかサッパリ分かりませんでした。この記事でomniauthを理解できた人が一人でもいれば嬉しいです?
- 投稿日:2020-08-11T10:31:09+09:00
Railsアプリケーションの立ち上げ方【初学者向け】
新しいRailsアプリケーションを作成
以下のコマンドを実行して、新しいRailsアプリケーション「My App」を作成しましょう。
※もちろん名前は「My App」じゃなくてもいい。# projectsディレクトリの作成 $ mkdir ~/projects # projectsディレクトリに移動 $ cd ~/projects # Railsのバージョン5.2.3を用いて、「my_app」を「-d」オプションでMySQLを指定して作成。 $ rails _5.2.3_ new my_app -d mysql # 「my_app」ディレクトリに移動 $ cd my_app # 現在のディレクトリのパスを表示 $ pwd上記の操作を行って、/Users/ユーザー名/projects/my_appと表示されれば一旦は成功です。
最後にエラーが出る場合
もし、アプリケーション作成段階でエラーが生じた場合は、以下のような赤字の文章が表示されます(必ずしも同じ文面ではありません)。
【例】Installing mysql2 0.5.3 with native extensions Gem::Ext::BuildError: ERROR: Failed to build gem native extension. current directory: /Users/user_name/Programs/web/foobar-repo/vendor/bundle/ruby/2.5.1/gems/mysql2-0.5.3/ext/mysql2 /Users/user_name/.rbenv/versions/2.5.1/bin/ruby -r (中略) An error occurred while installing mysql2 (0.5.3), and Bundler cannot continue. Make sure that `gem install mysql2 -v '0.5.3'` succeeds before bundling.エラーが表示されている場合は、以下のコマンドを実行してください。
$ bundle config --delete build.mysql2 $ bundle config --global build.mysql2 --with-opt-dir="$(brew --prefix openssl)" $ cd ~/projects/my_app $ bundle install正しく関連ファイルが読み込まれているか確認
以下のコマンドを実行して、関連ファイルが読み込まれているか確認しましょう。
# Users/ユーザー名/projects/my_appと表示されることを確認する $ pwd # 関連ファイルが読み込まれていることを確認する $ bundle installデータベースを作成しましょう
# データベースを作成 $ rails db:create # 以下のような表示がされれば成功 Created database 'my_app_development' Created database 'my_app_test'サーバーを立ち上げて確認しましょう
正しくアプリケーションが作成できたか、サーバーを立ち上げて確認しましょう。使用するコマンドは、rails sコマンドです。以下の通りに実行しましょう。
# サーバーの起動 $ rails shttp://localhost:3000 にアクセスして、Railsのデフォルト画面が表示されれば成功です。
サーバーを終了させる際はcontrol+cテキストエディタ(VS Code)を開いて、comand+oで作成したファイルを開いてコードを書きはじめましょう!!
- 投稿日:2020-08-11T05:10:48+09:00
bundle install でmysql2がインストールされない
はじめに
僕のローカル環境で毎回エラーになるので解決策をメモします
*まだ厳密な原因はわかってませんが、とりあえずこれで通りました程度の内容です$ bundle install --path vendor/bundle ... エラー文↓ An error occurred while installing mysql2 (0.5.3), and Bundler cannot continue.解決方法
$ bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl/lib" $ bundle install --path vendor/bundle上記コマンドを実行すると、
.bundle/config
に下記一行が追加されますBUNDLE_BUILD__MYSQL2: "--with-ldflags=-L/usr/local/opt/openssl/lib"とおるようになる。
- 投稿日:2020-08-11T02:42:54+09:00
Rails Tutorialを咀嚼する【第1章ゼロからデプロイまで】
1.1 はじめに
■REST
SQLでよく使う「Create/Read/Update/Delete」をそれぞれ「GET/POST/PUT/DELETE」に当てはめたもの。セッションなどの状態管理を行わないため、命令をいちいち書いていく必要がある。
基本的には「route.rb」に記載する。■コマンドライン
ターミナル。クラウドIDEに標準的に備わっている。1.2 さっそく動かす
■Cloud9
AWSが提供しているクラウド上で開発可能な統合開発環境。面倒な環境設定もいらないため超便利■gem
パッチファイル?追加要素?みたいなもの。「Gemfile」というファイルに記載して、bundle installとターミナルに打ち込むと自動でインストールしてくれる。1.3 最初のアプリケーション
■rails new
Railsを使ってアプリケーションを作る際に初めに書く呪文。必要なファイルを自動で生成してくれる。■フレームワーク
Railsがフレームワーク。エディタがあれば自由にプログラミングできるが、将来的にめちゃくちゃな書き方になってしまうため、「ある程度書き方を揃えましょうね」というもの。
Rubyで書くと何十行も掛かる処理をRailsを使えば独自の短い表現で同じ処理ができる。まだ実感値はない。■gameごとのバージョン
バージョンが違うと挙動も違う可能性があるので、バージョンを固定させて開発をした方が良い。
spring 2.0.2がインストールできないときは「bundle update spring」を打ってから再度インストール。【演習】
railsサーバーを立ち上げれた先に書いてある。■MVCモデル
どこにどのファイルを置くのかを定義した概念。本来どこに何を置いてもいいが、後々管理が面倒になるため、ある程度統一性をもって書こうというもの。
どこに何を書くべきかという実感値はまだない。■renderメソッド
レスポンスの出力をするメソッド。コントローラーでもビューでも使う。■メソッド
関数。defとendの間に挟んで使う。
呼び出すときは定義したメソッド名を書く。■routes.rb
どのリクエストにはどのページを返すか、を記載する。
基本的にはコントローラーを記載するのかな?■1.3.4 Hello, world!に書き換える
最初の「Yay!You're on Rails!」をHello, world!に書き換える。
今回は大した内容じゃないので恐らくビューはいじらない。
「hello, world!」というHTMLを表示する、というrenderメソッドをコンロトーラーで定義して、
rootをhelloメソッドにする。【演習】
1.文面を変えればOK
2.Windowsだから表示の仕方が分からないため跳ばす。
3.
def goodbye
render html: "goodbye, world!"end
Rails.application.routes.draw do
root 'application#goodbye'
endこんな感じ。
- 投稿日:2020-08-11T02:42:54+09:00
Rails Tutorialを咀嚼する【第1章ゼロからデプロイまで】前半
1.1 はじめに
■REST
SQLでよく使う「Create/Read/Update/Delete」をそれぞれ「GET/POST/PUT/DELETE」に当てはめたもの。セッションなどの状態管理を行わないため、命令をいちいち書いていく必要がある。
基本的には「route.rb」に記載する。■コマンドライン
ターミナル。クラウドIDEに標準的に備わっている。1.2 さっそく動かす
■Cloud9
AWSが提供しているクラウド上で開発可能な統合開発環境。面倒な環境設定もいらないため超便利■gem
パッチファイル?追加要素?みたいなもの。「Gemfile」というファイルに記載して、bundle installとターミナルに打ち込むと自動でインストールしてくれる。1.3 最初のアプリケーション
■rails new
Railsを使ってアプリケーションを作る際に初めに書く呪文。必要なファイルを自動で生成してくれる。■フレームワーク
Railsがフレームワーク。エディタがあれば自由にプログラミングできるが、将来的にめちゃくちゃな書き方になってしまうため、「ある程度書き方を揃えましょうね」というもの。
Rubyで書くと何十行も掛かる処理をRailsを使えば独自の短い表現で同じ処理ができる。まだ実感値はない。■gameごとのバージョン
バージョンが違うと挙動も違う可能性があるので、バージョンを固定させて開発をした方が良い。
spring 2.0.2がインストールできないときは「bundle update spring」を打ってから再度インストール。【演習】
railsサーバーを立ち上げれた先に書いてある。■MVCモデル
どこにどのファイルを置くのかを定義した概念。本来どこに何を置いてもいいが、後々管理が面倒になるため、ある程度統一性をもって書こうというもの。
どこに何を書くべきかという実感値はまだない。■renderメソッド
レスポンスの出力をするメソッド。コントローラーでもビューでも使う。■メソッド
関数。defとendの間に挟んで使う。
呼び出すときは定義したメソッド名を書く。■routes.rb
どのリクエストにはどのページを返すか、を記載する。
基本的にはコントローラーを記載するのかな?■1.3.4 Hello, world!に書き換える
最初の「Yay!You're on Rails!」をHello, world!に書き換える。
今回は大した内容じゃないので恐らくビューはいじらない。
「hello, world!」というHTMLを表示する、というrenderメソッドをコンロトーラーで定義して、
rootをhelloメソッドにする。【演習】
1.文面を変えればOK
2.Windowsだから表示の仕方が分からないため跳ばす。
3.app/controllers/application_controller.rbdef goodbye render html: "goodbye, world!" endconfig/routes.rbRails.application.routes.draw do root 'application#goodbye' endこんな感じ。
- 投稿日:2020-08-11T02:26:49+09:00
[devise カスタマイズ]ユーザー登録完了前に(仮登録の状態で)他のカラムを追加させる
[devise]ユーザー登録完了前に(仮登録の状態で)他のカラムを追加させる
はじめに
ruby on railsのユーザー周り(会員登録など)のgemといえばdeviseですかね・・?
一瞬で会員登録とかができるのは物凄い便利です。そんな便利な反面、カスタマイズするのにはかなり時間がかかります。
(今回もかなり時間がかかりました。)今回実装するのは、以下のような機能です。
# 実装したい内容 会員登録(emailとpassword) ↓ 認証メール送信 ↓ メールのリンクからプロフィール(今回はname)を追加するページへ ↓ プロフィールを入力して確認画面へ ↓ 確認画面で送信 ↓ 会員登録完了(ログイン画面へ)今回のissueは大きく二つ
- 会員登録を仮登録の状態で編集する
- 変更時に編集内容を確認するページを挟む
開発環境
- rails (6.0.3.2) - ruby 2.6.5p114 - devise (4.7.2) - letter_opener (1.7.0) - mac Catalina 10.15.6セットアップ
前提として、以下の状態を想定しています
- deviseがインストールされている
- deviseのview,controller,modelが作成されている
- Useモデルが存在する(カラムはデフォルトにnameを追加)
- letter openerをgemにインストールしている(初期設定している)
- メール認証をtrueに変更している
使い方
今回のissueは大きく二つ
- 会員登録を仮登録の状態で編集する => (解決策) confirmation_tokenを保持して、最後にconfirmation_pathに引数として与える
- 変更時に編集内容を確認するページを挟む => (解決策)hidden_fieldを入れることでデータを保持する
1つ目のissueの肝は、[confirmation_token]
仮登録完了時に送られるメールをみるとわかりやすい/app/views/devise/mailer/confirmation_instructions.html.erb<p>Welcome <%= @email %>!</p> <p>You can confirm your account email through the link below:</p> <p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></p>なんか、認証トークンとuserのデータを引数に持ってconfirmation_urlに入ったら仮登録→本登録完了になるらしい
つまり、
これをやらずにプロフィールを編集して、その後認証トークンを与えてconfirmation_tokenにアクセスして完了すればいい。
それでは実際にやってみる
① ルーティングを設定
まず、追加するアクションは三つ。そのルーティングを行う。
今回はこの三つ。カッコの中身がアクション名(センスなくてすみません・・・)
[入力、確認、更新]
- 入力:プロフィール入力アクション(before_create)
- 確認:入力内容確認アクション(before_confirm)
- 更新:入力内容で更新するアクション(before_update)config/routes.rbRails.application.routes.draw do devise_for :users, :controllers => { # コントローラーを見に行くようになる # 無しだと、そもそも見に行かずにデフォルトが実行される # (結論:deviseのコントローラーを変更したら記述が必須) :registrations => 'users/registrations', :sessions => 'users/sessions', :confirmations => 'users/confirmations' } devise_scope :user do # ルーティングを指定 # アクションが追加されたらそのルーティングを指定する get "sign_in", :to => "users/sessions#new" get "sign_out", :to => "users/sessions#destroy" #プロフィール編集画面(仮登録状態) get "before_sign_up", :to => "users/registrations#before_create" #プロフィール編集内容確認画面(仮登録状態) post "before_sign_up_confirm", :to => "users/registrations#before_confirm" #プロフィール編集内容のアップデート処理(仮登録→本登録に) post "before_sign_up", :to => "users/registrations#before_update" end # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html root 'pages#index' get 'pages/show' end大きくやったことは二つ
- device_forでdeviseのcotrollerをカスタマイズ可能に
- devise_scoopeで新しいアクションのパスを指定
② プロフィール編集アクションを追加(入力、確認、更新の三つ)
続いて、アクションの追加
この三つ。カッコの中身がアクション名
- 入力:プロフィール入力アクション(before_create)
- 確認:入力内容確認アクション(before_confirm)
- 更新:入力内容で更新するアクション(before_update)とりあえず、binding.pryで引数を見て回ったのと、superが表す内容をそれぞれ見て回った(こんなサイトで)
まずは入力:プロフィール入力アクション(before_create)
registrations_controller.rb# 仮登録状態のプロフィール入力画面(メール認証後のアクション) def before_create # 引数のresourceを使ってユーザーを取得 @user = User.find(params["resource"]) @token = params["confirmation_token"] endbefore_create.html.erb<h2>プロフィールを登録</h2> <%= form_for(resource, as: resource_name, url: before_sign_up_confirm_path(resource_name, confirmation_token: @token) ,html: {method: "post"}) do |f| %> <%= render "devise/shared/error_messages", resource: resource %> <%= f.hidden_field :user_id, :value => resource.id %> <div class="field"> <%= f.label :name %><br /> <%= f.text_field :name, autofocus: true, autocomplete: "name" %> </div> <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autofocus: true, autocomplete: "email",:readonly => true %> </div> <div class="actions"> <%= f.submit "Sign up" %> </div> <% end %> <%= render "devise/shared/links" %>デフォルトだったらparamsとかじゃなくてresourceで一発で呼べるんですけど、新しく追加したメソッドでresourceではとれない
余談
(厳密には、以下のような感じで取れるようにできるんですが、ログイン必須なので、仮登録では面倒そうだったので断念)
registrations_controller.rbに
prepend_before_action :authenticate_scope! , only: [:before_create]を追加(余談の出来事)ということもあり、地道に実装することに。
1- 実は仮登録で、newされてるらしいので、newせずに@userにとってくる
2- confirmation_tokenは持ち続けたいので一旦@tokenへ
3- viewのhidden_fieldでuserのidを保持(これしなくても、paramsから取れる)確認:入力内容確認アクション(before_confirm)
registrations_controller.rb# 仮登録状態のプロフィール入力完了画面(プロフィール入力後のアクション) def before_confirm @user = User.find(params["user"]["user_id"]) @user.name = params["user"]["name"] @token = params["confirmation_token"] if @user.valid? render :action => 'before_confirm' flash.now[:success] = '確認して完了してください' else render :action => 'before_create' flash.now[:alert] = '失敗しました' end endbefore_confirm.html.erb<h2>確認画面</h2> <%= form_for(@user, url: before_sign_up_path(@user, confirmation_token: @token),html: {method: "post"}) do |f| %> <%= render "devise/shared/error_messages", resource: @user %> <%= f.hidden_field :user_id, :value => @user.id %> <%= f.hidden_field :email, :value => @user.email %> <%= f.hidden_field :name, :value => @user.name %> <div class="field"> <%= f.label :name %><br /> <%= f.text_field :name, autofocus: true, autocomplete: "name",:readonly => true %> </div> <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autofocus: true, autocomplete: "email",:readonly => true %> </div> <div class="actions"> <%= f.submit "Sign up" %> </div> <% end %> <%= render "devise/shared/links" %>ここでsaveしないんですね。
@userに入れてみて、validかinvalidかを調べてるだけです。次のupdateで再び呼び出してからsaveします(ここがかなり効率悪いですよね・・・)更新:入力内容で更新するアクション(before_update)
registrations_controller.rb# 仮登録状態のプロフィール入力内容更新処理 def before_update @user = User.find(params["user"]["user_id"]) @token = params["confirmation_token"] @user.save if @user.valid? # ここが肝! # confirmation_pathにuserデータと認証トークンを付与することで本会員登録される redirect_to confirmation_path(@user, confirmation_token: @token) flash[:success] = '確認して完了してください' else render :action => 'before_create' flash.now[:alert] = '失敗しました' end end③ mailのパスを変更
最後に、
送られてくるメールの遷移先をを変更します。
confirmation_url → before_sign_up_url
resourceもparamsで呼び出せるように追加@resource → resource:@resource
(この辺深く理解してないのでミス多いかもです。すみません。)app/views/devise/mailer/confirmation_instructions.html.erb<p>Welcome <%= @email %>!</p> <p>You can confirm your account email through the link below:</p> <p><%= link_to 'Confirm my account', before_sign_up_url(resource:@resource, confirmation_token: @token) %></p>デモ
終わりに
gemってデフォルトで使う分にはすごい便利だけど、カスタマイズするにはgem自体をすごい理解しないといけないですよね。
特に初学者にはキツすぎる・・・勉強不足で間違いなどあるかもしれませんが、その時は優しく指摘していただきたいです。
よろしくお願いします!参考サイト
- 投稿日:2020-08-11T02:14:25+09:00
dockerの起動中に起きたエラー
railsアプリを立ち上げるためにdocker-compose buildを実行しようとすると次のエラーが出た。
$ docker-compose build Building db Step 1/4 : FROM mysql:8.0.17 ---> b8fd9553f1f0 Step 2/4 : RUN apt-get update && apt-get install -y apt-utils : : Fetching spring 2.0.2 Installing spring 2.0.2 Gem::Ext::BuildError: ERROR: Failed to build gem native extension. current directory: /usr/local/bundle/gems/nokogiri-1.10.9/ext/nokogiri /usr/local/bin/ruby -r ./siteconf20200529-6-18ba5hy.rb extconf.rb Cannot allocate memory - /usr/local/bin/ruby -r ./siteconf20200529-6-18ba5hy.rb extconf.rb 2>&1 : : An error occurred while installing nokogiri (1.10.9), and Bundler cannot continue. Make sure that `gem install nokogiri -v '1.10.9' --source 'https://rubygems.org/'` succeeds before bundling. :nokogiri?
gemファイルに記述した覚えは無いが、、エラー分にあるとおりnokogiriのインストールを試みたが、同様のエラーがでた。
$ gem install nokogiri -v '1.10.9'
調べると次の記事にあるように、容量不足によるエラーの可能性があるかもしれない。
https://qiita.com/HrsUed/items/c156ed69e927b6165717
記事通り容量を増加させたが、違うエラーが発生した。$ docker-compose up -d : ERROR: Service 'web' failed to build: failed to register layer: Error processing tar file(exit status 1): write /usr/lib/x86_64-linux-gnu/libx265.so.165: no space left on deviceエラーメッセージで調べると以下の記事が参考なった。
https://scrapbox.io/tsuchinaga/Docker%E3%81%A7%E5%AE%B9%E9%87%8F%E4%B8%8D%E8%B6%B3%E3%81%8C%E7%99%BA%E7%94%9F%E3%81%99%E3%82%8B
$ docker volume rm $(docker volume ls -qf dangling=true)
説明通りコマンドを実行するとbuildが成功した。
- 投稿日:2020-08-11T01:03:18+09:00
未経験エンジニアはこんなポートフォリオを作ってみてはどうか②〜PDF出力編〜
今回は前回同様に未経験エンジニアがポートフォリオを作るにあたってこんな機能を取り入れたらどうかなって思うものを一つ紹介したいと思います。
僕が実務を経験した中で
「あ、この技術は未経験のうちに習得できそうだな」
と思ったものを提案していくので、難易度的にもそんなに難しくはないはずです。
Youtubeに同じ内容の動画を掲載しているので興味がある人は観てください
未経験エンジニアはこんなポートフォリオを作ってみてはどうか②〜PDF出力編〜。
あと、
【実体験をもとに】30歳未経験から独学4ヶ月でバックエンドエンジニアとしてWeb系自社開発企業へ転職するまでのロードマップ
という記事も書いてますので是非では今回の内容はこんな感じ。
・機能紹介〜PDF出力〜
・意外とポートフォリオに取り入れている人は少ない
・なぜ取り入れておいた方が良いか
・導入するためには
・まとめ◾️機能紹介〜PDF出力〜
今回はPDF出力ですね
これは何をするのかパッと聞いて分かるとは思うのですが、目的としてはシステムの持つデータをきれいにまとめてPDFファイルとして出力するという事です。
だいたい皆さん「PDFファイルで出力」って動作はしたことあると思います。
(めちゃくちゃメジャーな機能ですからね。)◾️意外とポートフォリオに取り入れている人は少ない
僕の感覚ではあリますが、機能自体のメジャーさのわりに意外とポートフォリオに取り入れている人が少ない気がします。
何でそうなるのかっていうと、僕が見てきた限りですが多くの方が作成するポートフォリオって対個人を想定したアプリだからですね。
感覚的に7〜8割のポートフォリオが
「インスタグタムのようにユーザーが写真をつけて何かを投稿するとか個人が何かしら情報発信をする系」
って感じでした。※投稿する何かっていうのはアプリの趣旨に依存しますが、例えば景色・動物・食べ物・趣味とかですね。
こういったアプリにおいてはあんまりPDF出力って必要にならないことが多いのでこの機能を追加していない人が多いと思います。
◾️なぜ取り入れておいた方が良いか
世の中には対企業を想定したアプリを開発する企業がたくさんあるわけです。例えば経費の申請アプリとかタスクの管理アプリもそうですね。
特にベンチャー企業とかはこういったアプリを積極的に使う傾向がありますし、僕の勤務先も使っています。対企業を想定したアプリになってくると、こういったデータの吐き出し機能はほぼ必須級かなと個人的には思いますし絶対にあって損はない機能って感じです。
だいたいどこの会社でも「見積書」とか「報告用の資料」とかでシステム内のデータを使う事は多いですからね。
今後対企業向けアプリを開発する企業の選考を受ける可能性もあるので、そういったアプリでよく使用されるPDF出力機能はとりあえずポートフォリオに入れておこうって事です。
例えば自分が作ったポートフォリオがインスタグラムみたいなものなら、投稿された日にちとか付けられたタグとかでデータを集計してPDFで出力する機能をつけると良いのではないかな〜って思います。
「6/20(土) 投稿数100」
「未経験タグ:投稿数 20、エンジニアタグ:投稿数10」とかですね。
先の話ですが、JsやjQueryを使ってグラフ化できれば完璧です。いきなり企業向けを想定したポートフォリオを作るのもなかなかハードルが高いものだと思うので個人向けアプリに導入するくらいでいいと思います。
そんなポートフォリオを携えて面接の時に
「自分のポートフォリオにはあまり必要ない機能かとは思いましたが、エンジニアとして仕事をしていく上でPDF出力機能はいつか必ず必要になるかと思ったので学習目的で取り入れました」
なんて言えれば
「お、こいつはちゃんと先のことも考えてる」
って思ってもらえますし、あまりないとは思いますが仮に選考を受けた企業の開発ツールがまだブラッシュアップされていなくてPDF出力機能が必要なデータに対して完備されていなければ
「御社のツールのOOのデータを管理しやすくするため、僕が入社したらPDF機能つけます」
みたいなことを言えれば、それが必要と判断されるかどうかはともかく未経験エンジニアの口から出てくる内容として上等なんじゃないでしょうか。
◾️導入するためには
詳しい解説は行わないのですが、Ruby on Railsを使っている方であればwicked_pdfというgemを使用すればそこそこ簡単に導入できると思います。
このgemはインストール・初期設定・フォーマット用のHTMLを作成・controllerに4行くらい記述するくらいでとりあえず実装できます。
参考資料もたくさんあるので使い方はググればすぐ見つかるのも良いですね。PDFを作成するだけではあんまり意味がないので、ダウンロードもできるよう設定するのも忘れないようにしましょう。
やり方はめちゃくちゃ簡単なので、Railsを使用されてる方なら「wicked_pdf send_data」とかで調べればすぐ見つかると思います。前に紹介したwheneverよりは難易度が上がりますが、未経験の方でも十分実装できると思うのでぜひ調べてみてください。
◾️まとめ
今回はポートフォリオに追加する機能としてPDF出力機能を紹介しました。
紹介したのはPDFでしたが、CSVで出力する機能を実装しても全然構わないと思います。
ただCSVの方がちょっと難易度が高いです。未経験エンジニアのポートフォリオというのは選考で使われるものだと思いますので、追加する機能に関してはより相手にヒットしやすいものをチョイスした方がいいと思います。
いかに自分が興味を持って取り入れたものでも相手から
「へーそうなんだよくわかんないけどがんばったね乙」
と思われるのはもったいないですよね。なので「今後自分がどんな会社の選考を受けることになってゆくのか」を考えて、その会社で使っていると思われる機能を自分のポートフォリオに盛り込むのが一番手っ取り早いんじゃないかっていうのが僕の見解です。
今後もそういった観点で僕なりにお勧めの機能を紹介していきたいと思います。
はい、ということで今回は以上です。