Edited at

rails初心者が、ユーザー登録できるToDoアプリ作成をリリースまで一通り経験できる記事

2018年8月に行った、JavaとHTMLを軽くやったことのある、大学の後輩向けruby on rails勉強会で作った資料を横展開しました。

rails初心者が、一通りアプリを作成しリリースすることのできるので、誰かのためになればいいな〜という思い出Qiitaの記事にしました。

後半に向けて、だいぶ大雑把になっているのと、コメントにございますように不適切な面もございます。

時間を見つけ次第修正しますが、コメントまで拝見していただけると幸いです。

自分もrails初心者なので、間違っているところがあったらコメントでご指摘お願いいたします。


rubyの開発環境を準備しよう

rubyとは、まつもとゆきひろ氏(Matzさん)により開発されたオブジェクト指向スクリプト言語


Javaみたいにコンパイルを行い実行するのではなく、そのまま実行することができる言語をスクリプト言語といいます。

ruby自体はオブジェクト指向なので、ほとんどJavaとできることは一緒です。

書き方がちょっと違うだけなので、rubyの書き方がわからない!ってなったら下記のサイトで検索してください。

Ruby入門


1. rubyのインストール

今回はv2.5.0のバージョンのrubyをインストールしてもらいます。

(ここからはMacの説明です。)


1. homebrewインストール

brew -v でバージョン表示されなかったらhomebrewが入ってないのでいれましょう。

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"


2. rbenvをインストール

rbenvは、rubyのバージョンを管理するツールです。


rubyが新しくなっても、いつでもバージョンを変えられるので、入れておきましょう。

brew install rbenv ruby-build

パスを通します。

$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile

$ source ~/.bash_profile

インストールできたかの確認は

rbenv -vでバージョン表示されるかです。

表示されなかったら読んでください!


3. rubyのインストール

rbenv経由でrubyをインストールします。

rbenv install 2.5.0

次に,どのバージョンのrubyを使うかを書きます。

rbenv local 2.5.0

ruby -v2.5.0がでたらok


4. bundlerのインストール

bundlerは、特定のディレクトリ(フォルダ)に、ruby on railsで必要になるパーツたちを入れてくれる優しい子です。

この子は大切なので、入れておきましょう。

gem install bundler

ちなみにgemは、rubyのライブラリって思っておけば大丈夫です。

https://blog.codecamp.jp/rails-gem

次からが本番です。ruby on railsのアプリを作成して行きます!


参考記事

Qiita|MacにHomeBrew,rbenv,bundlerをインストールする


2. railsのアプリを作成しよう

ruby on railsとは、Rubyで構築された、Webアプリケーション開発のためのフレームワークです。

まっつさんが作った言語Rubyで、webアプリをえーかんじに作れる子って覚えてば大丈夫!

👇railsってどんな子?ってのが詳しく知りたい人へ


https://blog.codecamp.jp/what_is_rails


1. railsアプリ作りたいディレクトリに遷移

cd ディレクトリ名

みんな意外と自分がどこにいるか見失うので、pwdって打ってみてください。

どこにいるかわかります。


2. Gemfileを作成

bundle init


3. Gemfileを書き換える。

Gemfileを下記のように書き換えます。


前: Gemfile

# gem "rails"

後: Gemfile

gem "rails", "~> 5.2.1"   # 5.2.1以上5.3.0未満の最新のものを使用


4.必要なパーツをインストール

プロジェクトに必要なパーツをvendor/bundlerにぼこすか入れて行きます。

bundle install --path vendor/bundler

まぁまぁかかるので、待っててください。

今後gemってのを追加したら、bundle installに入ります。


5. railsのアプリを入れる。

bundle exec rails new --skip-turbolinks --skip-test .

Overwrite /Users/YunaKato/takuten/practice_app/Gemfile? (enter "h" for help)ってでるので、Enter。


6. railsのサーバーを起動

bundle exec rails server

これでhttp://localhost:3000/をアクセスして「Yay! You’re on Rails!」が出たら、railsのアプリが無事起動しました!



みんなの疑問 「bundle execって何?」

おそらくProgateやった人は、rails new ファイル名みたいなコマンドを打っていたと思います。


でも今回はbundle execを必ずrailsの前につけます。


なんでだと思いますか?

今までは、PC上に入っているrailsで実行していたんですが、

今回はvendor/bundle内にいるrailsで実行しているんです。


なぜそれをした方が良いかというと、今後共同開発とかするようになると、「バージョン違い」ってのがおきたりします。


railsは割とバージョンに依存しているので、PCに入っているrailsで実行するのではなく、

プロジェクトごとのrailsを実行する必要があります。


なので、bundle execをつけることが大切です!!

もし、bundle exec打つのめんどい!って人がいたら、エイリアスってのを設定するとbe railsbundle exec railsって打てるようになるよ!!


(ちなみに私は git statusgit stにしたり、git checkoutgit coにしたりしています。)

【初心者向け】エイリアスの設定方法


3. ユーザー登録ができるようにしよう!

まずはじめに、ユーザー登録が必要な人は、ユーザー登録ができるようにしましょう!

ユーザー登録やログイン、パスワードの設定などは自分で書くと、結構セキュリティ面がダメになっちゃったりします。

そこで、今回はdevise というセッション周りを全部管理してくれる有能なパッケージを使います!

⚠︎ コメントにはございますように、最初のRailsアプリケーションを作成にはdeviseは向いていません。railsというフレームワークを理解した上で用いることが推奨されます。

かなり参考なサイト - [Rails] deviseの使い方


1. deviseをインストール

deviseはgemなんで、それをまずインストールします。

そのために、Gemfileに書き加えます。

# Reduces boot times through caching; required in config/boot.rb

gem 'bootsnap', '>= 1.1.0', require: false

# ↓追加
# Devise
gem 'devise'

書き加えたgemをインストールします。

bundle install


2. deviseをアプリ内に生成する。

先ほどのは、vendor/bundleにdeviseをダウンロードしてきただけです。

まだアプリ内でdeviseを使える状態ではありません。

deviseをアプリ内で使うには、generate(生成)する必要があります。

下記コマンドを実行してdeviseを生成しましょう。

bundle exec rails g devise:install

そしたら、こんなのが出るはずです。

===============================================================================

Some setup you must do manually if you haven't yet:

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.

2. Ensure you have defined root_url to *something* in your config/routes.rb.
For example:

root to: "home#index"

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>

4. You can copy Devise views (for customization) to your app by running:

rails g devise:views

===============================================================================


3. deviseの設定を行う。

先ほどのマニュアルの通りにセットアップを行なって行きます。


1. config/environments/development.rb にポート番号等を追記


config/environments/development.rb

config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }



2. home#indexをrootに設定

ここはprogateやった人ならできるはず!!!!!


自力で頑張ってみよう。


3. app/views/layouts/application.html.erbに警告やエラーを表示できるように書き換える。


app/views/layouts/application.html.erb

  <body>

<!-- ▼ 追加 -->
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
<!-- ▲ 追加 -->
<%= yield %>
</body>


4. Deviseのviewを作成

下記deviseのコマンドを実行するだけで、必要なviewが生成されます。

bundle exec rails g devise:views


Userモデルの作成

今回はdevise経由でUserのモデルを作成します。

下記コマンドを実行すると、Userモデルを作成すると共に、ルーティングが自動に生成され先ほど作ったviewに結びつきます。

bundle exec rails g devise User

また、モデルを生成してもデータベースの貯蔵庫がいないので、DBをマイグレートして作成しましょう。

bundle exec rails db:migrate

こんな感じに表示されたら成功です。

== 20180720205705 DeviseCreateUsers: migrating ================================

-- create_table(:users)
-> 0.0021s
-- add_index(:users, :email, {:unique=>true})
-> 0.0009s
-- add_index(:users, :reset_password_token, {:unique=>true})
-> 0.0010s
== 20180720205705 DeviseCreateUsers: migrated (0.0043s) =======================

一度、ルーティングがどうなってるのかをみてみましょう。

下記コマンドで、ルーティングの設定がみることができます。

bundle exec 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 / home#index

http://localhost:3000/users/sign_upにアクセスすると、ユーザー登録できそうなフォームが表示されてると思います。

app/views/layouts/application.html.erbに下記htmlを追加すると、セッション周りに必要なページに遷移できるように設定できます。

  <body>

<!-- ▼ 追加 -->
<nav>
<% if user_signed_in? %>
<%= link_to 'ログアウト', destroy_user_session_path, method: :delete %>
<% else %>
<%= link_to 'サインアップ', new_user_registration_path %>
<%= link_to 'ログイン', new_user_session_path %>
<% end %>
</nav>
<!-- ▲ 追加 -->
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
<%= yield %>
</body>



Userにデフォルト以外のデータを保存できるようにしたい!

今回deviseを用いると,メールアドレスとパスワードが保存できるようになりますね。


でも、他に〇〇を登録させたいってこともあるでしょう。


そのような場合、どのようにすれば良いかをかいていきますね!

今回は、usernameを登録できるようにします。

カスタマイズは自分自身でチャレンジしてみてください!


1. usernameを追加するマイグレーションファイルの作成

今回は、Userテーブルのにusernameというカラムを追加します。(何言ってるかわからない!ってなったら聞いて欲しいです!)


そのためには下記のコマンドを実行します。

bundle exec rails g migration AddColumnToUser username:string

すると、YYYYMMDD~~~~~_add_column_to_user.rbが生成されると思います。


中をみてみると、


YYYYMMDD~~~~~_add_column_to_user.rb

class AddColumnToUser < ActiveRecord::Migration[5.2]

def change
add_column :users, :username, :string
end
end

string型のusernameカラム(:username)をusersテーブル(:users)に追加するというコードが書かれてますね!

カラムを追加したり削除したりする時に参考になる記事

rails generate migrationコマンドまとめ


2. データベースに反映させる

migrationファイルを生成したあとは必ずデータベースをマイグレートします。

じゃないとDBに何も反映されません!

bundle exec rails db:migrate

そうすると、DBから反応が返ってきます。

== 20180720212254 AddColumnToUser: migrating ==================================

-- add_column(:users, :username, :string)
-> 0.0024s
== 20180720212254 AddColumnToUser: migrated (0.0025s) =========================


3. 登録できるようにコントローラを設定する。

/app/controllers/application_controller.rbに下記のコードを追加


application_controller.rb

class ApplicationController < ActionController::Base

#### ▼ 追加 ###
before_action :configure_permitted_parameters, if: :devise_controller?

protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :username])
end
#### ▲ 追加 ###
end


ここに書いてあることはちょっとだけ難しいです。

なので、説明は割愛します。

before_actionに関して

rails: before_actionとは

permitに関して

【Ruby on Rails】require と permit の使い方がよく分からない


4. 登録できるようにビューを設定する。

せっかく登録できるようになったのに、それらを登録できるフォームを作らないと意味がないですね。

なので、usernameを登録できるフォームを/app/views/devise/registrations/edit.html.erb/app/views/devise/registrations/new.html.erbに追加しましょう。


new.html.erb

  <div class="field">

<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>

<!-- ▼ 追加 -->
<div class="field">
<%= f.label :username %><br />
<%= f.text_field :username, autofocus: true, autocomplete: "username" %>
</div>
<!-- ▲ 追加 -->

<div class="field">



edit.html.erb

  <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>

<div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
<% end %>

<!-- ▼ 追加 -->
<div class="field">
<%= f.label :username %><br />
<%= f.text_field :username, autofocus: true, autocomplete: "username" %>
</div>
<!-- ▲ 追加 -->

<div class="field">


また、ログインしてる時は、ユーザーネームが表示されてるようにしましょう。


application.html.erb

    <nav>

<% if user_signed_in? %>
<%= link_to 'ログアウト', destroy_user_session_path, method: :delete %>
<% else %>
<%= link_to 'サインアップ', new_user_registration_path %>
<%= link_to 'ログイン', new_user_session_path %>
<% end %>
<!-- ▼ 追加 -->
<% if user_signed_in? %>
username : <%= current_user.username %>さん
<% end %>
<!-- ▲ 追加 -->
</nav>


4. ToDoリストの作成

今回はtodoリストということで、taskというモデルを作成します。



bundle exec rails g model task

YYYYMMDD~~~~_create_tasks.rbというマイグレーションファイルができるので、必要なデータをかいていきます。

class CreateTasks < ActiveRecord::Migration[5.2]

def change
create_table :tasks do |t|
# タイトル
t.string :title, null: false
# 説明
t.text :description, null: true
# 締め切り
t.datetime :target_at, null: true
# タスク完了日
t.datetime :completed_at, null: true
# タスク完了したか
t.boolean :completed, null: false, default: false
# userモデルのuser_idに結びつけるため、必要
            t.references :user, foreign_key: true
t.timestamps
end
end
end

データベースをマイグレート。

bundle exec rails db:migrate 

成功したら下記とおり表示されます。

== 20180720221424 CreateTasks: migrating ======================================

-- create_table(:tasks)
-> 0.0016s
== 20180720221424 CreateTasks: migrated (0.0017s) =============================

Userモデルクラス、Taskモデルクラスにアソシエーションの設定をします。

一つのuserが複数のタスクを持つことは可能であるため、「has_many」で関連付けします。

has_many関連付けは、他のモデルとの間に「1対多」のつながりがあることを示します。

app/models/user.rb

class User < ApplicationRecord

# ▼ 追加
has_many :tasks, dependent: :destroy
# ▲ 追加

# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end

一つのタスクは一つのユーザーに結びつくため、「belongs_to」で関連付けします。

「belongs_to」関連付けを行なうと、他方のモデルとの間に「1対1」のつながりが設定されます。

app/models/task.rb

class Task < ApplicationRecord

belongs_to :user, optional: true
end

タスクの一覧、詳細、新規作成、編集のページが欲しいので、作成。

bundle exec rails g controller tasks index show new edit

app/controllers/tasks_controller.rb

# 認証済みであることを確認

before_action :authenticate_user!

def index
@tasks = current_user.tasks
end

def show
@task = target_task params[:id]
end

def new
@task = Task.new
end

def create
@task = current_user.tasks.new task_params
@task.save!
redirect_to @task
end

def edit
@task = target_task params[:id]
end

def update
@task = target_task params[:id]
@task.update(task_params)
redirect_to @task
end

def destroy
@task = target_task params[:id]
@task.destroy
redirect_to tasks_url
end

private
def target_task task_id
current_user.tasks.where(id: task_id).take
end

def task_params
params.require(:task).permit(:title, :description)
end

app/views/tasks/index.html.erb

<h1>Tasks#index</h1>

<p>Find me in app/views/tasks/index.html.erb</p>
<table>
<tr>
<th>Id</th><th>Title</th><th>Description</th><th></th><th></th><th></th>
</tr>
<% @tasks.each do |task| %>
<tr>
<td><%= task.id %></td>
<td><%= task.title %></td>
<td><%= task.description %></td>
<td><%= link_to 'Show', task_path(task) %></td>
<td><%= link_to 'Edit', edit_task_path(task) %></td>
<td><%= link_to 'Delete', task_path(task), method: :delete %></td>
</tr>
<% end %>
</table>
<p><%= link_to 'ToDoの作成', new_task_path %></p>

app/views/tasks/edit.html.erb

<h1>Tasks#edit</h1>

<p>Find me in app/views/tasks/edit.html.erb</p>
<div style="width: 300px;">
<%= form_for(@task) do |f| %>
<div>
<%= f.label :title %>
<%= f.text_field :title, size: 50 %>
</div>
<div>
<%= f.label :description %>
<%= f.text_area :description %>
</div>
<%= f.submit 'Submit' %>
<% end %>
</div>
<p><%= link_to '一覧に戻る', tasks_url %></p>

app/views/tasks/new.html.erb

<h1>Tasks#new</h1>

<p>Find me in app/views/tasks/new.html.erb</p>
<div style="width: 300px;">
<%= form_for(@task) do |f| %>
<div>
<%= f.label :title %>
<%= f.text_field :title, size: 50 %>
</div>
<div>
<%= f.label :description %>
<%= f.text_area :description %>
</div>
<%= f.submit 'Submit' %>
<% end %>
</div>
<p><%= link_to '一覧に戻る', tasks_url %></p>

app/views/tasks/show.html.erb

<h1>Tasks#show</h1>

<p>Find me in app/views/tasks/show.html.erb</p>
<table>
<tr>
<th>Title</th>
<td><%= @task.title %></td></tr>
<tr>
<th>Description</th>
<td><%= @task.description %></td>
</tr>
<tr>
<th>User.Email</th>
<td><%= @task.user.email %></td>
</tr>
</table>
<p><%= link_to '一覧に戻る', tasks_url %></p>

routingの設定をします。

今回は、リソースフルルーティングを用いて設定します。

リソースフルルーティングでは、CRUD(Create/Read/Update/Delete) 操作に対応付けられるルーティングを自動生成します。

resources :tasks


参考サイト

https://blog.freedom-man.com/rails-devise-todoapp/


5. Herokuでリリース


1. herokuの登録

今回は、アプリとして使ってもらうため、serviceworkerを導入します。

また、Herokuはsqlite3が対応していないため、本番ではpostgresqlというデータベースを使います。


1-1. 下記リンクから登録

https://jp.heroku.com/


「welcome to heroku」が表示されたら、OK!!


1-2. PCにherokuいれる

(ターミナル or コマンドプロンプト)

brew install heroku

確認は


(ターミナル or コマンドプロンプト)

heroku --version


1-3. herokuをPCからログインする

(ターミナル or コマンドプロンプト)

heroku login

からの、emailとpassを入力


2. herokuアプリ作成


2-1. アプリ作成

(ターミナル or コマンドプロンプト)

heroku create [アプリ名]

git remote -> herokuってでたらok

git remote -> herokuって出ない -> git remote add heroku https://git.heroku.com/xxxxx-xxxxx-xxxxx.git(createした時にでてきた.gitのやつ)


2-2. Gemfile書き換え

(ターミナル)

brew install postgresql

(Gemfile)

gem 'sqlite3' # <- 削除

gem 'pg' # <- 追加
gem 'serviceworker-rails' # <- 追加

gem 'jquery-rails' # <- ない人追加
gem 'jquery-ui-rails' # <- ない人追加

group :development do
gem 'sqlite3' # <-こっちに追加
end

gemを再インストール

(ターミナル or コマンドプロンプト)

bundle install


3. serviceworkerを導入


3-1. インストール

(ターミナル or コマンドプロンプト)

bundle exec rails g serviceworker:install


3-2. いろいろ読み込ませる


/config/database.yml

production:

<<: *default
adapter: pg
database: db/production.pg


app/assets/javascripts/application.js

//

//= require jquery #ない人追加
//= require serviceworker-companion #追加
//= require rails-ujs
//= require activestorage
//= require_tree .

// safari起動させないための記述
$(function(){
$('a').click(function(){
location.href = $(this).attr('href');
return false;
});
});



app/view/layouts/application.html.erb

<!-- headの中に書く -->

<link rel="manifest" href="/manifest.json" />
<meta name="apple-mobile-web-app-capable" content="yes"></head>
<link rel="apple-touch-icon" href="<%=image_path("icon.png")%>" />


config/initializers/assets.rb

Rails.configuration.assets.precompile += %w[serviceworker.js manifest.json]



app/assets/stylesheets/application.css

/* iosがデフォルト明朝体なので変更 */

body {
font-family: 'Avenir','Helvetica Neue','Helvetica','Arial','Hiragino Sans','ヒラギノ角ゴシック',YuGothic,'Yu Gothic','メイリオ', Meiryo,'MS Pゴシック','MS PGothic'
}


3-4. manifestのカスタマイズ


app/assets/javascripts/manifest.json

{

"name": "appApp", #アプリの長い名前
"short_name": "app", #アプリの短い名前
"start_url": "/", #起動時のパス
"icons": [
{
"src": "<%=image_path("icon.png")%>", #アイコン
"type": "image/png",
"sizes": "192x192"
}
],
"theme_color": "#fbb03b", #テーマ
"background_color": "#9ce4ff", #起動時の色
"display": "fullscreen",
"orientation": "portrait"
}


4. herokuにリリース


4-1. git操作

git add .

git commit -m"〜〜〜〜"


4-2. herokuにpush

git push heroku master


4-3. herokuでデータベース構築

heroku run:detached rails db:migrate


4-4. herokuで作ったアプリ起動

heroku open