なぜRailsにリプレイスしようと思ったのか?
僕が通っていたプログラミングスクール「CODE BASE」ではRubyのマイクロフレームワークである「Sinatra」を使って、簡単なwebアプリを制作します。
今後、Railsを使った企業にwebエンジニア転職を目指すに当たり、「勉強したRails技術で何か作ってみたい」と思い、Sinatraで作ったwebアプリをRailsでリプレイスすることにしました。
※「リプレイス」 = 英語:replace
置き換えることを意味する英語。既存のものに取って代わること、交換すること、置換、後任といった意味でも用いられる。
引用:https://www.weblio.jp/content/%E3%83%AA%E3%83%97%E3%83%AC%E3%82%A4%E3%82%B9
リプレイスに挑戦する時点での僕のスキル
- ProgateのRailsコースは1週済み
- Railsチュートリアル9章まで終わらせている
- 人生逆転サロンというプログラミングのオンラインサロンの学習教材でRailsを使ったCRUDアプリが作れる
Sinatra => Rails へのリプレイスで詰まったところ
deviseのpath記述が分からない
RailsはdeviseというGemを使えば、ログイン機能を簡単に実装することができます。
が、しかし!! deviseで自動生成されるルーティングが分からず、詰みそうになりました。
具体的に分からなかったところ
deviseでusersテーブルを作成し、GETのHTTPリクエストで「ユーザー編集画面」に飛ぶパス記述が分からない状態でした。
URL指定でアクセスするなら「 /posts/:id(.:format)」に該当するルーティングですね。
解決方法
ターミナルでrails routes
を叩けば即解決。
Prefix Verb URI Pattern Controller#Action
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
user_password PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
POST /users/password(.:format) devise/passwords#create
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
user_registration PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
POST /users(.:format) devise/registrations#create
root GET / posts#index
posts GET /posts(.:format) posts#index
POST /posts(.:format) posts#create
new_post GET /posts/new(.:format) posts#new
edit_post GET /posts/:id/edit(.:format) posts#edit
post GET /posts/:id(.:format) posts#show
PATCH /posts/:id(.:format) posts#update
PUT /posts/:id(.:format) posts#update
DELETE /posts/:id(.:format) posts#destroy
comments GET /comments(.:format) comments#index
POST /comments(.:format) comments#create
new_comment GET /comments/new(.:format) comments#new
edit_comment GET /comments/:id/edit(.:format) comments#edit
comment GET /comments/:id(.:format) comments#show
PATCH /comments/:id(.:format) comments#update
PUT /comments/:id(.:format) comments#update
DELETE /comments/:id(.:format) comments#destroy
GET /likes/:id(.:format) likes#touch
follow_action GET /follow/action(.:format) follows#touch
users GET /users(.:format) users#index
user GET /users/:id(.:format) users#show
rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show
rails_blob_representation GET /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show
rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show
update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update
rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create
Railsはrails routes
を叩くことで定義されているルーティング情報を一発で全件表示することができます。
今回、僕が見つけられなかった/users/edit(.:format)
もこれで即調べることが可能です。
edit_user_registration
←の末尾に「_path」を付けるだけ。
<%= link_to "プロフィールを編集する", edit_user_registration_path %>
↑こういう書き方をすれば、プロフィール編集ページへのリンクが簡単に作れるわけですね。
RailsからDBへのテーブル接続がうまくいかない
carrierwave
という画像アップロードのGemを導入したが画像投稿時に「画像のパス」ではなく「クラス名」が登録されてしまう事態が発生。
class CommentsController < ApplicationController
# 新しいコメントオブジェクト作成
def new
@comment = Comment.new
# binding.pry
end
# 新しいコメントをテーブルに保存
def create
binding.pry
Comment.create(
score: comment_params[:score],
comment_text: comment_params[:comment_text],
comment_image: comment_params[:comment_image],
post_id: params[:id],
user_id: current_user.id)
redirect_to root_path
end
private
def comment_params
params.require(:comment).permit(:score, :comment_text, :comment_image)
end
end
<div class="text-center mt-5 mb-5">
<h2>口コミ投稿する</h2>
</div>
<%= form_for @comment, method: :post do |f| %>
<!-- 評価 -->
<div class="form-group row">
<label class="col-md-3 col-form-label" for="score">評価</label>
<div class="col-md-9">
<%= select :comment, :score, [["5", "5"], ["4", "4"], ["3", "3"], ["2", "2"], ["1", "1"]] %>
</div>
</div>
<!-- 口コミ内容 -->
<div class="form-group row">
<label class="col-md-3 col-form-label" for="comment_text">口コミ内容</label>
<div class="col-md-9">
<%= text_area :comment, :comment_text, :size=>"40x5" %>
</div>
</div>
<!-- 口コミ画像 -->
<div class="form-group row">
<label class="col-md-3 col-form-label" for="comment_image">口コミ画像</label>
<div class="col-md-9">
<%= f.file_field :comment_image %>
</div>
</div>
<input type="submit" value="内容を送信">
<% end %>
[3] pry(#<CommentsController>)> params[:comment][:comment_image]
=> #<ActionDispatch::Http::UploadedFile:0x00007f9062250e78
@content_type="image/jpeg",
@headers="Content-Disposition: form-data; name=\"comment[comment_image]\"; filename=\"1-2.jpg\"\r\nContent-Type: image/jpeg\r\n",
@original_filename="1-2.jpg",
@tempfile=#<File:/var/folders/y8/0wn59wsd67d090zgbpv_8r6w0000gn/T/RackMultipart20190717-48041-rjs60c.jpg>>
下記の画像のように commentsテーブルの comment_image
カラムに対して
#<ActionDispatch::Http::UploadedFile:0x00007f9062250e78
のようなクラス名が
登録されてしまう状態でした。
同じcarrierwave
のGemを使っているpostsテーブルは。product_image
というカラムにファイル名が正しく書き込めている状態。
原因
app/models/comment.rb
ファイル内のタイポ(タイピングミス)
対策
エディタ側でタイポを防ぐ。RubyMineならタイポ部分をハイライトしてくれる。
ActiveRecordを使って、2つのテーブルを結合し、特定の条件でレコードを取得したい
下記画像のように
following_user_id「3」を持つ人がフォローしている➔followed_user_id「1」「4」「6」のユーザー情報をusersテーブルから取得したい、という場合、
app/controllers/users_controller.rb
に必要な記述が分からず、詰まっていました。
解決方法
テーブルを結合するのではなく、下記のようにSQLを2回発行する方法で欲しいレコードを取得しました。
# フォローしてる人、フォロワー情報、お気に入りしている投稿情報を取得
followed_user_ids = Follow.where(following_user_id: params[:id]).pluck(:followed_user_id)
@follow_list = User.find(followed_user_ids)
まず最初にfollowed_user_ids = Follow.where(following_user_id: params[:id]).pluck(:followed_user_id)
で[4, 6, 1]のユーザー情報を取得。
[1] pry(#<UsersController>)> followed_user_ids
=> [4, 6, 1]
後はfindメソッドを使い、usersテーブルの主キーであるIDを[4, 6, 1]
で検索し欲しいレコードを@follow_list
のインスタンス変数に代入するだけ。
@follow_list = User.find(followed_user_ids)
このインスタンス変数をerbに渡せば、フォローしている人、フォロワー情報などを簡単に出力することができる。
find と where 使い方の理解不足で1時間半、沼にハマる
沼にハマった内容
フォローしている人のuser_id
をfollows
テーブルから取得するところまでは良かったのですが・・・
# タイムライン(フォローしている人の投稿一覧)を取得
timeline_post_ids = Follow.where(following_user_id: params[:id]).pluck(:followed_user_id)
@post_list = Post.find(user_id: timeline_post_ids )
上記のように@post_list = Post.find(user_id: timeline_post_ids )
で
主キーで検索する findメソッドを使ってしまい。postsテーブルからレコードが取れない・・・と悩みました・
本来なら下記のように書くのが正しい記述です。
# タイムライン(フォローしている人の投稿一覧)を取得
timeline_post_ids = Follow.where(following_user_id: params[:id]).pluck(:followed_user_id)
@post_list = Post.where(user_id: timeline_post_ids )
対策
ActiveRecordのメソッドをしっかりと理解する。
また、Rails・Rubyで使うメソッドの理解を深めること!
find
idなどの主キーが一致するレコードを取得します。
user = User.find(1)
where
条件が一致するすべてのレコードを取得します。
名前がsuzukiのユーザーを検索する
User.where(name: 'suzuki')
その他、分からない部分などを参考にした記事
updated_atを日本時間で表示する
口コミや、タイムライン部分を日本語曜日入り日付フォーマットを1行で書く
女装アイテム(商品)が削除された際、紐付ている「お気に入り」「口コミ」も同時に削除する
口コミ内で「改行」が起きた場合、
タグへ変換させてブラウザ上でも改行してる状態で見えるようにする
https://qiita.com/defunty/items/8c64a2939bcd31a62ffb
https://qiita.com/t_oginogin/items/0164ad76b753fdff9902
口コミに写真が投稿されていない場合の判定(nil?, empty?, blank?)の使い分け
<% unless comment.comment_image.blank? %>
link_toメソッドの使い方
RailsのDeviseで新たに追加したカラムをStrong Parametersに追加してSignup/Updateする方法
formのバリデーション
【Rails】Flashメッセージの使い方とメッセージの拡張・応用
お気に入り数のカウントをする際のActiveRecord参考
devise日本語化
gem 'bootstrap-sass', '3.3.7' をGemfileに記述すると下記のエラーがでる「rails s」でアプリは起動できる
/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/bootstrap-sass-3.3.7/lib/bootstrap-sass/version.rb:2: warning: already initialized constant Bootstrap::VERSION
/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/bootstrap-4.1.3/lib/bootstrap/version.rb:2: warning: previous definition of VERSION was here
/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/bootstrap-sass-3.3.7/lib/bootstrap-sass/version.rb:3: warning: already initialized constant Bootstrap::BOOTSTRAP_SHA
/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/bootstrap-4.1.3/lib/bootstrap/version.rb:3: warning: previous definition of BOOTSTRAP_SHA was here
https://qiita.com/SonoT/items/a45ca6e91e32191f5449
↑で解決
リプレイスを通して得られたこと
Railsチュートリアルや、オンラインサロンの学習教材でも、簡単にwebアプリは一通り作っていましたが、やはりオリジナルのアプリをRailsで作成する。となると難易度は結構上がります、
今回、僕が制作した「女装アイテムの口コミ投稿アプリ」は
- usersテーブル
- postsテーブル
- commentsテーブル
- likesテーブル
- followsテーブル
合計「5つ」のテーブル数でしたが、Sinatra => Railsへリプレイスするだけでも「30時間」かかりました。
1週間詰め込みだったので、結構たいへんでしたが「初めて自分でオリジナルのRailsアプリを完成させた」という達成感は半端ないです!
作っていく中で、色んな人に質問してアドバイスを頂けたのも完成まで挫折しなかった、大きな理由かと思います。
最後に、完成した「女装アイテムの口コミ投稿アプリ」のGit-hubのリポジトリを共有↓
https://github.com/yuikotonoha/sinatra_replace_app
今後はSinatraでは実装できなかった機能をGemで増やしたり、テーブルなどを増やして新機能を拡張していったりして
webエンジニアの転職活動に持っていけるポートフォリオにレベルアップさせていきます!!
ではでは!この辺で失礼いたします。