はじめに
こんにちは。アメリカで独学でエンジニアを目指している者です。
現在、Ruby on Rails Tutorialを使ってRailsを勉強しており、学んだことを忘れないように振り返りの記事を書いてみました。
開発環境
OS: Window11
Gemfile: Ruby on Rails Tutorialに書いてあるバージョンを使用
その他 : Doceker + vscodeを用いて開発
ユーザー登録
前回はユーザーの名前やメールアドレスについてのバリデーションを学習しました。今回はそれらを活用してサインアップページを作成し、テストを行うところまでがメインの内容です。
ユーザーを表示する
まずは、Webサイトのレイアウトにデバッグ情報を表示させました。Railsは裏側で動いている処理が多く見えづらいので、デバッグ情報を明示的に表示し、理解を深めるのが狙いだと思われます。以下のように、app/views/layouts/application.html.erb
にデバッグ用のコードを追加しました。
<!DOCTYPEhtml>
<html>
.
.
.
<body>
<%= render 'layouts/header' %>
<div class="container">
<%= yield %>
<%= render 'layouts/footer' %>
<%= debug(params) if Rails.env.development? %> <!--追加-->
</div>
</body>
</html>
Rails.env.development?
は、Railsが開発環境(development)のときのみtrueとなります。Railsにはこのほかにも test
、production
(本番環境) が用意されています。
ここで引数に渡している params
は、HTTPリクエストから受け取ったパラメータを扱うための変数です。詳しい仕様は今後改めて学ぶ予定です。
続いて、routes.rb
において users/:id
のルーティングが有効になっていなかったので、以下のコードを追記しました。
Rails.application.routes.draw do
root "static_pages#home"
get "/help",
to: "static_pages#help"
get "/about", to: "static_pages#about"
get "/contact", to: "static_pages#contact"
get "/signup", to: "users#new"
resources :users # 追加
end
resources :users
を追加することで、RESTfulなUsersリソースで必要となるアクション(index, show, new, create, edit, update, destroy)にアクセスできるようになります。
RESTfulについては本格的に理解しようとするとややこしいですが、ひとまずは「これでユーザー関連の基本的なルーティングが一括で設定される」と理解しておけばOKです。
debugger
ここでトラブルが発生しました。debugger
メソッドを使おうとするとエラーが出てしまい、実行できなかったのです。
実は、$ rails console
とGemfile内の
group :development, :test do
gem "debug", "1.7.1", platforms: %i[ mri mingw x64_mingw ]
end
が干渉しており、毎回この行をコメントアウトしないと $ rails console が使用できませんでした。しかし、debugger を使うには上記のGemを有効化しておく必要があるため、コメントアウトするわけにもいかず、ChatGPTを使って解決策を模索しました。
エラーメッセージの一部に
/usr/local/rvm/rubies/ruby-3.2.3/lib/ruby/gems/3.2.0/gems/debug-1.7.1/lib/debug/console.rb:25:in reset': missing keyword: :encoding (ArgumentError)
とあり、console.rb
の中に
# reline 0.2.7 or later is required.
raise LoadError if Reline::VERSION < '0.2.7'
という記述がありました。そこで以下のコマンドで現在のrelineバージョンを確認してみました。
gem list reline
# 実行結果
WARN: Unresolved or ambiguous specs during Gem::Specification.reset:
stringio (>= 0)
Available/installed versions of this gem:
- 3.1.2
- 3.0.4
WARN: Clearing out unresolved specs. Try 'gem cleanup <gem>'
Please report a bug if this causes problems.
*** LOCAL GEMS ***
reline (0.6.0, default: 0.3.2)
このあと、stringioのバージョンを3.1.2や3.0.4に変更して試しましたが効果はなく、最終的にGemfileに以下の記述を加えることで解決しました。
gem 'reline', '~> 0.3.2'
これは「relineを0.3.2以上かつ0.4.0未満でインストールする」という意味です。実際に使用していたrelineのバージョン0.6.0は debug と互換性がなかったようで、バージョンを ~> 0.3.2 に固定したところ問題が解消しました。
Gravatar
Gravatarとは、メールアドレスと画像を紐づける無料のサービスです。サンプルアプリケーションではこれを使用して、プロフィール画像を表示しています。
app/views/users/show.html.erb
でGravatarを呼び出し、その実装を app/helpers/users_helper.rb
に書きました。
<% provide(:title, @user.name) %>
<h1>
<%= gravatar_for @user %>
<%= @user.name %>
</h1>
module UsersHelper
# 引数で与えられたユーザーのGravatar 画像を返す
def gravatar_for(user)
gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}"
image_tag(gravatar_url, alt: user.name, class: "gravatar")
end
end
ここではRuby標準ライブラリの Digest モジュールにある hexdigest メソッドを用いて、ユーザーのメールアドレスをMD5ハッシュ化し、その値を用いてGravatarのURLを生成しています。
ユーザー登録フォーム
次に、他のユーザーがブラウザ上で新規登録できるようにフォームを作成しました。
まず、app/controllers/users_controller.rb
の def new
で @user
を生成し、続いて app/views/users/new.html.erb
にフォームのレイアウトを追加します。
class UsersController <ApplicationController
def show
@user =User.find(params[:id])
end
def new
@user =User.new # 追加
end
end
<% provide(:title,'Signup') %>
<h1>Signup</h1>
<div class="row">
<div class="col-md-6col-md-offset-3">
<%= form_with(model:@user)do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.email_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirmation"%>
<%= f.password_field :password_confirmation %>
<%= f.submit "Createmyaccount", class: "btnbtn-primary"%>
<% end %>
</div>
</div>
<% %>
の中にRubyの処理を書けるのは便利で、Railsの特徴の一つですね。
このフォームでは、名前・メールアドレス・パスワード・パスワード確認の入力欄を用意しています。form_with
を呼び出すとRails内のFormBuilder
がfというオブジェクトを生成し、これを使って手軽にフォーム要素を生成できるようになっています。
ユーザー登録失敗
ここでは、Strong Parametersについて学びました。
以下のように、コントローラで User.new(params[:id])
のようにparamsをまるごと渡してしまうと、ユーザーがリクエストに admin: "1"
を仕込むだけで管理者権限を奪えてしまいます。
def crate
@user = User.new(params[:id])
if @user.save
.
.
end
この問題を防ぐため、RailsではStrong Parametersという仕組みを使います。コントローラ内でparamsのうち許可したキーのみを受け取り、ホワイトリスト化された安全なデータだけをモデルに渡します。
class UsersController <ApplicationController
.
.
.
def create
@user =User.new(user_params)
if @user.save
#保存の成功をここで扱う。
else
render 'new',status::unprocessable_entity
end
end
private
def user_params
params.require(:user).permit(:name,:email, :password, :password_confirmation)
end
end
また、private メソッドにすることで、コントローラ外から user_params を直接呼び出せないようにしています。
まとめ
7章あたりから難易度が上がってきたように感じます。
8章が終わったら、また1章から復習を始めようと思います。継続して取り組みながら、理解を深めていきたいです。