20200107のRailsに関する記事は28件です。

[Rails]本日のエラー

今度作業する時に、あれ?過去にも同じエラーが起こったことあるぞ!!となった時用に記事として保管しておくのが目的です。
なので、個人的に使用する記事なので投稿内容は大雑把にまとめます。

記事の流れ
1.なんの作業中にエラーが起きたのか
2.エラーの内容
3.対処法
4.原因

以上の流れで書いていきます。

1.dbをリセットしようとした時

ターミナル.
rake db:migrate:reset

2.エラー内容

ActiveRecord::NoEnvironmentInSchemaError: 

Environment data not found in the schema. To resolve this issue, run: 

        bin/rails db:environment:set RAILS_ENV=development


Tasks: TOP => db:migrate:reset => db:drop => db:check_protected_environments
(See full trace by running task with --trace)

3.対処法

rake db:migrate:status

上記のコマンドでdbのステータスを確認します。
⬇︎実行内容

   up     20191223083031  Create articles
   up     20191223091431  Devise create users
   up     20191225043801  Add name to user
  down    20191225083536  Add frequency to habits

どうやら、一番下のマイグレーションファイルが怪しい。。。
確認したところ
habitsテーブルにfrequencyカラムを二回作成していました。。
なので、一番下のマイグレーションファイルを削除してみます。
※downの状態だったら、手動でファイルを削除しても問題ない
⬇︎実行結果

== 20191225234523 CreateHabits: migrating =====================================
-- create_table(:habits)
   -> 0.0302s
== 20191225234523 CreateHabits: migrated (0.0302s) ============================

== 20191229141445 AddImageToHabits: migrating =================================
-- add_column(:habits, :image, :string)
   -> 0.0195s
== 20191229141445 AddImageToHabits: migrated (0.0195s) ========================

== 20200101140707 AddDateAtToHabits: migrating ================================
-- add_column(:habits, :date_at, :date)
   -> 0.0231s
== 20200101140707 AddDateAtToHabits: migrated (0.0232s) =======================

== 20200103135302 CreateLikes: migrating ======================================
-- create_table(:likes)
   -> 0.0157s
== 20200103135302 CreateLikes: migrated (0.0158s) =============================

== 20200107020748 AddLikesCountToHabits: migrating ============================
-- add_column(:habits, :likes_count, :integer)
   -> 0.0174s
== 20200107020748 AddLikesCountToHabits: migrated (0.0174s) ===================

問題なくできました。

4.原因

1つのテーブルに同じカラム名のカラムを追加、作成するマイグレーションファイルが重複していたため、migrateコマンドが実行できなかったと思われる。
なぜ二つ追加、作成したかは謎。
参考記事
https://blog.freedom-man.com/no-environment-in-schema-error

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】2つのテーブルを結合しつつ、欲しいカラムだけを抜き出してJSONで返すサンプルコード

はじめに

Railsで2つのテーブルを結合しつつ、欲しいカラムだけを抜き出してJSONにして返すサンプルコードです。

このコードで出来たJSONはネストされておらず、シンプルなので扱いやすいです。

環境

OS: macOS Catalina 10.15.1
Ruby: 2.6.5
Rails: 6.0.2.1

前提

  • UserモデルとPostモデルがある
  • User1に対してPostが多の関係
  • それぞれのテーブル名はusersとposts
  • 以下のように関連付け済み
user.rb
class User < ActiveRecord::Base
  has_many :posts
end
post.rb
class Post < ApplicationRecord
  belongs_to :user
end

欲しいデータ

各テーブルのカラムは以下のように多数あり、
「不要なデータは取得したくない!」
という状況を想定し、#欲しいを付けたカラムだけを抜き出したJSONが欲しいとします。

- usersテーブル
    - id
    - name #欲しい
    - email
    - ...

- postsテーブル
    - id #欲しい
    - name #欲しい
    - description #欲しい
    - user_id #欲しい
    - date
    - ...

これは以下コードで実現可能です。

結論

posts_controller.rb
  def posts_needed
    posts_needed = Post.joins(:user)
    .select("
      posts.id,
      posts.name,
      description, #ここはusersテーブルと名前が被らない
      user_id, #ここはusersテーブルと名前が被らない
      users.name AS user_name #別名を付けられる
      ")
    render json: posts_needed
  end

【ポイント】

  • Post.joins(:user)postsテーブルとusersテーブルを結合

  • .select("カラム1, カラム2, ...")で欲しいカラムを指定

  • 元のカラム名が被る場合posts.nameusers.nameのようにテーブル名.カラム名として指定しないと、両方取り出すのは不可

  • テーブル名.カラム名 AS 任意名で出力されるカラム名を指定可能

  • テーブル名は複数形

出力

出力(JSON)
[
    {
        "id": 1,
        "name": "投稿名1",
        "description": "投稿詳細1",
        "user_id": 2,
        "user_name": "Brutus"
    },
    {
        "id": 2,
        "name": "投稿名2",
        "description": "投稿詳細2",
        "user_id": 3,
        "user_name": "Omae Dattanoka"
    },
...
]

ネストされたものよりシンプルで扱いやすいJSONに仕上がりました:relaxed:

おわりに

最後まで読んで頂きありがとうございました:bow_tone1:

どなたかの参考になれば幸いです:relaxed:

参考にさせて頂いたサイト(いつもありがとうございます)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerでalpineイメージ使用時に発生したstandard_init_linux.go:211: exec user process caused "no such file or directory" を解決

alpineイメージ使用時に発生するstandard_init_linux.go:211: exec user process caused "no such file or directory" を解決

Docker X Rails6 X MySQL8で環境構築する際に、初めてalpineイメージを使用するとエラーに出会いました。
alpineはLinuxディストリビューションの1つで、CentOSやUbuntuよりも軽量なためDockerイメージのサイズを小さくすることができます。

各種設定

Dockerfile
FROM ruby:2.7.0-alpine
ENV LANG C.UTF-8

RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock

RUN apk update -qq && apk add --no-cache yarn build-base tzdata libxml2-dev mariadb-dev libxslt-dev alpine-sdk mysql-dev nodejs vim g++
RUN bundle install
run yarn install
COPY . /myapp

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]
docker-copose.yml
~~省略
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
~~省略
entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"

(他, Gemfile,Gemfile.lock)

エラー発生

$ docker-compose run web rails new .

を実行すると

standard_init_linux.go:211: exec user process caused "no such file or directory

というエラーが発生し、rails newは実行できませんでした。

原因

alpineのシェルはbashではなくashだった。

解決

docker-compose.ymlentrypoint.shを編集します。

docker-compose.yml
  web:
    build: .
    # bash → ashに変更
    command: ash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
entrypoint.sh
#!/bin/sh ←bashからshへ
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"

編集後、再度

$ docker-compose run web rails new .

すれば実行できました。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

alpineイメージ使用時に発生するstandard_init_linux.go:211: exec user process caused "no such file or directory" を解決

alpineイメージ使用時に発生するstandard_init_linux.go:211: exec user process caused "no such file or directory" を解決

Docker X Rails6 X MySQL8で環境構築する際に、初めてalpineイメージを使用するとエラーに出会いました。
alpineはLinuxディストリビューションの1つで、CentOSやUbuntuよりも軽量なためDockerイメージのサイズを小さくすることができます。

各種設定

Dockerfile
FROM ruby:2.7.0-alpine
ENV LANG C.UTF-8

RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock

RUN apk update -qq && apk add --no-cache yarn build-base tzdata libxml2-dev mariadb-dev libxslt-dev alpine-sdk mysql-dev nodejs vim g++
RUN bundle install
run yarn install
COPY . /myapp

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]
docker-copose.yml
~~省略
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
~~省略
entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"

(他, Gemfile,Gemfile.lock)

エラー発生

$ docker-compose run web rails new .

を実行すると

standard_init_linux.go:211: exec user process caused "no such file or directory

というエラーが発生し、rails newは実行できませんでした。

原因

alpineのシェルはbashではなくashだった。

解決

docker-compose.ymlentrypoint.shを編集します。

docker-compose.yml
  web:
    build: .
    # bash → ashに変更
    command: ash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
entrypoint.sh
#!/bin/sh ←bashからshへ
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"

編集後、再度

$ docker-compose run web rails new .

すれば実行できました。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerでalpineイメージ使用時に発生するstandard_init_linux.go:211: exec user process caused "no such file or directory" を解決

alpineイメージ使用時に発生するstandard_init_linux.go:211: exec user process caused "no such file or directory" を解決

Docker X Rails6 X MySQL8で環境構築する際に、初めてalpineイメージを使用するとエラーに出会いました。
alpineはLinuxディストリビューションの1つで、CentOSやUbuntuよりも軽量なためDockerイメージのサイズを小さくすることができます。

各種設定

Dockerfile
FROM ruby:2.7.0-alpine
ENV LANG C.UTF-8

RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock

RUN apk update -qq && apk add --no-cache yarn build-base tzdata libxml2-dev mariadb-dev libxslt-dev alpine-sdk mysql-dev nodejs vim g++
RUN bundle install
run yarn install
COPY . /myapp

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]
docker-copose.yml
~~省略
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
~~省略
entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"

(他, Gemfile,Gemfile.lock)

エラー発生

$ docker-compose run web rails new .

を実行すると

standard_init_linux.go:211: exec user process caused "no such file or directory

というエラーが発生し、rails newは実行できませんでした。

原因

alpineのシェルはbashではなくashだった。

解決

docker-compose.ymlentrypoint.shを編集します。

docker-compose.yml
  web:
    build: .
    # bash → ashに変更
    command: ash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
entrypoint.sh
#!/bin/sh ←bashからshへ
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"

編集後、再度

$ docker-compose run web rails new .

すれば実行できました。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

herokuへデプロイ後、We're sorry, but something went wrong.

We're sorry, but something went wrong.

herokuへデプロイ後にブラウザで表示されるました。

image.png

原因

色々調べたところ

・データベースの変更が更新されていない。

・モデルにアクセスする処理を行っているのに、heroku上のデータベースをリセットを行っていない。

これは、デプロイ自体はできているみたい。
このパターンが多いみたいです。
僕もそうでした。

解決法

$heroku run rake db:migrate

↑これで、heroku上のデータベースを更新

いけました。。一安心です

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSでのデプロイ手順①ネットワーク環境設定

初心者には難関である、AWSを使用したデプロイ手順を書いてみます

AWSはUIもよく変化するので、
現在のもの(2019/10)で書いています

※アカウントがない人はまず新規で申し込みしておいてください

今回内容
STEP1 ネットワーク環境設定
1.VPCの作成
2.サブネットの作成
3.インターネットゲートウェイの作成
4.ルートテーブルの作成
5.サブネットとの紐付け
6.セキュリティグループの作成

STEP2 EC2の設定
1.EC2にてインスタンスの作成
2.Elastic IPの割り当て
3.インスタンスにSSHでログイン

次回内容
STEP3以降
AWSでデプロイするまでの手順②サーバー(EC2インスタンス)環境設定

※ここでいうサーバーとはAWS EC2インスタンス (Amazon Linux) のこととする

STEP1 ネットワーク環境設定

1.VPCの作成

https://aws.amazon.com/
Amazon Web Servicesでサインインします

ヘッダーにあるリージョンを東京に設定し、
「VPC」を検索し「VPC」にいきます

スクリーンショット 2019-10-01 10.13.39.png

サイドメニューのVPCより[VPCの作成]を押下します
スクリーンショット 2019-09-29 20.26.18.png

作成画面になるので
今回は下のように設定し、[作成]を押下します

・ネームタグ       :testVPC
・IPv4 CIDRブロック:10.0.0.0/16
・IPv4 CIDRブロック:ブロックなし
・テナンシー       :デフォルト

スクリーンショット 2019-10-01 10.18.41.png

2.サブネットの作成

サイドメニューのサブネットより[サブネットの作成]を押下します
スクリーンショット 2019-09-29 20.30.39.png

作成画面になるので
下のように設定し、[作成]を押下します

・ネームタグ:testSubnet
・VPC:先ほど作成したものを選択
・アベイラビリティゾーン:ap-northeast-1a
・CIDRブロック:10.0.0.0/24

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3335353531372f34633731633536382d346231352d653262622d636665612d6333373631643964363634642e706e67.png

3.インターネットゲートウェイの作成

サイドメニューのインターネットゲートウェイより
[インターネットゲートウェイの作成]を押下します

スクリーンショット 2019-09-29 20.34.02.png

作成画面になるので
下のように設定し、[作成]を押下します

名前タグ:testGateway

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3335353531372f30303636333333392d383839352d643333632d343637332d6362376530643365353366632e706e67.png

[アクション]を押下し、[VPCにアタッチ]を押下します
68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3335353531372f63333666633763662d313638622d626136392d306135652d3365326235653836303433642e706e67.png

下のように設定し、[アタッチ]を押下する

VPC:先ほど作成したものを選択

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3335353531372f66303032333238392d653838612d326264652d306337632d3661323536666230373264312e706e67.png

4.ルートテーブルの作成

サイドメニューのルートテーブルより[ルートテーブルの作成]を押下

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3335353531372f37616534643065332d323862302d613333372d346132632d6630623434383936643238352e706e67.png

作成画面になるので
下のように設定し、[作成]を押下します

名前タグ:testTable
VPC:先ほど作成したものを選択

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3335353531372f32623430326161332d633761652d666461622d616163622d6130326265323933383230652e706e67.png

作成したルートテーブルを選択した状態で、
下のタブ「ルート」>「ルートの編集」を押下、[ルートの追加]を押下

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3335353531372f35336331383337372d353137662d613265342d313139352d3263613730396130306661632e706e67.png

下のように設定し[ルールの保存]を押下します

送信先:0.0.0.0/0
ターゲット:Internet Gatewayを選択し、先ほど作成したゲートウェイIDを選択

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3335353531372f63626462313066362d656534352d616239312d613164612d6534363733636333313136662e706e67.png

5.サブネットとの紐付け

→左側の「サブネット」を選択します
→関連付けを変更するサブネットを選択します
→画面下のルートテーブルを選択します
→[ルートテーブルの関連付けの編集]を押下します

スクリーンショット 2019-10-01 10.35.17.png

→先ほど作成したルートテーブルIDを選択します
→[保存]を押下します

スクリーンショット 2019-10-01 10.39.06.png

6.セキュリティグループの作成

サイドメニューの
セキュリティ>セキュリティグループより>[セキュリティグループの作成]を押下します
スクリーンショット 2019-09-29 21.07.37.png

下のように設定し、[作成]を押下する

セキュリティグループ名:testSecurityGroup
説明:そのセキュリティグループの説明
VPC:先ほど作成したものを選択

スクリーンショット 2019-10-01 10.43.36.png

画面下のインバウンドのルールの[ルールの編集]を押下し、[ルールの追加]を押下、
下のように設定し、[ルールの保存]を押下する

タイプ:SSH
ソース:マイIP

スクリーンショット 2019-09-30 21.23.54.png

STEP2 EC2の設定

AWSでDBを利用したい場合、

・EC2にてインスタンスの作成
・RDSを利用する
※ ただRDSを使用すると料金が掛かるので、
使用しない場合はサーバーに直接データベースを作成してください。

この2種類の方法があります。
今回は
EC2にてインスタンスの作成(サーバーに直接データベースを作成)
をメインに行なっていきます

1.EC2にてインスタンスの作成

インスタンスは起動のままだと
課金請求されるので、使わない場合は
停止状態にすることをお勧めします

AWS マネジメントコンソールにて"EC2"を検索しアクセスする

スクリーンショット 2019-09-26 23.58.51.png

サイドメニューのインスタンスより[インスタンスの作成]を押下する

スクリーンショット 2019-09-27 0.02.03.png

今回はこちらをクリックします
スクリーンショット 2019-09-27 0.06.56.png

[次の手順: インスタンスの詳細の設定]をクリックする

スクリーンショット 2019-09-27 0.08.21.png

下を設定し,[次の手順: ストレージの追加]を押下する

ネットワーク:先ほど作成したVPCを選択
サブネット:先ほど作成したサブネットを選択
自動割り当てパブリック IP:有効
他はデフォルトのまま

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3335353531372f30353438646266632d333631362d396662392d386166662d6265383133353536653934632e706e67.png

デフォルトのままで,[次の手順: タグの追加]を押下する

タグを追加する

[タグの追加]を押下する
スクリーンショット 2019-09-30 16.46.54.png

キー:Name
値:testInstance

で[次の手順: セキュリティグループの設定]を押下する

セキュリティグループの設定する

セキュリティグループの割り当て:既存を
選択し、先ほど作成したセキュリティグループを選択し、
[確認と作成]を押下する
68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3335353531372f39616532356237392d396565342d363531342d396237392d6237333732613434373030322e706e67.png

一覧画面にて、
最後に[起動]を押下します

下ような表示になり、
新しいキーペアを作成を選択、
キーペア名を入力し、
[キーペアのダウンロード]を押下します
(一度作成されたファイルは再度ダウンロードができなくなるので注意)
スクリーンショット 2019-09-30 19.51.28.png

ダウンロードしたら[インスタンスの作成]を押下します

しばらくするとインスタンスが作成されます!!

2.Elastic IPの割り当て

サイドメニューの
ネットワーク&セキュリティ>
Elastic IP[新しいアドレスの割り当て]を押下する

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3335353531372f36323739383338622d633864352d643366312d383066342d6639613635663234633238612e706e67.png

[割り当て]を押下します
スクリーンショット 2019-09-30 17.06.31.png

[閉じる]で戻り

[アクション]>アドレスの関連付けを押下します
68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3335353531372f34643235323034332d663531632d653261362d396330362d3462626139363734326635662e706e67.png

インスタンスを先ほど作成したものを選択し、[関連付け]を押下する
スクリーンショット 2019-09-30 17.09.45.png

※停止していたインスタンスにElastic IPを関連付けたままにしていると小額の料金が発生してしまうので、
インスタンスを停止している場合は解放することをお勧めします

Elastic IPをアタッチ(関連付け)しているインスタンスが起動している状態であれば、料金は発生しません。しかし、インスタンスが「停止」している状態や、Elastic IPを使っていない場合、料金が発生します。そのため、使わないElastic IPは削除しなければいけません。

Elastic IPがまだインスタンスにアタッチしている場合は、Elastic IPから該当のIPを選択し、「アクション」→「アドレスの関連付けの解除」をクリックします。確認画面が表示されますので、間違いなければ、「アドレスの関連付けの解除」をクリックし、EIPをデタッチします。

その後、再度該当のIPを選択し、「アクション」→「アドレスの解放」をクリックし、EIPを削除します。これで、料金が発生しなくなります。

3.インスタンスにSSHでログイン

各種インストール

python

$ brew install python

pip(pythonのパッケージ管理システム)

$ easy_install pip

awscli(awsをPCのコンソール上から扱うためのもの)

$ pip install awscli

できない場合はこちら
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-macos.html

ec2-userでインスタンスにログインする

AWSでは、
EC2インスタンスにログインできるユーザーとして、
デフォルトでec2-userという名のユーザーが用意されています
こちらではまずec2-userでログインします

ターミナルで以下を入れていきます
(※testKey.pemは、先ほどSTEP2でダウンロードしたキーです)

$ mv Downloads/testKey.pem .ssh/
(#作成した公開鍵をsshフォルダに移動)

$ cd .ssh/
(#ディレクトリをsshに移動)

$ chmod 600 testKey.pem
(#公開鍵に600番で定義されたアクセス権を付与する)

$ ssh -i testKey.pem ec2-user@(@以降のURLは、作成したEC2インスタンスと紐付けたElastic IPを使用してください。)
(#公開鍵を利用してec2-userとしてログイン)

例:
($ ssh -i testKey.pem ec2-user@13.112.140.56)

yes/noを聞かれるので

yesでEnterを押下
スクリーンショット 2019-09-30 21.49.54.png

無事にログインできました!!!


ssh port 22 Operation timed out
エラーになる場合はこちら
https://qiita.com/yokoto/items/338bd80262d9eefb152e

https://qiita.com/minicoopers0716/items/cac50f29ef79a03f1d8d

ユーザー作成(EC2上での操作)

上記方法でインスタンスにログインしている状態で

[ec2-user|~]$ sudo adduser testuser
(#新規ユーザー名の登録)
[ec2-user|~]$ sudo passwd testuser
(#新規ユーザー名のパスワード登録)


パスワードを登録します


vimでユーザーに権限を追加する記述する

$ sudo visudo

vimモードになります

## Allows people in group wheel to run all commands
# %wheel        ALL=(ALL)       ALL

## Same thing without a password
# %wheel  ALL=(ALL)       NOPASSWD: ALL

## Allows members of the users group to mount and unmount the
## cdrom as root
# %users  ALL=/sbin/mount /mnt/cdrom, /sbin/umount /mnt/cdrom

## Allows members of the users group to shutdown this system
# %users  localhost=/sbin/shutdown -h now

検索モードにし下の
"wheel"を探します
(キーボードで"/wheel"を入力し押下、"N"を押下すると次にいけます)

## Same thing without a password
# %wheel  ALL=(ALL)       NOPASSWD: ALL

キーボードの「i」を押下し、編集モードで

# %wheel ALL=(ALL) NOPASSWD: ALL
のコメントアウトを外します

## Same thing without a password
%wheel  ALL=(ALL)       NOPASSWD: ALL

さらに

その下に、作成したユーザーに権限を追加する記述
testuser   ALL=(ALL)       ALL  を追加する
## Allow root to run any commands anywhere
root    ALL=(ALL)       ALL
testuser   ALL=(ALL)       ALL

キーボードの「esc」を押下します
「:wq」を入力しEnterで保存します

こちらでユーザーの切り替えを行ってください。

[ec2-user|~]$ sudo su - testuser
(#ユーザー名の切り替え)
[testuser@ ~]

無事に[ec2-user|がtestuser(作成したユーザー名)と切り替わればOKです。

exit

を二回いれて
で一度ログアウトする

追加ユーザ用キーペアを作成

こちらはローカルでの作業です

$ cd .ssh
[.ssh]$ ssh-keygen -t rsa
(#公開鍵を作成)
-----------------------------
Enter file in which to save the key ():
(#ここでファイルの名前を記述して、エンターを押す)
test_key_rsa 

Enter passphrase (empty for no passphrase): 
(#何もせずそのままエンター)
Enter same passphrase again: 
(#何もせずそのままエンター)
-----------------------------

[.ssh]$ ls
#「test_key_rsa」と「test_key_rsa.pub」が生成されたことを確認
[.ssh]$ vi config
(#VIMを起動し、設定ファイルを編集する)
-----------------------------

キーボードの「i」を押下し、編集モードで

# 以下を追記
Host test_key_rsa
  Hostname 前出のElastic IP (#自分の設定に合わせて)
  Port 22
  User testuser (#先ほどのユーザー名)
  IdentityFile ~/.ssh/test_key_rsa (#秘密鍵の設定)
* ()部分は削除する。
-----------------------------
キーボードの「esc」を押下します
「:wq」で保存します

[.ssh]$ cat test_key_rsa.pub (#鍵の中身をターミナル上に出力)

★ ssh-rsa~~~~localまでをコピーしておく

サーバー側作業

続いてサーバーでの作業です
ec2-userでログインします

$ cd .ssh
$ ssh -i testKey.pem ec2-user@(@以降のURLは、作成したEC2インスタンスと紐付けたElastic IPを使用してください。)
[ec2-user|~]$ sudo su - testuser
[testuser@ ~]$ mkdir .ssh
[testuser@ ~]$ chmod 700 .ssh
[testuser@ ~]$ cd .ssh
[testuser@ |.ssh~]$ vi authorized_keys

(vimがオープンするので、「i」を押し、
先ほど ★ で、コピーしたssh-rsaをペーストする)
キーボードの「esc」を押下します
「:wq」で保存します

[testuser@ |.ssh~]$ chmod 600 authorized_keys

$ exit
もう一度
$ exit
ログアウト
[~]$ ssh test_key_rsa

ログインできれば、無事ユーザー設定は終了です。

なお、時間が経つとローカルからログインできなくなることがあるので、その場合は、
セキュリティグループ>インバウンド>編集で
SSHのソースで
マイIPを選択し[保存]すると繋がるようになります

続きはこちら
AWSでデプロイするまでの手順②サーバー(EC2インスタンス)環境設定

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

railsでdeviseを使う手順

ユーザー登録の際に使える、deviseという便利なツール。
よく使うことが多いので、簡単な手順をまとめました。

gemを入れる

まずはgemを入れます

gem 'devise'
$ bundle install

deviseをインストールする

次にアプリケーション内にdeviseを読み込みます

$ rails g devise:install

deviseを使って、モデルを作成

今回はユーザーモデルを作ってみます

$ rails g model devise user

必要な追加カラム等があれば、マイグレーションファイルを編集します

t.string :email,              null: false, default: ""
t.string :encrypted_password, null: false, default: ""
#以下のように追加
t.string :name,              null: false, default: ""

その後、application_controllerを編集し、カラム追加を許可してもらいます

before_action :configure_permitted_parameters, if: :devise_controller?

def configure_permitted_parameters
  devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
end
#[:name]のところが、追加したいカラム名。複数指定の場合はカンマ区切りで記入

必要なビューをダウンロード

新規登録ページやログインページなどのビューをダウンロードします

$ rails g devise:views

特殊な処理が必要な場合はdevise用のコントローラーを生成する

$ rails g devise controller users 
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rails db:migrateでエラー(StandardError: An error has occurred, this and all later migrations canceled:)

$rails db:migrate、または、$rake db:migrateを行った後の謎のエラー。

== 20200107095832 CreateMicroposts: migrating =================================
-- create_table(:microposts)
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:

SQLite3::SQLException: table "microposts" already exists: CREATE TABLE "microposts" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "content" text, "user_id" integer, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL)
・
・以下つづく
・

原因

『この前に行ったコマンドのmigrationで何らかの手違いがあると思います。おそらく、migration処理の途中からエラーが起きていて、テーブルは生成されているが、テーブルを生成したmigrationは未実行まま。といった状態なのかな?と思います。』

解決策

$ rake db:migrate:reset

↑これで、データベースのリセットを行った後。

$ rake db:migrate

↑もう一度!

直った!

これでオッケーかと❗️

このコマンドで、マイグレーションを順に実行し、データベースに変更を加えていくんですね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】ブックマーク(お気に入り)機能

備忘録です。

掲示板におけるブックマーク機能追加し、ブックマーク一覧ページを作成。
※初学者です。ご指摘あればお願いします!

環境

Rails 5.2.3
mysql 5.7.28
gem font-awesome-sass
gem Sorcery
→installしていない場合、後述のcurrent_userメソッドが使用できません。

ER図

中間テーブル(Bookmark)使用。
中間テーブル...userとboardのidだけを保存するテーブル。
bookmark_ER図.png

User:Board = 1:多
User:Bookmark = 1:多
Board:Bookmark = 1:多

あくまでブックマーク機能実装の記事ですので、UserとBoardモデルはすでに作成されているものとして進行しますのでご注意ください。

実装

それでは実装していきます。

Bookmarkモデル作成

ターミナル
$ rails g model Bookmark user:references board:references

上記コマンドでbookmark.rb(モデルファイル)とxxxxxxxx_create_bookmarks.rb(マイグレーションファイル)が作成されます。

referencesを指定することで外部キー制約がついてインデックスも貼られるので便利です。

bookmark.rb
belongs_to :user
belongs_to :board
validates :user_id, uniqueness: { scope: :board_id } # 追加

uniqueness: trueでモデルレベルで一意性(ユニーク)を保ちます。
参照:Railsガイドバリデーション

xxxxxxx_create_bookmarks.rb
def change
  create_table :bookmarks do |t|
    t.references :user, foreign_key: true, null: false
    t.references :board, foreign_key: true, null: false

    t.timestamps
    t.index [:user_id, :board_id], unique: true # 追加
  end
end

t.index [:user_id, :board_id], unique: trueと書き足してDBレベルで一意性(ユニーク)を保ちます。

モデルとDB両方に一意性を保つことでより安全性が高まります。
ここでいう一意性とは1人のユーザーが同じ投稿を複数回bookmarkできないようにすることです。

ターミナル
$ rails db:migrate

上記コマンド実行で中間テーブル完成!

UserモデルとBoardモデルのアソシエーション

user.rb
class User < ApplicationRecord
  has_many :boards, dependent: :destroy
  has_many :bookmarks, dependent: :destroy
  has_many :bookmark_boards, through: :bookmarks, source: :board
end

dependent: :destroyでユーザーが削除されたとき、そのユーザーに関連する情報を削除するよう紐付けます。

注目すべきは

has_many :bookmark_boards, through: :bookmarks, source: :board

です。
has many throughオプションでユーザーがブックマークした投稿を直接アソシエーションで取得できます。
後ほどboard_controller.rb実装時に使用しますので、覚えておいてください。

sourceでは参照するモデルを指定しています。

board.rb
class Board < ApplicationRecord
  belongs_to :user
  has_many :bookmarks, dependent: :destroy

# boardのお気に入り判定 → vies側で呼び出し
  def bookmark_by?(user)
    bookmarks.where(user_id: user.id).exists?
  end
end

こちらで注目するのは

def bookmark_by?(user)
  bookmarks.where(user_id: user.id).exists?
end

このインスタンスメソッドです。
ここではbookmark_by?(user)というアクションを明記してcurrent_userに特定の投稿がブックマークされているかされていないかの判定をするメソッドを記述しています。

後々記述しますが引数の(user)にはcurrent_userが引き渡されています。

インスタンスメソッド...インスタンスに使用するメソッド。

ルーティング設定

routes.rb
resources :boards, shallow: true do
  resource :bookmarks, only: %i[create destroy]
  get :bookmarks, on: :collection
end

ブックマーク一覧ページをboards/bookmarksにルーティンングを設定したいのでcollectionオプションを使用します。
ネスト(入れ子)すると外部キーのboard_idを取得するのに容易になります。
また単数形のメソッドであるresourceとしたのはbookmarkのidが必要ないため。

shallowオプション
参照:resources を nest するときは shallow を使うと幸せになれる

Bookmarkコントローラー作成

ターミナル
$ rails g controller bookmarks create destroy

上記コマンドでbookmarks_controller.rbが作成されます。

bookmarks_controller.rb
class BookmarksController < ApplicationController
  def create
    bookmark = current_user.bookmarks.build(board_id: params[:board_id])
    bookmark.save!
    redirect_to boards_path, success: t('.flash.bookmark')
  end

  def destroy
    current_user.bookmarks.find_by(board_id: params[:board_id]).destroy!
    redirect_to boards_path, success: t('.flash.not_bookmark')
  end

ここの記述でリクエストが送られた際のブックマーク機能を管理しています。

create
bookmark = current_user.bookmarks.build(board_id: params[:board_id])

ここでcurrent_userのBookmarkインスタンスを生成(buildはnewと同じ意味で、アソシエーションしながらインスタンスを作成するときに形式的に使用される模様)

create
bookmark.save!
redirect_to boards_path, success: t('.flash.bookmark')

登録して、リダイレクト先を指定。
success以降はフラッシュメッセージ関連です。

destroy
current_user.bookmarks.find_by(board_id: params[:board_id]).destroy!
redirect_to boards_path, success: t('.flash.not_bookmark')

ここではブックマークしているユーザー情報を取得、ブックマークを解除して、リダイレクト先を指定。

destroysaveではなくdestroy!save!にしているのは条件分岐使わない場合は失敗したときに例外を発生させて処理を終了させるのがベターと見聞きしたのでこの記述にしています。

boards_controller実装

boards_controller.rb
def index
    @boards = Board.all.includes(:user).recent
end

.
.
.

def bookmarks
    @boards = current_user.bookmark_boards.includes(:user).recent
end

今回関係あるのはこの2つのアクションだけなので他は割愛します。
上から見ていきます。

def index
    @boards = Board.all.includes(:user).recent
end

indexアクションでは@boardsインスタンス変数にboardsテーブルから全てのデータを取得しています。

includesはn+1問題解消のため。
参照:Rails「N+1問題」超分かりやすい解説・解決方法【includesを使おう】

recentはScopeを用いて可読性を保つために記述しているもので、掲示板を降順で表示するためのオプションをモデルで設定しています。
今回は関係ないので削除しても問題ありません。

def bookmarks
    @boards = current_user.bookmark_boards.includes(:user).recent
end

bookmarksアクションでは@boardsインスタンス変数にログインしているユーザー(current_user)がブックマークしている全てのデータを取得しています。

current_user.bookmark_boardsこういう書き方でユーザーがブックマークしてる投稿を取得できるのは先ほどhas many throughでリレーションを組んだことによる効果です。

ビュー実装

views/boards/index.html.erb
<div class="row d-flex">
  <%= render @boards %>
</div>

パーシャルを読み込んで

views/boards/_board.html.erb
<% if current_user.own_board?(board) %>
  <div style='display: inline; float: right;'>
    <%= link_to icon('fas', 'pen'), edit_board_path(board), id: :"button-edit-#{board.id}" %>
    <%= link_to icon('fas', 'trash-alt'), board_path(board), id: :"button-delete-#{board.id}",method: :delete, data: { confirm: '削除してよろしいですか?' } %>
  </div>
<% else %>
  <div style='display: inline; float: right;'>
     <%= render 'boards/bookmark_area', board: board %>
  </div>
<% end %>

<% if current_user.own_board?(board) %>で投稿をログインユーザーか他ユーザーかを条件分岐させてます。
own_board?(board)は自身で作成したインスタンスメソッドなので、このままコピペしても動きません。

own_board?メソッド中身はこちら↓
[Rails]ログインidと投稿者が一致した時のみ編集・削除アイコンを表示させる条件式をモデルに書き出す

views/boards/_bookmark_area.html.erb
<% if board.bookmark_by?(current_user) %> 
  <%= render 'boards/bookmark', board: board %>
<% else %>
  <%= render 'boards/unbookmark', board: board %>
<% end %>

bookmark_by?は先ほどboard.rbで定義したブックマーク判定をするインスタンスメソッドです。引数はログインユーザーであるcurrent_userのインスタンスを引き渡しています。

views/boards/_bookmark.html.erb
<%= link_to icon('fas', 'star'), board_bookmarks_path(board.id), method: :delete, id: :"js-bookmark-button-for-board-#{board.id}" %>
views/boards/_unbookmark.html.erb
<%= link_to icon('far', 'star'), board_bookmarks_path(board.id), method: :post, id: :"js-bookmark-button-for-board-#{board.id}" %>

参考記事

【初心者向け】丁寧すぎるRails『アソシエーション』チュートリアル【幾ら何でも】【完璧にわかる】

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】Bookmark機能

備忘録です。

掲示板におけるブックマーク機能追加し、ブックマーク一覧ページを作成。
※初心者です。ご指摘あればお願いします!

環境

Rails 5.2.3
mysql 5.7.28
gem font-awesome-sass
gem Sorcery
→installしていない場合、後述のcurrent_userメソッドが使用できません。

ER図

中間テーブル(Bookmark)使用。
中間テーブル...userとboardのidだけを保存するテーブル。
bookmark_ER図.png

User:Board = 1:多
User:Bookmark = 1:多
Board:Bookmark = 1:多

あくまでブックマーク機能実装の記事ですので、UserとBoardモデルはすでに作成されているものとして進行しますのでご注意ください。

実装

それでは実装していきます。

Bookmarkモデル作成

ターミナル
$ rails g model Bookmark user:references board:references

上記コマンドでbookmark.rb(モデルファイル)とxxxxxxxx_create_bookmarks.rb(マイグレーションファイル)が作成されます。

referencesを指定することで外部キー制約がついてインデックスも貼られるので便利です。

bookmark.rb
belongs_to :user
belongs_to :board
validates :user_id, uniqueness: { scope: :board_id } # 追加

uniqueness: trueでモデルレベルで一意性(ユニーク)を保ちます。
Railsガイドバリデーション

xxxxxxx_create_bookmarks.rb
def change
  create_table :bookmarks do |t|
    t.references :user, foreign_key: true, null: false
    t.references :board, foreign_key: true, null: false

    t.timestamps
    t.index [:user_id, :board_id], unique: true # 追加
  end
end

t.index [:user_id, :board_id], unique: trueと書き足してDBレベルで一意性(ユニーク)を保ちます。

モデルとDB両方に一意性を保つことでより安全性が高まります。
ここでいう一意性とは1人のユーザーが同じ投稿を複数回bookmarkできないようにすることです。

ターミナル
$ rails db:migrate

上記コマンド実行で中間テーブル完成!

UserモデルとBoardモデルのアソシエーション

user.rb
class User < ApplicationRecord
  has_many :boards, dependent: :destroy
  has_many :bookmarks, dependent: :destroy
  has_many :bookmark_boards, through: :bookmarks, source: :board
end

dependent: :destroyでユーザーが削除されたとき、そのユーザーに関連する情報を削除するよう紐付けます。

注目すべきは

has_many :bookmark_boards, through: :bookmarks, source: :board

です。
has many throughオプションでユーザーがブックマークした投稿を直接アソシエーションで取得できます。
後ほどboard_controller.rb実装時に使用しますので、覚えておいてください。

sourceでは参照するモデルを指定しています。

board.rb
class Board < ApplicationRecord
  belongs_to :user
  has_many :bookmarks, dependent: :destroy

# boardのお気に入り判定 → vies側で呼び出し
  def bookmark_by?(user)
    bookmarks.where(user_id: user.id).exists?
  end
end

こちらで注目するのは

def bookmark_by?(user)
  bookmarks.where(user_id: user.id).exists?
end

このインスタンスメソッドです。
ここではbookmark_by?(user)というアクションを明記してcurrent_userに特定の投稿がブックマークされているかされていないかの判定をするメソッドを記述しています。

後々記述しますが引数の(user)にはcurrent_userが引き渡されています。

インスタンスメソッド...インスタンスに使用するメソッド。

ルーティング設定

routes.rb
resources :boards, shallow: true do
  resource :bookmarks, only: %i[create destroy]
  get :bookmarks, on: :collection
end

ブックマーク一覧ページをboards/bookmarksにルーティンングを設定したいのでcollectionオプションを使用します。
ネスト(入れ子)すると外部キーのboard_idを取得するのに容易になります。
また単数形のメソッドであるresourceとしたのはbookmarkのidが必要ないため。

shallowオプションについてはこちら
resources を nest するときは shallow を使うと幸せになれる

Bookmarkコントローラー作成

ターミナル
$ rails g controller bookmarks create destroy

上記コマンドでbookmarks_controller.rbが作成されます。

bookmarks_controller.rb
class BookmarksController < ApplicationController
  def create
    bookmark = current_user.bookmarks.build(board_id: params[:board_id])
    bookmark.save!
    redirect_to boards_path, success: t('.flash.bookmark')
  end

  def destroy
    current_user.bookmarks.find_by(board_id: params[:board_id]).destroy!
    redirect_to boards_path, success: t('.flash.not_bookmark')
  end

ここの記述でリクエストが送られた際のブックマーク機能を管理しています。

create
bookmark = current_user.bookmarks.build(board_id: params[:board_id])

ここでcurrent_userのBookmarkインスタンスを生成(buildはnewと同じ意味で、アソシエーションしながらインスタンスを作成するときに形式的に使用される模様)

create
bookmark.save!
redirect_to boards_path, success: t('.flash.bookmark')

登録して、リダイレクト先を指定。
success以降はフラッシュメッセージ関連です。

destroy
current_user.bookmarks.find_by(board_id: params[:board_id]).destroy!
redirect_to boards_path, success: t('.flash.not_bookmark')

ここではブックマークしているユーザー情報を取得、ブックマークを解除して、リダイレクト先を指定。

destroysaveではなくdestroy!save!にしているのは条件分岐使わない場合は失敗したときに例外を発生させて処理を終了させるのがベターと見聞きしたのでこの記述にしています。

boards_controller実装

boards_controller.rb
def index
    @boards = Board.all.includes(:user).recent
end

.
.
.

def bookmarks
    @boards = current_user.bookmark_boards.includes(:user).recent
end

今回関係あるのはこの2つのアクションだけなので他は割愛します。
上から見ていきます。

def index
    @boards = Board.all.includes(:user).recent
end

indexアクションでは@boardsインスタンス変数にboardsテーブルから全てのデータを取得しています。

includesはn+1問題解消のため。
Rails「N+1問題」超分かりやすい解説・解決方法【includesを使おう】

recentはScopeを用いて可読性を保つために記述しているもので、掲示板を降順で表示するためのオプションをモデルで設定しています。
今回は関係ないので削除しても問題ありません。

def bookmarks
    @boards = current_user.bookmark_boards.includes(:user).recent
end

bookmarksアクションでは@boardsインスタンス変数にログインしているユーザー(current_user)がブックマークしている全てのデータを取得しています。

current_user.bookmark_boardsこういう書き方でユーザーがブックマークしてる投稿を取得できるのは先ほどhas many throughでリレーションを組んだことによる効果です。

ビュー実装

views/boards/index.html.erb
<div class="row d-flex">
  <%= render @boards %>
</div>

パーシャルを読み込んで

views/boards/_board.html.erb
<% if current_user.own_board?(board) %>
  <div style='display: inline; float: right;'>
    <%= link_to icon('fas', 'pen'), edit_board_path(board), id: :"button-edit-#{board.id}" %>
    <%= link_to icon('fas', 'trash-alt'), board_path(board), id: :"button-delete-#{board.id}",method: :delete, data: { confirm: '削除してよろしいですか?' } %>
  </div>
<% else %>
  <div style='display: inline; float: right;'>
     <%= render 'boards/bookmark_area', board: board %>
  </div>
<% end %>

<% if current_user.own_board?(board) %>で投稿をログインユーザーか他ユーザーかを条件分岐させてます。
own_board?(board)は自身で作成したインスタンスメソッドなので、このままコピペしても動きません。
<% current_user == board.board.id %>で上記判断ができると思います。

views/boards/_bookmark_area.html.erb
<% if board.bookmark_by?(current_user) %> 
  <%= render 'boards/bookmark', board: board %>
<% else %>
  <%= render 'boards/unbookmark', board: board %>
<% end %>

bookmark_by?は先ほどboard.rbで定義したブックマーク判定をするインスタンスメソッドです。引数はログインユーザーであるcurrent_userのインスタンスを引き渡しています。

views/boards/_bookmark.html.erb
<%= link_to icon('fas', 'star'), board_bookmarks_path(board.id), method: :delete, id: :"js-bookmark-button-for-board-#{board.id}" %>
views/boards/_unbookmark.html.erb
<%= link_to icon('far', 'star'), board_bookmarks_path(board.id), method: :post, id: :"js-bookmark-button-for-board-#{board.id}" %>

参考記事

【初心者向け】丁寧すぎるRails『アソシエーション』チュートリアル【幾ら何でも】【完璧にわかる】

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Linuxサーバからリモートリポジトリにpush & リモートリポジトリからローカルPCにclone

目標
  • linuxサーバ上で運用されているrailsアプリのソースコードをGitlab.comのリモートリポジトリにプッシュする。
  • リモートリポジトリからローカルPCのローカルリポジトリにクローンする。
環境
  • linux(GCE, Debian)
  • Gitlab.com
  • Mac(OSX 10.15.2)
準備:git install (linuxサーバ、ローカルPCにGitをインストール)

下記サイトなどを参考にしてください。
https://git-scm.com/book/ja/v2/%E4%BD%BF%E3%81%84%E5%A7%8B%E3%82%81%E3%82%8B-Git%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB

1. linuxの操作
git config(USER_NAMEとEMAILは環境による)
ターミナル
git config --list
git config --global user.name "USER_NAME"
git config --global user.email "EMAIL"
ファイル権限(USERNAMEとUSERGROUPは環境による)

権限を間違えるとgit push時に権限エラーになります。

ターミナル
sudo chown -R USERNAME:USERGROUP ./
sudo find ./ -type d -exec chmod 755 {} +
sudo find ./ -type f -exec chmod 644 {} +
SSH鍵(gitlab_rsaは好きな名前をつける)
  • 秘密鍵は~/.ssh/に置いてください。
  • .pubの内容をGitlab.comのユーザーのssh鍵に貼り付けてください。
ターミナル
ssh-keygen -t rsa -f gitlab_rsa

mv ./gitlab_rsa ~/.ssh/
mv ./gitlab_rsa.pub ~/.ssh/
cat gitlab_rsa.pub 
=>.pubの内容をGitlab.comに貼り付け

eval $(ssh-agent -s)

ssh-add ~/.ssh/gitlab_rsa

ssh -T git@gitlab.com
git init ~ git pushまで(:repoは環境による)

gitコマンドの詳細の説明は省略します。
サーバのローカルリポジトリを初期化+初期コミットして、リモートリポジトリにプッシュしています。

ターミナル
git init

vi .gitignore 
=>rails用のテンプレートから持ってくるとラク

git add .

git commit .

git remote add origin git@gitlab.com:repo

git push origin master
2. ローカルPC操作
プロジェクト用ディレクトリ作成(好きな名前のディレクトリを作成する)
ターミナル
mkdir Gitlab
SSH鍵(gitlab_rsa_userは好きな名前をつける)
  • 秘密鍵は~/.ssh/に置いてください。
  • .pubの内容をGitlab.comのユーザーのssh鍵に貼り付けてください。
ターミナル
ssh-keygen -t rsa -f gitlab_rsa_user

mv gitlab_rsa_user ~/.ssh/

mv gitlab_rsa_user.pub  ~/.ssh/

cat gitlab_rsa_user.pub
=>Gitlabに貼り付け

eval $(ssh-agent -s)

ssh-add ~/.ssh/gitlab_rsa_user

ssh -T git@gitlab.com
git config(USERNAMEとEMAILは環境による)

リモートリポジトリからローカルPCのローカルリポジトリにクローンしています。

ターミナル
git config --global user.name "USERNAME"
git config --global user.email EMAIL
git clone(/repo.gitは環境による)
ターミナル
git clone https://gitlab.com/repo.git
bundle ~ rails sまで

ローカルPCにクローンしてきたディレクトリでbundleとrails sが実行可能か確認する。
サーバ環境と同じrubyバージョン、railsバージョンで実行すると環境依存のエラーを回避できる。
rbenvを使用するとプロジェクトディレクトリ毎にrubyバージョンを指定できるのでラク。
windowsでrbenvを使用する場合は、wslを有効化してubuntuターミナル上で作業する。
参考:
https://qiita.com/chimame/items/8130aa2c07a152a865b1

エラーが出たらエラーメッセージを読んで不足するファイルをサーバから直接持ってくる。
(.gitignoreで指定したファイルはgit管理から外れるため。)

ターミナル
bundle

rails s
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

application_helperを使う

長くてみにくかったviewの記述をapplication_helper.rbに移動させてcontent_tagと言うものを使ってhtmlタグを生成する

content_tagについて
参考: https://qiita.com/yusaku_/items/d6e98b77124131e628fb

rails/app/helpers/try_helper.rb
  def discount_text(service, provider)
    discount_price = provider.key == "noe-jx-group" ? service['discount'].to_f : service['discount'].to_i
    discount_from_energy = if SetPlan.is_discount_from_energy?(service)
      "/kWh"
    elsif SetPlan.yearly?(service)
      "/年"
    elsif SetPlan.monthly?(service)
      "/月"
    end
    content_tag(:div, class: "e__saving") do
      content_tag(:span, "割引額", class: "e__tag") + content_tag(:span, discount_price, class: "e__number e__deals" ) + "円" + discount_from_energy
    end
  end
rails/app/views/try/_set_discount.html.erb
 // 修正前
<div class="e__saving"><span class="e__tag">割引額</span><span class="e__number e__deals"><%= service['discount'].to_i %></span>円<% if SetPlan.is_discount_from_energy?(service) %>/kWh<% elsif SetPlan.monthly?(service) %>/月<% elsif SetPlan.yearly?(service) %>/年<% end %></div>

// 修正後(とっても短くなった!)
<%= discount_text(service, @provider) %>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【学習まとめ】 Railsアプリケーションのテスト

なぜテストですか。

ソフトウェア開発の仕事は、機能しているコードを書くことと思います。

問題は、正確さをどうやって確保できるのか

一つの方法は、コードを書いた後で、実行してみます。この方法は、小さいプロジェクトに対して効果がありますが、ある時点で機能が多すぎて追跡できません。新しいコード(フィーチャー)を追加すると、他のコードが予期せず壊れてしまいます。これは、regression(リグレックション)と呼ばれています。

より良い方法があり、自動テストです。コードで作成したコードを自動的にテストしてもらいます。自動テストは、私たちのプログラムが機能していること、そして今後も機能して続いていることを確認します。

お金や時間の節約

自動テストは、バグをより早く発現し、本番に不正な状態を展開されるのを防ぎます。

コードに自信がある

良いテストがあると、

何か壊すことを恐れことなく、コードに大きな変更を加えることができます。
金曜日の午後でも、リリースする自信があります。

より良いドキュメント

ドキュメントは、コードを更新するとフルいくなります。テストは、いつもコードによって更新しなければならないものである。

TDD(テスト駆動開発)

TDDは、テストを利用してアプリケーションの設計や開発の推進するプロセスである。
Red, Green, Refactorと呼ばれているサイクルから始めます。

tdd-cycle.png

Red

最初に、適用する予定のメソッドやロジックのテストを先に書きます。この時点でコードはどのように見えるかを知る必要がありません、それが何をするかを知るだけで十分です。

テストを実行すると、失敗するはずです。(テストがRed色になります)

Green

失敗するテストから、エラーメッセじを読んで、コードを書きます。この時点、テストを合格するのに十分なコードを書くだけです。コードの品質に焦点を合わせなくていいです。

Refactor

コードをクリーンニングし、複数なコードを削除する。アプリケーションのコードではなくテストコードもします。

コードに何か変更しても壊れない自信があるまでします。

TDDアプローチ

Outside-In Development

アウトサイド ・イン開発は、最初は最高レベルアブストラクション(抽象化)から始めます。というのは、ユーザがブラウザ(UI)を操作し、ページ上の要素と対話する観点である。これは、受け入れテストと呼ばれています。

受け入れテストが緑色になったら、よりコードを記述する必要はありません。

Inside-Out Development

時々、最終のソリューションがどのように見えるかわからない場合、インサイド・アウト開発はお勧めします。コンポーネントごとを構築します。

テスト駆動とテストファースト

最初にテストを書くだけで、テスト駆動と呼ばれているのは違います。

赤、緑、リファクタリングのサイクルに沿って、失敗テストに対して必要なコードのみを記述することは重要です。これにより、ソリューションのスコープ外の設計、テストされていない機能を実装しなくなります。

また、リファクタリングのスッテプをスキップしないことも重要です。これは、TDDの最も重要な部分の一つであります、コードを保守しやすく、将来変更しやすいくようにします。

TDDの利点

  • Confidence(自信)
  • Time Savings(時間節約)
  • Flow(フロー)
  • Improved Design(設計の改善)

TDDしない時(実用的)

  • アプリケーションが小さい、変更が少ない(ほとんどない)
  • 短い時間で利用するつもりであるプログラム
  • アプリケーションの重要性が低い、壊れても影響がない

効果的なテストスイートの特性

  • 速度 (speed)
  • 完成度 (complete)
  • 信頼性ある (reliable)
  • 孤立 (isolated)
  • 保守可能 (maintainable)

テストタイプ

テストパイラミッド

Refs

testing-rails/testing-rails.md at master · thoughtbot/testing-rails · GitHub

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pay.jpとRailsで決済機能実装してみた。

投稿経緯

payjpの実装記事そのものはたくさんあるのですが、hamlで書かれてるのがほとんど。
正直僕はまだslimhamlのような短縮系での書き方がわからず手間取ったので、今回通常盤での記載で投稿しようと思いました。

実装

APIキー取得

スクリーンショット 2020-01-07 15.35.24.png

1. Payjpにログイン

https://pay.jp/login
※アカウントがなければ↑からも作成可能。

2. ログイン後APIをクリック

クリック後が写真の画面になります。
大事な情報になるので、基本的には第三者に見せないようにしましょう。

gemの導入

1.Gemfileに記載する。

Gemfile
# 決済
gem 'payjp'
2.インストール
ターミナル
bundle install

コントローラー

1.決済情報アクションを作成
pays.controller.rb
 def index
 end

 def pay
    Payjp.api_key = 'sk_test_c6a7dfaf173ad9733cd904e9'
    Payjp::Charge.create(
      #amountは値段を記載
      amount: 3500, 
      card: params['payjp-token'],
      currency: 'jpy'
    )
  end

ActionController::InvalidAuthenticityTokenが出た場合

protect_from_forgery except: :payを一番上に記載してください。
有効ではないトークンみたいな感じで弾いてしまうみたいなので、
例外としてpayアクションを指定して通すようにします。

pays.controller.rb
 protect_from_forgery except: :pay

 def index
 end

 def pay
    Payjp.api_key = 'sk_test_c6a7dfaf173ad9733cd904e9'
    Payjp::Charge.create(
      #amountは値段を記載
      amount: 3500, 
      card: params['payjp-token'],
      currency: 'jpy'
    )
  end

View

1.Payjoが用意しているUIを使用する

data-keyの箇所は先ほどのPayjpのAPIに記載されいるものを入れる。
※今回は簡単な導入方法になりますので、セキュリティー面では直かきはよくないみたいなので、本番でやる場合は違う場所書いて参照するようにお願いします。

index.html.erb
<h1>決済画面</h1>
<form action="/pay" method="post">
  <script src="https://checkout.pay.jp/" class="payjp-button" data-key="テスト公開鍵"></script>
</form>

2.トークン

トークンを作成するために必要なものになりますので、indexの一番下に書きます。

index.html.erb
<script>
  $(document).on('turbolinks:load', function() {
      var form = $("#charge-form");
      Payjp.setPublicKey('pk_test_0383a1b8f91e8a6e3ea0e2a9');

      $("#charge-form").on("click", "#submit-button", function(e) {
        e.preventDefault();
        form.find("input[type=submit]").prop("disabled", true);
        var card = {
            number: parseInt($("#payment_card_no").val()),
            cvc: parseInt($("#payment_card_security_code").val()),
            exp_month: parseInt($("#payment_card_expire_mm").val()),
            exp_year: parseInt($("#payment_card_expire_yy").val())
        };
        Payjp.createToken(card, function(s, response) {
          if (response.error) {
            alert("error")
            form.find('button').prop('disabled', false);
          }
          else {
            $(".number").removeAttr("name");
            $(".cvc").removeAttr("name");
            $(".exp_month").removeAttr("name");
            $(".exp_year").removeAttr("name");

            var token = response.id;
            $("#charge-form").append($('<input type="hidden" name="payjp_token" class="payjp-token" />').val(token));
            $("#charge-form").get(0).submit();
          }
        });
      });
    });
</script>

ルーティング

今回はわかりやすく/payだけのURLで作成します。
変更する場合はindex.html.erbのformのaction="~"で場所を買えてください

config/routes.rb
post '/pay', to: 'pays#pay'

完成

index.html.erbにカードで支払うボタンが出てるのそれをクリック
スクリーンショット 2020-01-07 16.11.03.png
すると入力フォームが出現しますので、記入してカードで支払うボタンをクリック

すると元のページへリダイレクトするので、次はpayjpに移動
スクリーンショット 2020-01-07 16.13.23.png
サイドバーの売上をクリックすると
先ほどの金額で支払済みと確認できましたね。

まとめ

今回はかなり簡略的に書きましたので、これをもとに各々に合わせた形にアレンジしていっていただけたらと思いまいす。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

画像ファイルについてしまった[ ]を取り除く

はじめに

画像ファイルを複数登録するときに、multipleを使うと簡単に実装できます。
が、(自分の環境だけなのか)保存されるデータに含まれる画像ファイル名に
[ ]がついてしまい、実際に保存されている画像ファイル名を齟齬が生じ
エラーとなる自体が発生していました。
そこで、Model側にこれを取り除くメソッドを追加しましたが、同じような環境で
困っている方はご利用ください
最近、某プログラミングスクールではこれの影響なのかmultipleを使わないようにと
御達しが出たようですね。

前提条件

ItemモデルはImagesを複数持つアソシエーションが組まれていること

コード

app/models/image.rb
class Image < ApplicationRecord
  belongs_to :item, optional: true
  validates_presence_of :item
  mount_uploaders :image_url, ImageUploader

  def image_path
    return '' if self.image_url[0].try(:file).nil?
    if Rails.env.production?
      self.image_url[0].url.gsub(/%5B%22/, "").gsub(/%22%5D/, "")
    else
      self.image_url[0].file.file.sub(/.*public/,'').sub(/\["/,'').sub(/"\]/,'')
    end 
  end
end

今回はS3に画像を保存するようにしており、本番環境とローカルでは指定する画像パスが異なってくるので
production?を使って分岐させています。

使い方

app/controllers/items_controller.rb
 def show
    @item = Item.find_by(id: params[:id])
    @image_path = @item.images.map{|img| img.image_path}
 end

paramsで渡されたidのアイテムを@itemに格納し、@itemのimagesに対して
modelで作成したimage_pathメソッドを実行して[ ]を削除したパスを@image_path
格納して使えるようにします。
あとはビュー側でimage_tagに@image_path[n]とすれば格納したパスを
取り出すことができます。@image_pathは配列になっていることに注意です。

おわりに

細かいことですが、私は最初Controllerに[ ]を取り除く処理を書いていましたが、メンバーが
MVCモデルの法則に則ってModelにメソッドを書き直してくれました。
開発の基準をしっかりと把握していないと他のメンバーに迷惑をかけてしまいますね・・・猛省

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

haml-railsでerbファイルをhamlに変換する方法

個人アプリ開発において新しく立ち上げる度に何度も調べてしまうので備忘録として残す。

結論

このgemをGemfileに記述

Gemfile
gem "haml-rails"

bundle installを実行

ターミナル
$ bundle install #bundle でも可

下記コマンドを実行し、erbファイルをhamlに変換。

ターミナル
$ rails haml:erb2haml

元のerbファイルを削除するかどうかを聞かれる。不要な場合はyを選択。

ターミナル
Would you like to delete the original .erb files? (This is not recommended unless you are under version control.) (y/n)
y
Deleting original .erb files.
--------------------------------------------------------------------------------
Task complete!
No .erb files found. Task will now exit.

hamlで開発を行う事の利点とは

hamlはdivタグ自体を書く必要がなく、また各タグを閉じる必要もない為、コード量の削減、簡略化ができる。rubyも使用可。
インデントによる管理である事から、誰が書いても似たような構造になり、可読性が高い。
逆にインデントが少しでもずれるとすぐエラーを吐くため慣れるまでが大変。

rails newを叩く際にデフォルトで生成されるerbファイルはhtmlとほとんど同じ記述で書けて且つ、rubyも実行できる。
ただhamlと違いタグ1つ1つに対しての閉じタグが必要になる為、コードが冗長になりやすい。
学習し始めのうちは視覚的に理解しやすいので使うのも有り。

まとめ

爆速で開発を行いたいのであれば時間が掛かっても少しずつhamlに慣れていくのが良いであろう。
似たような書き方でslimというのもあるが、基本的な書き方はhamlと変わらず、2020年1月現在ではhamlの方が若干使用比率が高いようなので、現場に合わせ必要に応じて学ぶと良いのではないだろうか。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】resourcesメソッド

config/routes.rb
Rails.application.routes.draw do
  # 追記する
  resources :blogs
end

$ rails routes

Prefix    Verb   URI Pattern               Controller#Action
blogs     GET    /blogs(.:format)          blogs#index
          POST   /blogs(.:format)          blogs#create
new_blog  GET    /blogs/new(.:format)      blogs#new
edit_blog GET    /blogs/:id/edit(.:format) blogs#edit
 blog     GET    /blogs/:id(.:format)      blogs#show
          PATCH  /blogs/:id(.:format)      blogs#update
          PUT    /blogs/:id(.:format)      blogs#update
          DELETE /blogs/:id(.:format)      blogs#destroy
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Mix-inはやめてくれ。「関数的モジュール」だ!

TL;DR

  • Mix-inは危険な機能だ
  • Mix-inは必要なシーンにだけ使おう
  • 関数だけを提供するだけのモジュールを作るのが、弊害が少なくシンプル

Mix-in は弊害が多い

Mix-inはRubyの基本的な機能であり、入門書でも序盤で紹介されます。

それゆえか単に処理をクラス間で共有するためだけにMix-inを使おうとしているのをしばしば見かけます。

実際には、Mix-inにはうかつに使うと後々痛い目に会う機能であり、大抵のケースではMix-inを使うのは適切ではありません

落とし穴1: インスタンス変数やメソッドが上書きされる

includeがやっているのは、「単にMix-inのメソッドをクラスにコピーする」ことだけです1

なので同じ名前のメソッドをクラス側で定義すると、Mix-inのメソッドを警告なしに上書きしてしまいます。同様にMix-inのインスタンス変数を、クラス側で参照したり変更したりできてしまいます。

module HttpRequestable
  def get(uri)
    request(:get, uri)
  end

  private

  def request(http_method, uri)
    # HTTPリクエストする処理
  end
end

class StoreAPI
  include HttpRequestable

  ...

  # 商品の入荷をリクエストする機能を追加しよう!
  # (実はHttpRequestableのメソッドを上書きしてしまっている)
  def request(product_id, count)
  end
end

落とし穴2: メソッドの関係が複雑になる

クラスからMix-inのメソッドを呼び出せるだけでなく、Mix-inからクラスのメソッドを呼び出したり、Mix-inから別のMix-inのメソッドを呼び出すことができるため、

クラスのメソッド => Mix-in Aのメソッド => Mix-in Bのメソッド => クラスのメソッド => ...

のような複雑な参照関係が生じてしまうことがあります。

呼び出しが適切に管理されていればTemplate Method パターンと呼べるのですが、

おっ、親クラスの〇〇っていうメソッドを呼べば動かせるぞ。よし!!

と、深く考えずに呼んでしまうことが、稀によくあります。

落とし穴3: メソッドの定義場所が分かりにくい

最近はIDEが良くなったので問題になりにくいのですが、includeするモジュールが増えてくると、メソッドの定義箇所がわかりにくくなりがちです。

RailsのActionMailer::Baseには12個のモジュールがincludeされているのですが、この中からrelative_url_rootの定義箇所をIDEなしで見つけるのは一苦労です。

落とし穴4: 確信が持てない

最大の問題は、上記のような落とし穴を踏んでいないか確信を持てないことです。Rubyは動的言語なので、静的なチェックが難しく、

これは private メソッドだから、変更しても安全だな!!

と思っていたら、実はMix-inで誤って呼び出していないとも限らないのです。

そこで「関数的モジュール」

(以下の「関数的モジュール」は私の造語です。もっと適切な用語があるのかもしれませんが、調べ方が悪いのか見つからなかったので、ここでは「関数的モジュール」と呼びます)

関数的モジュールとは、特異メソッドだけを提供するモジュールのことです。

module HttpRequestable
  class << self
    def get(uri)
      request(:get, uri)
    end

    private

    def request(http_method, uri)
      # HTTPリクエストする処理
    end
  end
end

使うときは、includeせずメソッドを直接呼び出します。

class StoreApi
  # メソッド名が被っても大丈夫!!
  def request 
    HttpRequestable.get(uri)
  end
end

関数的モジュールでは、Mix-inのような問題は起きません。

  • インスタンス変数を使わない(使えない2
  • メソッドがコピーされることが無い
  • クラス側のメソッドを呼び出すことがない(できない)
  • どのモジュールのメソッドを呼んでいるかは明らか

それでもMix-in を使うケース

そうはいっても、Mix-inを定義するのが便利なケースもあります。

Mix-inを定義する際にはTemplate Method パターンとして正しく定義することを心がけましょう。

具体的には・・・

  • Mix-inがクラスのどのメソッドを呼ぶか明らかにする
  • クラスからはMix-inのどのメソッドを呼んでよいのか明らかにする
  • インスタンス変数を避ける
  • privateメソッドを避ける(RubyのprivateはC++やJavaのprivateと異なることに気をつける)

  1. 掘り下げるともっと複雑でしょうが、基本的な理解としては、「メソッドをコピーするだけ」。 

  2. インスタンス変数を使うこともできるが、Mix-inとは振る舞いが異なるので、Mix-inでのような問題は起きません。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Deviseを使ってController側からログアウトさせる

1. 経緯

userテーブルにflgを持たせて、0以外の人はログインさせたくないなぁ・・・
ということで調べてみたところ以下の内容でできました:raised_hands:

2. 結果

appllication_controller.rb
  before_action :sign_out_user,  if: :user_signed_in?
  protected
    # ログイン後のパス
    def after_sign_in_path_for(resource)
      root_path
    end
    # flgが0以外はログアウトさせる
    def sign_out_user
      sign_out_and_redirect(current_user) if current_user.flg == 0
    end

3. 詳しい内容

4. ネットの記事

ネットの記事見てると以下の内容とかもあったんですが、サインアウトはHTTPリクエストからしか
受け付けないみたいで以下の書き方をしてもダメでした・・・。

redirect_to :controller=>"user/sessions", :action=>"destroy"

4. 最後に

いいね!もらえると励みになるのでよろしくお願いします!:v:

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

emun のform select対応 実際に使えたもの

上記ものもを日本語対応させたい場合、下のように書く

<%= form.select :status, Post.statuses.keys,class:"form-control" %>
<%= form.select :status, Post.statuses.keys.map {|k| [I18n.t("enums.post.status.#{k}"), k]} ,class:"form-control" %>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

条件付きバリデーション(特定の状況においてバリデーションを発生させる方法)

実現したいこと

PostモデルのFormにてGenreモデルのnameはuniquenessかつnameは空でもバリデーションに引っかからないようにしたい。そして空のデータは表示させたくない。

整理すると、
1. カラムはuniqueness、しかしカラムが空であった場合でもデータ送信ができる。
2. 空の状態を保存したものは出現させない。

課題
カラムが空であった場合データ送信ができる=空の場合uniquenessのバリデーションには引っかからないようにする。

解決策
条件付きバリデーションを作成する

前提

新規投稿を作るformに置いてPostモデルとGenreモデルの2つのデータ送信を同時に行いたい。

Formの一部(ここでPostモデルのFormでGenreモデルのデータも同時に送信)

<%= fields_for @genre, :genres do |form| %>
        <%= form.label :新しくジャンルを作る %>
        <%= form.text_field :name, class:"form-control" %>
      <% end %>

Form全体

<div class="container">
  <%= form_with(model: [:mypage, post], local: true) do |form| %>
    <% if post.errors.any? %>
      <div id="error_explanation">
        <h2><%= pluralize(post.errors.count, "error") %> prohibited this post from being saved:</h2>

        <ul>
          <% post.errors.full_messages.each do |message| %>
            <li><%= message %></li>
          <% end %>
        </ul>
      </div>
    <% end %>
    <div class="form-group">
      <%= form.text_field :title, class:"form-control", placeholder:"タイトル" %>
    </div >
    <div class="form-group">
      <%= form.text_area :body, class:"form-control", placeholder:"自分の辞書をマークダウン記法で記入してみよう" %>
    </div>

    <div class="field">
      <%= form.label :status %>
      <%= form.select :status, Post.statuses.keys,class:"form-control" %>
    </div>

    <div class="field">
      <%= form.label :posted_at %>
      <%= form.datetime_select :posted_at %>
    </div>

    <div class="form-group">
      <%= form.text_area :reason, class:"form-control", placeholder:"メモした経緯を書いてみよう" %>
    </div>

    <div class="field">
      <%= form.label :rank %>
      <%= form.select :rank, Post.ranks.keys, class:"form-control" %>
    </div>

    <div class="form-group">
      <%= form.label :summary %>
      <%= form.text_field :summary, class:"form-control" %>
    </div>

    <div class="form-group">
      <%= form.label :URL %>
      <%= form.text_field :url, class:"form-control" %>
    </div>

    <%= form.label :genre, 'ジャンル' %>
      <%= form.collection_check_boxes(:genre_ids, current_user.genres.where.not(name:""), :id, :name) do |genre| %>
        <%= genre.label do %>
          <%= genre.check_box %>
          <%= genre.text %>
        <% end %>
      <% end %><br>
      <%= fields_for @genre, :genres do |form| %>
        <%= form.label :新しくジャンルを作る %>
        <%= form.text_field :name, class:"form-control" %>
      <% end %>

    <div class="actions">
      <%= form.submit class:"btn btn-info" %>
    </div>
  <% end %>
</div>


Genreモデルでの条件付きバリデーションの作成
これによってから以外でuniquenessが発動するようになった

validates :name, uniqueness: true, unless: :name_check?
def name_check?
    return true if self.name == ""
  end

空は表示させない
where.not

<%= form.collection_check_boxes(:genre_ids, current_user.genres.where.not(name:""), :id, :name) do |genre| %>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ruby: 個人でよく使うtrue falseを返す正規表現の書き方

※備忘録

半角小文字の英文字かどうかを判定

/\A[a-z]+\z/.match?("kaye")
=> true

半角大文字の英文字かどうかを判定

/\A[A-Z]+\z/.match?("KAYE")
=> true

半角数字かどうかを判定

/\A[0-9]+\z/.match?("21")
=> true

半角英文字と半角数字かどうかを判定

/\A[a-zA-Z0-9]+\z/.match?("kayeN21")
=> true

半角英文字と半角数字かどうかを判定

/\A[a-zA-Z0-9]+\z/.match?("kayeN21")
=> true

半角英文字と半角数字と特定の記号のみを許容する判定

/\A[a-z0-9[.][_]]+\z/.match?("kaye.nr")
=> true

適宜暇なときに追記していきます。
なお、こんな書き方の方がいいよとかがあればご教示いただけると嬉しいです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

serverが起動せず"Usage: rails new APP_PATH [options]..."となってしまう場合の解決法[Ruby on Rails]

経緯

私がRailsの環境を構築する際「Rails s」でサーバーが起動しなかったが解決に至ったためここに記載したいと思う。
投稿に至った経緯は以下の通り。

  • Web上で私と同じように悩んでいる方が多く、またほとんどの記事において解決に至っていなかったため。

  • 該当する記事がそうないように感じたため。

  • 同じ状況に陥っている同志の助けになりたいと考えたため。

陥った状況

  1. 前提として使用OSは Windows10
  2. コマンドプロンプトでrails sを実行すると「Usage: rails new APP_PATH [options] ...(以下省略)」が表示されてサーバが起動できていない。
  3. Ruby、SQLite、Ruby on Railsはインストールされている。
  4. rails new プロジェクト名を実行済み ( 新しいrailsプロジェクトを生成するコマンド )
  5. cd プロジェクト名を実行済み ( プロジェクトのrootに移動するコマンド )

詳細な状況

  • 本来はrails sを実行した際、下記のようになればよい。
C:¥Users¥leone> rails s
=> Booting Puma
=> Rails 5.2.4.1 application starting in development
=> Run `rails server -h` for more startup options
*** SIGUSR2 not implemented, signal based restart unavailable!
*** SIGUSR1 not implemented, signal based restart unavailable!
*** SIGHUP not implemented, signal based logs reopening unavailable!
Puma starting in single mode...
* Version 3.12.2 (ruby 2.6.4-p104), codename: Llamas in Pajamas
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://localhost:3000
Use Ctrl-C to stop
  • しかし問題の状態では下記のようになってしまう。
C:¥Users¥leone> rails s
Usage:
  rails new APP_PATH [options]

Options:
      [--skip-namespace], [--no-skip-namespace]            # Skip namespace (affects only isolated applications)
  -r, [--ruby=PATH]                                        # Path to the Ruby binary of your choice
                                                           # Default: C:/Ruby26-x64/bin/ruby.exe
  -m, [--template=TEMPLATE]                                # Path to some application template (can be a filesystem path or URL)
  -d, [--database=DATABASE]                                # Preconfigure for selected database (options: mysql/postgresql/sqlite3/oracle/frontbase/ibm_db/sqlserver/jdbcmysql/jdbcsqlite3/jdbcpostgresql/jdbc)
                                                           # Default: sqlite3
      [--skip-yarn], [--no-skip-yarn]                      # Don't use Yarn for managing JavaScript dependencies
      [--skip-gemfile], [--no-skip-gemfile]                # Don't create a Gemfile
  -G, [--skip-git], [--no-skip-git]                        # Skip .gitignore file
      [--skip-keeps], [--no-skip-keeps]                    # Skip source control .keep files
  -M, [--skip-action-mailer], [--no-skip-action-mailer]    # Skip Action Mailer files
  -O, [--skip-active-record], [--no-skip-active-record]    # Skip Active Record files
      [--skip-active-storage], [--no-skip-active-storage]  # Skip Active Storage files
  -P, [--skip-puma], [--no-skip-puma]                      # Skip Puma related files
  -C, [--skip-action-cable], [--no-skip-action-cable]      # Skip Action Cable files
  -S, [--skip-sprockets], [--no-skip-sprockets]            # Skip Sprockets files
      [--skip-spring], [--no-skip-spring]                  # Don't install Spring application preloader
      [--skip-listen], [--no-skip-listen]                  # Don't generate configuration that depends on the listen gem
      [--skip-coffee], [--no-skip-coffee]                  # Don't use CoffeeScript
  -J, [--skip-javascript], [--no-skip-javascript]          # Skip JavaScript files
      [--skip-turbolinks], [--no-skip-turbolinks]          # Skip turbolinks gem
  -T, [--skip-test], [--no-skip-test]                      # Skip test files
      [--skip-system-test], [--no-skip-system-test]        # Skip system test files
      [--skip-bootsnap], [--no-skip-bootsnap]              # Skip bootsnap gem
      [--dev], [--no-dev]                                  # Setup the application with Gemfile pointing to your Rails checkout
      [--edge], [--no-edge]                                # Setup the application with Gemfile pointing to Rails repository
      [--rc=RC]                                            # Path to file containing extra configuration options for rails command
      [--no-rc], [--no-no-rc]                              # Skip loading of extra configuration options from .railsrc file
      [--api], [--no-api]                                  # Preconfigure smaller stack for API only apps
  -B, [--skip-bundle], [--no-skip-bundle]                  # Don't run bundle install
      [--webpack=WEBPACK]                                  # Preconfigure for app-like JavaScript with Webpack (options: react/vue/angular/elm/stimulus)

Runtime options:
  -f, [--force]                    # Overwrite files that already exist
  -p, [--pretend], [--no-pretend]  # Run but do not make any changes
  -q, [--quiet], [--no-quiet]      # Suppress status output
  -s, [--skip], [--no-skip]        # Skip files that already exist

Rails options:
  -h, [--help], [--no-help]        # Show this help message and quit
  -v, [--version], [--no-version]  # Show Rails version number and quit

Description:
    The 'rails new' command creates a new Rails application with a default
    directory structure and configuration at the path you specify.

    You can specify extra command-line arguments to be used every time
    'rails new' runs in the .railsrc configuration file in your home directory.

    Note that the arguments specified in the .railsrc file don't affect the
    defaults values shown above in this help message.

Example:
    rails new ~/Code/Ruby/weblog

    This generates a skeletal Rails installation in ~/Code/Ruby/weblog.

原因

"Usage: rails new APP_PATH [options]"が表れるということは考えられることはアプリケーションがないことが原因と考えられますが、前提としてrails new プロジェクト名cd プロジェクト名は実行されているはずです。

そこから察するに、実行はされたが何らかが原因で生成されたプロジェクトが認識されてないのではないかと考えました。ではなぜ認識されないのか考えたところ、予想としてrails new プロジェクト名で生成されるファイルが足りないのではないかと考えたため、私はプロジェクトとして生成されたディレクトリ内を確認したのです。すると予想は的中し明らかにファイルが足りなかったのでした。

下記は本来、プロジェクト生成時に生成されるはずのファイル、またはその処理

C:¥Users¥leone> rails new アプリケーション名
      create
      create  README.md
      create  Rakefile
      create  .ruby-version
      create  config.ru
      create  .gitignore
      create  Gemfile
         run  git init from "."
Initialized empty Git repository in C:/Users/leone/アプリケーション名/.git/
      create  package.json
      create  app
      create  app/assets/config/manifest.js
      create  app/assets/javascripts/application.js
      create  app/assets/javascripts/cable.js
      create  app/assets/stylesheets/application.css
      create  app/channels/application_cable/channel.rb
      create  app/channels/application_cable/connection.rb
      create  app/controllers/application_controller.rb
      create  app/helpers/application_helper.rb
      create  app/jobs/application_job.rb
      create  app/mailers/application_mailer.rb
      create  app/models/application_record.rb
      create  app/views/layouts/application.html.erb
      create  app/views/layouts/mailer.html.erb
      create  app/views/layouts/mailer.text.erb
      create  app/assets/images/.keep
      create  app/assets/javascripts/channels
      create  app/assets/javascripts/channels/.keep
      create  app/controllers/concerns/.keep
      create  app/models/concerns/.keep
      create  bin
      create  bin/bundle
      create  bin/rails
      create  bin/rake
      create  bin/setup
      create  bin/update
      create  bin/yarn
      create  config
      create  config/routes.rb
      create  config/application.rb
      create  config/environment.rb
      create  config/cable.yml
      create  config/puma.rb
      create  config/storage.yml
      create  config/environments
      create  config/environments/development.rb
      create  config/environments/production.rb
      create  config/environments/test.rb
      create  config/initializers
      create  config/initializers/application_controller_renderer.rb
      create  config/initializers/assets.rb
      create  config/initializers/backtrace_silencers.rb
      create  config/initializers/content_security_policy.rb
      create  config/initializers/cookies_serializer.rb
      create  config/initializers/cors.rb
      create  config/initializers/filter_parameter_logging.rb
      create  config/initializers/inflections.rb
      create  config/initializers/mime_types.rb
      create  config/initializers/new_framework_defaults_5_2.rb
      create  config/initializers/wrap_parameters.rb
      create  config/locales
      create  config/locales/en.yml
      create  config/master.key
      append  .gitignore
      create  config/boot.rb
      create  config/database.yml
      create  db
      create  db/seeds.rb
      create  lib
      create  lib/tasks
      create  lib/tasks/.keep
      create  lib/assets
      create  lib/assets/.keep
      create  log
      create  log/.keep
      create  public
      create  public/404.html
      create  public/422.html
      create  public/500.html
      create  public/apple-touch-icon-precomposed.png
      create  public/apple-touch-icon.png
      create  public/favicon.ico
      create  public/robots.txt
      create  tmp
      create  tmp/.keep
      create  tmp/pids
      create  tmp/pids/.keep
      create  tmp/cache
      create  tmp/cache/assets
      create  vendor
      create  vendor/.keep
      create  test/fixtures
      create  test/fixtures/.keep
      create  test/fixtures/files
      create  test/fixtures/files/.keep
      create  test/controllers
      create  test/controllers/.keep
      create  test/mailers
      create  test/mailers/.keep
      create  test/models
      create  test/models/.keep
      create  test/helpers
      create  test/helpers/.keep
      create  test/integration
      create  test/integration/.keep
      create  test/test_helper.rb
      create  test/system
      create  test/system/.keep
      create  test/application_system_test_case.rb
      create  storage
      create  storage/.keep
      create  tmp/storage
      create  tmp/storage/.keep
      remove  config/initializers/cors.rb
      remove  config/initializers/new_framework_defaults_5_2.rb
         run  bundle install
Fetching gem metadata from https://rubygems.org/.............
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies....
Using rake 13.0.1
Using concurrent-ruby 1.1.5
Using i18n 1.7.0
Using minitest 5.13.0
Using thread_safe 0.3.6
Using tzinfo 1.2.6
Using activesupport 5.2.4.1
Using builder 3.2.4
Using erubi 1.9.0
Using mini_portile2 2.4.0
Using nokogiri 1.10.7 (x64-mingw32)
Using rails-dom-testing 2.0.3
Using crass 1.0.5
Using loofah 2.4.0
Using rails-html-sanitizer 1.3.0
Using actionview 5.2.4.1
Using rack 2.0.8
Using rack-test 1.1.0
Using actionpack 5.2.4.1
Using nio4r 2.5.2
Using websocket-extensions 0.1.4
Using websocket-driver 0.7.1
Using actioncable 5.2.4.1
Using globalid 0.4.2
Using activejob 5.2.4.1
Using mini_mime 1.0.2
Using mail 2.7.1
Using actionmailer 5.2.4.1
Using activemodel 5.2.4.1
Using arel 9.0.0
Using activerecord 5.2.4.1
Using mimemagic 0.3.3
Using marcel 0.3.3
Using activestorage 5.2.4.1
Using public_suffix 4.0.3
Using addressable 2.7.0
Using io-like 0.3.0
Using archive-zip 0.12.0
Using bindex 0.8.1
Using msgpack 1.3.1 (x64-mingw32)
Using bootsnap 1.4.5
Using bundler 1.17.2
Using byebug 11.0.1
Using regexp_parser 1.6.0
Using xpath 3.2.0
Using capybara 3.30.0
Using childprocess 3.0.0
Using chromedriver-helper 2.1.1
Using coffee-script-source 1.12.2
Using execjs 2.7.0
Using coffee-script 2.4.1
Using method_source 0.9.2
Using thor 1.0.1
Using railties 5.2.4.1
Using coffee-rails 4.2.2
Using duktape 2.3.0.0
Using ffi 1.11.3 (x64-mingw32)
Using jbuilder 2.9.1
Using puma 3.12.2
Using sprockets 3.7.2
Using sprockets-rails 3.2.1
Using rails 5.2.4.1
Using rb-fsevent 0.10.3
Using rb-inotify 0.10.1
Using rubyzip 2.0.0
Using sass-listen 4.0.0
Using sass 3.7.4
Using tilt 2.0.10
Using sass-rails 5.1.0
Using selenium-webdriver 3.142.7
Using sqlite3 1.4.2
Using turbolinks-source 5.2.0
Using turbolinks 5.2.1
Using tzinfo-data 1.2019.3
Using uglifier 4.2.0
Using web-console 3.7.0
Bundle complete! 16 Gemfile dependencies, 76 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.

下記は陥った状況

C:¥Users¥leone> rails new アプリケーション名
      create
      create  README.md
      create  Rakefile
      create  .ruby-version
      create  config.ru
      create  .gitignore
      create  Gemfile
  //ここらで終わっていた。

ではなぜこのようなことが起こるのか。
それはgitがインストールされていない、または上手くインストールされていないためです。
既にしている場合は、gitbashしかgitコマンド使用の許可がされていない。つまりはpathが通っていないことが原因ということになります。

解決方法

Gitをインストールする

既にインストールしてある場合は再インストール、またはpathを設定し直す。
pathを設定し直すのが早くC:\Program Files\Git\cmdをpathに追加。
再インストールする際は、インストール前にアンインストールを行う。

アンインストール手順
デスクトップ > スタート > 設定 > ホーム > アプリ > Git version〇〇を選択 > アンインストール

Gitインストール手順
Gitのインストール方法は検索して該当したサイトを参考にインストールして構いませんが、下記に記す部分は注意してほしい。
https://proengineer.internous.co.jp/content/columnfeature/6893(こちらのサイトを参考にするとよい)

Gitインストール時の注意点
6 (3).png

上記の画面に進んだら画像のように真ん中を選んでください。これはbash以外のシェルでもgitコマンドを使えるようにするためです。もし上を選んでインストールしてしまったら環境変数からpathを追加することをおすすめしますが、pathの概念がわからなければ再インストールしても問題はありません。

最後に

私はこのような方法で解決に至ったのですが、皆さんはどうだったでしょうか。当投稿でお力添え出来たら幸いです。
解決出来た、または役に立ったという方がいればグッドボタン:thumbsup:を押して頂けると励みになります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Ruby on Rails] serverが起動せず"Usage: rails new APP_PATH [options]..."となってしまう場合の解決法

経緯

私がRailsの環境を構築する際「Rails s」でサーバーが起動しない問題に陥ったが解決に至ったためここにその方法を記載したいと思う。
投稿に至った経緯は以下の通り。

  • Web上で私と同じように悩んでいる方が多く、またほとんどの記事において解決に至っていなかったため。

  • 該当する記事がそうないように感じたため。

  • 同じ状況に陥っている同志の助けになりたいと考えたため。

陥った状況

  1. 前提として使用OSは Windows10
  2. コマンドプロンプトでrails sを実行すると「Usage: rails new APP_PATH [options] ...(以下省略)」が表示されてサーバが起動できていない。
  3. Ruby、SQLite、Ruby on Railsはインストールされている。
  4. rails new プロジェクト名を実行済み ( 新しいrailsプロジェクトを生成するコマンド )
  5. cd プロジェクト名を実行済み ( プロジェクトのrootに移動するコマンド )

詳細な状況

  • 本来はrails sを実行した際、下記のようになればよい。
C:¥Users¥leone> rails s
=> Booting Puma
=> Rails 5.2.4.1 application starting in development
=> Run `rails server -h` for more startup options
*** SIGUSR2 not implemented, signal based restart unavailable!
*** SIGUSR1 not implemented, signal based restart unavailable!
*** SIGHUP not implemented, signal based logs reopening unavailable!
Puma starting in single mode...
* Version 3.12.2 (ruby 2.6.4-p104), codename: Llamas in Pajamas
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://localhost:3000
Use Ctrl-C to stop
  • しかし問題の状態では下記のようになってしまう。
C:¥Users¥leone> rails s
Usage:
  rails new APP_PATH [options]

Options:
      [--skip-namespace], [--no-skip-namespace]            # Skip namespace (affects only isolated applications)
  -r, [--ruby=PATH]                                        # Path to the Ruby binary of your choice
                                                           # Default: C:/Ruby26-x64/bin/ruby.exe
  -m, [--template=TEMPLATE]                                # Path to some application template (can be a filesystem path or URL)
  -d, [--database=DATABASE]                                # Preconfigure for selected database (options: mysql/postgresql/sqlite3/oracle/frontbase/ibm_db/sqlserver/jdbcmysql/jdbcsqlite3/jdbcpostgresql/jdbc)
                                                           # Default: sqlite3
      [--skip-yarn], [--no-skip-yarn]                      # Don't use Yarn for managing JavaScript dependencies
      [--skip-gemfile], [--no-skip-gemfile]                # Don't create a Gemfile
  -G, [--skip-git], [--no-skip-git]                        # Skip .gitignore file
      [--skip-keeps], [--no-skip-keeps]                    # Skip source control .keep files
  -M, [--skip-action-mailer], [--no-skip-action-mailer]    # Skip Action Mailer files
  -O, [--skip-active-record], [--no-skip-active-record]    # Skip Active Record files
      [--skip-active-storage], [--no-skip-active-storage]  # Skip Active Storage files
  -P, [--skip-puma], [--no-skip-puma]                      # Skip Puma related files
  -C, [--skip-action-cable], [--no-skip-action-cable]      # Skip Action Cable files
  -S, [--skip-sprockets], [--no-skip-sprockets]            # Skip Sprockets files
      [--skip-spring], [--no-skip-spring]                  # Don't install Spring application preloader
      [--skip-listen], [--no-skip-listen]                  # Don't generate configuration that depends on the listen gem
      [--skip-coffee], [--no-skip-coffee]                  # Don't use CoffeeScript
  -J, [--skip-javascript], [--no-skip-javascript]          # Skip JavaScript files
      [--skip-turbolinks], [--no-skip-turbolinks]          # Skip turbolinks gem
  -T, [--skip-test], [--no-skip-test]                      # Skip test files
      [--skip-system-test], [--no-skip-system-test]        # Skip system test files
      [--skip-bootsnap], [--no-skip-bootsnap]              # Skip bootsnap gem
      [--dev], [--no-dev]                                  # Setup the application with Gemfile pointing to your Rails checkout
      [--edge], [--no-edge]                                # Setup the application with Gemfile pointing to Rails repository
      [--rc=RC]                                            # Path to file containing extra configuration options for rails command
      [--no-rc], [--no-no-rc]                              # Skip loading of extra configuration options from .railsrc file
      [--api], [--no-api]                                  # Preconfigure smaller stack for API only apps
  -B, [--skip-bundle], [--no-skip-bundle]                  # Don't run bundle install
      [--webpack=WEBPACK]                                  # Preconfigure for app-like JavaScript with Webpack (options: react/vue/angular/elm/stimulus)

Runtime options:
  -f, [--force]                    # Overwrite files that already exist
  -p, [--pretend], [--no-pretend]  # Run but do not make any changes
  -q, [--quiet], [--no-quiet]      # Suppress status output
  -s, [--skip], [--no-skip]        # Skip files that already exist

Rails options:
  -h, [--help], [--no-help]        # Show this help message and quit
  -v, [--version], [--no-version]  # Show Rails version number and quit

Description:
    The 'rails new' command creates a new Rails application with a default
    directory structure and configuration at the path you specify.

    You can specify extra command-line arguments to be used every time
    'rails new' runs in the .railsrc configuration file in your home directory.

    Note that the arguments specified in the .railsrc file don't affect the
    defaults values shown above in this help message.

Example:
    rails new ~/Code/Ruby/weblog

    This generates a skeletal Rails installation in ~/Code/Ruby/weblog.

原因

"Usage: rails new APP_PATH [options]"が表れるということはプロジェクトがないことが原因と考えられますが、前提としてrails new プロジェクト名cd プロジェクト名は実行されているはずです。

そこから察するに、実行はされたが何らかが原因で生成されたプロジェクトが認識されてないのではないかと考えました。ではなぜ認識されないのか考えたところ、予想としてrails new プロジェクト名で生成されるファイルが足りないのではないかと考えたため、私はプロジェクトとして生成されたディレクトリ内を確認したのです。すると予想は的中し明らかにファイルが足りなかったのでした。

下記は本来、プロジェクト生成時に生成されるはずのファイル、またはその処理

C:¥Users¥leone> rails new アプリケーション名
      create
      create  README.md
      create  Rakefile
      create  .ruby-version
      create  config.ru
      create  .gitignore
      create  Gemfile
         run  git init from "."
Initialized empty Git repository in C:/Users/leone/アプリケーション名/.git/
      create  package.json
      create  app
      create  app/assets/config/manifest.js
      create  app/assets/javascripts/application.js
      create  app/assets/javascripts/cable.js
      create  app/assets/stylesheets/application.css
      create  app/channels/application_cable/channel.rb
      create  app/channels/application_cable/connection.rb
      create  app/controllers/application_controller.rb
      create  app/helpers/application_helper.rb
      create  app/jobs/application_job.rb
      create  app/mailers/application_mailer.rb
      create  app/models/application_record.rb
      create  app/views/layouts/application.html.erb
      create  app/views/layouts/mailer.html.erb
      create  app/views/layouts/mailer.text.erb
      create  app/assets/images/.keep
      create  app/assets/javascripts/channels
      create  app/assets/javascripts/channels/.keep
      create  app/controllers/concerns/.keep
      create  app/models/concerns/.keep
      create  bin
      create  bin/bundle
      create  bin/rails
      create  bin/rake
      create  bin/setup
      create  bin/update
      create  bin/yarn
      create  config
      create  config/routes.rb
      create  config/application.rb
      create  config/environment.rb
      create  config/cable.yml
      create  config/puma.rb
      create  config/storage.yml
      create  config/environments
      create  config/environments/development.rb
      create  config/environments/production.rb
      create  config/environments/test.rb
      create  config/initializers
      create  config/initializers/application_controller_renderer.rb
      create  config/initializers/assets.rb
      create  config/initializers/backtrace_silencers.rb
      create  config/initializers/content_security_policy.rb
      create  config/initializers/cookies_serializer.rb
      create  config/initializers/cors.rb
      create  config/initializers/filter_parameter_logging.rb
      create  config/initializers/inflections.rb
      create  config/initializers/mime_types.rb
      create  config/initializers/new_framework_defaults_5_2.rb
      create  config/initializers/wrap_parameters.rb
      create  config/locales
      create  config/locales/en.yml
      create  config/master.key
      append  .gitignore
      create  config/boot.rb
      create  config/database.yml
      create  db
      create  db/seeds.rb
      create  lib
      create  lib/tasks
      create  lib/tasks/.keep
      create  lib/assets
      create  lib/assets/.keep
      create  log
      create  log/.keep
      create  public
      create  public/404.html
      create  public/422.html
      create  public/500.html
      create  public/apple-touch-icon-precomposed.png
      create  public/apple-touch-icon.png
      create  public/favicon.ico
      create  public/robots.txt
      create  tmp
      create  tmp/.keep
      create  tmp/pids
      create  tmp/pids/.keep
      create  tmp/cache
      create  tmp/cache/assets
      create  vendor
      create  vendor/.keep
      create  test/fixtures
      create  test/fixtures/.keep
      create  test/fixtures/files
      create  test/fixtures/files/.keep
      create  test/controllers
      create  test/controllers/.keep
      create  test/mailers
      create  test/mailers/.keep
      create  test/models
      create  test/models/.keep
      create  test/helpers
      create  test/helpers/.keep
      create  test/integration
      create  test/integration/.keep
      create  test/test_helper.rb
      create  test/system
      create  test/system/.keep
      create  test/application_system_test_case.rb
      create  storage
      create  storage/.keep
      create  tmp/storage
      create  tmp/storage/.keep
      remove  config/initializers/cors.rb
      remove  config/initializers/new_framework_defaults_5_2.rb
         run  bundle install
Fetching gem metadata from https://rubygems.org/.............
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies....
Using rake 13.0.1
Using concurrent-ruby 1.1.5
Using i18n 1.7.0
Using minitest 5.13.0
Using thread_safe 0.3.6
Using tzinfo 1.2.6
Using activesupport 5.2.4.1
Using builder 3.2.4
Using erubi 1.9.0
Using mini_portile2 2.4.0
Using nokogiri 1.10.7 (x64-mingw32)
Using rails-dom-testing 2.0.3
Using crass 1.0.5
Using loofah 2.4.0
Using rails-html-sanitizer 1.3.0
Using actionview 5.2.4.1
Using rack 2.0.8
Using rack-test 1.1.0
Using actionpack 5.2.4.1
Using nio4r 2.5.2
Using websocket-extensions 0.1.4
Using websocket-driver 0.7.1
Using actioncable 5.2.4.1
Using globalid 0.4.2
Using activejob 5.2.4.1
Using mini_mime 1.0.2
Using mail 2.7.1
Using actionmailer 5.2.4.1
Using activemodel 5.2.4.1
Using arel 9.0.0
Using activerecord 5.2.4.1
Using mimemagic 0.3.3
Using marcel 0.3.3
Using activestorage 5.2.4.1
Using public_suffix 4.0.3
Using addressable 2.7.0
Using io-like 0.3.0
Using archive-zip 0.12.0
Using bindex 0.8.1
Using msgpack 1.3.1 (x64-mingw32)
Using bootsnap 1.4.5
Using bundler 1.17.2
Using byebug 11.0.1
Using regexp_parser 1.6.0
Using xpath 3.2.0
Using capybara 3.30.0
Using childprocess 3.0.0
Using chromedriver-helper 2.1.1
Using coffee-script-source 1.12.2
Using execjs 2.7.0
Using coffee-script 2.4.1
Using method_source 0.9.2
Using thor 1.0.1
Using railties 5.2.4.1
Using coffee-rails 4.2.2
Using duktape 2.3.0.0
Using ffi 1.11.3 (x64-mingw32)
Using jbuilder 2.9.1
Using puma 3.12.2
Using sprockets 3.7.2
Using sprockets-rails 3.2.1
Using rails 5.2.4.1
Using rb-fsevent 0.10.3
Using rb-inotify 0.10.1
Using rubyzip 2.0.0
Using sass-listen 4.0.0
Using sass 3.7.4
Using tilt 2.0.10
Using sass-rails 5.1.0
Using selenium-webdriver 3.142.7
Using sqlite3 1.4.2
Using turbolinks-source 5.2.0
Using turbolinks 5.2.1
Using tzinfo-data 1.2019.3
Using uglifier 4.2.0
Using web-console 3.7.0
Bundle complete! 16 Gemfile dependencies, 76 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.

下記は陥った状況

C:¥Users¥leone> rails new アプリケーション名
      create
      create  README.md
      create  Rakefile
      create  .ruby-version
      create  config.ru
      create  .gitignore
      create  Gemfile
  //ここらで終わっていた。

ではなぜこのようなことが起こるのか。
それはgitがインストールされていない、または上手くインストールされていないためです。
既にインストールしている場合は、gitbashしかgitコマンド使用の許可がされていない。つまりはpathが通っていないことが原因ということになります。

解決方法

Gitをインストールする

既にインストールしてある場合は再インストール、またはpathを設定し直す。
pathを設定し直すのが早くC:\Program Files\Git\cmdをpathに追加。
再インストールする際は、インストール前にアンインストールを行う。

アンインストール手順
デスクトップ > スタート > 設定 > ホーム > アプリ > Git version〇〇を選択 > アンインストール

Gitインストール手順
Gitのインストール方法は検索して該当したサイトを参考にインストールして構いませんが、下記に記す部分は注意してほしい。
サイトは、こちらのサイトがオススメです。 
https://proengineer.internous.co.jp/content/columnfeature/6893

Gitインストール時の注意点
6 (3).png

上記の画面に進んだら画像のように真ん中を選んでください。これはbash以外のシェルでもgitコマンドを使えるようにするためです。もし上を選んでインストールしてしまったら環境変数からpathを追加することをおすすめしますが、pathの概念がわからなければ再インストールしても問題はありません。

最後に

私はこのような方法で解決に至ったのですが、皆さんはどうだったでしょうか。当投稿でお力添え出来たら幸いです。
解決出来た、または役に立ったという方がいればグッドボタン:thumbsup:を押して頂けると励みになります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RubyとRailsの気になる単語

時々あの、あれ、あの〜意味なんだっけって単語を記していきます。
あくまで一言で行きたい。深追いはしない派。

  • オブジェクト クラスの参照とインスタンス
  • クラス 入れるべきデータとメソッドを記載した設計図
  • クラスの参照 オブジェクトの所属するクラス
  • インスタンス クラスの設計図から出来たもの
  • インスタンス変数 クラス内であれば全メソッドで使用することができる、@で定義
  • module ミックスイン、ネームスペースを提供
  • include インスタンスとしてメソッドを追加
  • extend クラスとしてメソッドを追加
  • ブロック do~endもしくは{}で囲まれた処理のカタマリ
  • Proc ブロックを持ち運び便利なオブジェクトにしたもの
  • Lambda Procオブジェクトを作る方法の一つ。Procとの違いは引数チェックする&returnした後もメソッドを実行し続ける
  • joins sqlでINNER JOIN
  • INNER JOIN 関係があるデータだけを取ってきてくれる
  • includes データの先読みをしてキャッシュしてくれる
  • Gemfile Railsアプリで利用するgemが記述されているファイル
  • Gemfile.lock Gemfileをもとに実際にインストールしたgemリスト
  • Private オブジェクトの外側からコールはできない
  • Protected 同じクラスのオブジェクトからならコールは可能
  • セッション サーバー側に保存するユーザー情報
  • クッキー ブラウザを通じて配布され、パソコンのハードディスクドライブ上に一時的に保存される「小さいファイル」

終わりなんてない。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.js入門としてWEBブラウザで使える会社の歓送迎会用費用計算機を作った。

はじめに

会社の歓送迎会の幹事。会社員ならば必ずと言っていいほどやらされる面倒くさい仕事。
2019年12月、ちょうど参加者20人を超える歓送迎会の幹事をやることになった。そこには歓送迎者に加え部長、課長、平社員勢揃いで、全員から同じ参加費を取るわけにもいかないので傾斜計算をする必要があった。

そして、いざ計算する時にやっぱり思う、「めちゃくちゃ面倒くさい...」
ゲスト3人タダで、部長が6000円で課長3人が5000円で平社員20人が4000円で…え?●●さんやっぱ出れない?→再計算が始まる。悪夢。

できたもの

さっそくできたサイトは以下。着想からリリースまで1週間、15時間ぐらい。
歓送迎会の会費計算 | Cocktail -f liquor
スクショ.png

使ったもの

簡単に傾斜計算をするためのWEBサービスを入門書だけ読んだVue.jsで作る事にした。
読んだ本→動かして学ぶ!Vue.js開発入門 (NEXT ONE)

既に自分はカクテルレシピ検索サイト「Cocktail -f liquor」を持っていたので、そこに機能として追加した。
レシピ検索サイト自体はPaaSにheroku、フレームワークにRails、CSSフレームワークにUIKitを使っているため、PCスマホどちらでもWEBブラウザ上で利用可能にした。

傾斜計算をするにあたって考えたこと

歓送迎会の傾斜計算をする場合に必要なものを考えた。いわゆる画面設計。

  • 参加する全体の人数と一人分のコース料金のための予約情報の入力欄
  • ゲスト、部長、課長、平社員といった参加費用の異なるグループごとの人数と参加費用の入力欄
  • 全グループ参加費の合計と人数の合計
  • 全グループの情報と予約情報が一致しているかの判定結果
  • 残りの参加費を自動的に計算できるようにする機能(これが結構考えるの面倒だった)
  • 結果を残しておけるように結果コピー機能

Vue.js部分

自身のスキルが入門書レベルということもあり、コンポーネントは使わない非常にシンプルな構成でVue.jsは記述した。
大枠としては以下の通りで、filter,data,computed,watch,methodsの基本構成で作成することができた(全体のソースコードは最後に記述)。今回はお金と人数を扱うこともあり、Vue.filterを使用して20,000のようにコンマを自動的につけれるようにした。

<script>
    Vue.filter('number_format', function (value) {
            ...
        }); 
    new Vue({
        el: "#app",
        data: {
            price: null,
            ...
        },
        computed :{
            ...
        },
        watch :{
            ...
        },
        methods :{
            ...
        }
    })
</script>

少し止まった部分

各グループ情報ごとのグループ参加費合計(グループ人数×グループごとの参加費)を出す必要がある。グループごとの情報は連想配列を配列で保持しており、watchで各グループ情報を監視する際に連想配列の中身をwatchする場合はdeepを指定する必要があった。

参考
[Vue]watchフックで連想配列を監視する場合、ディープウォッチャーにしておく必要がある件 - Qiita

data: {
    calcs: [{c_name:"",c_price:null,c_person:null,c_total:0,c_auto:false}],
},
watch :{
    calcs: {
        handler: function(val){
            for (var i = 0; i < this.calcs.length; i++ ){
                this.calcs[i].c_total = this.calcs[i].c_price * this.calcs[i].c_person;
            }
        },
        deep: true
    }
},

最後に

歓送迎会用の費用計算機の感想・意見を募集中です。
Twitter @anemoi42 までリプライまたはDMを送っていただけると助かります。

以上、ありがとうございました。

ソースコード

<% @page_title = '歓送迎会の会費計算' %>
<% content_for :header do %>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.min.js"></script>
<% end %>

<body>
    <div class='uk-card uk-card-default uk-card-small uk-card-body uk-margin-small'>
        <h3 class="box8 uk-margin-remove">歓送迎会の会費計算</h3>
        <div class="uk-margin-small">
        参加費用に傾斜をつける歓送迎会の会費シミュレーションが可能です。コース料金、全体参加人数を入力後、支払う金額ごとのグループを作成して最終的に参加費用と人数が予約と一致しているか確認できます。ゲストは無料、一般社員は3000円、課長は5000円、部長は6000円といった際の計算が簡単にできます。
        </div>

    </div>
    <div id="app">
        <div class='uk-card uk-card-default uk-card-small uk-card-body uk-margin-small'>
            <div class='uk-h4 uk-margin-small'>予約情報</div>
            <div>
                全体の参加費合計を出すために、一人分のコース料金と全体の参加人数を入力して下さい。
            </div>
            <hr>
            <div class='uk-grid uk-margin-small uk-flex uk-flex-middle uk-text-center' >
                 <div>1人分のコース料金:</div>
                 <div>
                    <input v-model.number="price" type="number" placeholder="例)5000" class="uk-input uk-form-width-medium" v-on:blur="complementPriceReserve"></div>
                 <div>
                    <input v-model="tax" type="checkbox" class="uk-checkbox"> 税別(10%)
                </div>
            </div>
            <div class='uk-grid uk-margin-small uk-flex uk-flex-middle uk-text-center' >
                <div>
                    参加人数:
                </div>
                <div>
                    <input v-model.number="person" type="number" placeholder="例)10" class="uk-input uk-form-width-small" v-on:blur="complementPersonReserve"></div>
            </div>
            <hr>
            <div class='uk-h4 uk-margin-small uk-align-right'>予約上の参加費合計: {{ total_price|number_format }}円</div>

        </div>

        <div class="tmpcalc uk-card uk-card-default uk-card-small uk-card-body uk-margin-small">
            <div class='uk-h4 uk-margin-small'>グループ情報</div>
            支払う金額ごとのグループを作成して下さい。
            <hr>
            <div v-for="(calc,c) in calcs">
                <div class="tmpcalc uk-card uk-card-group uk-card-small uk-card-body uk-margin-small">

                    <div class='uk-grid uk-margin-small uk-flex uk-flex-middle uk-text-center' >
                        <div>
                        グループ名(任意):
                        </div>
                        <div>
                            <input v-model.number="calc.c_name" type="text" placeholder="例)ゲスト、平社員、課長" class="uk-input uk-form-width-auto">
                        </div>
                    </div>
                    <div class='uk-grid uk-margin-small uk-flex uk-flex-middle uk-text-center' > 
                        <div>
                            グループ人数:
                        </div>
                        <div>
                            <input v-model.number="calc.c_person" type="number" placeholder="例)5" v-on:blur="complementPerson(c)" class="uk-input uk-form-width-small"></div>
                    </div>
                    <div class='uk-grid uk-margin-small uk-flex uk-flex-middle uk-text-center' >
                        <div>
                            グループ参加費(1人分):
                        </div>
                        <div>
                            <input v-model.number="calc.c_price" type="number" placeholder="例)4000" v-on:blur="complementPrice(c)" class="uk-input uk-form-width-medium"></div>

                        <div>
                            <button v-on:click="autoCalculate(c)" class="uk-button uk-button-default" uk-tooltip="title: 予約の参加費合計と一致するようにこのグループの参加費を計算します。自動計算をするには事前に他のグループ情報と、このグループの人数を入力して下さい。; pos: right">自動計算</button>
                        </div>

                    </div>

                    <hr>

                    <div class='uk-h4 uk-margin-small uk-text-right'>グループ参加費合計: {{ calc.c_total|number_format }}円</div>
                    <div class='uk-flex uk-flex-center' >                        
                        <div class='uk-padding-small uk-padding-remove-vertical'>
                            <button v-on:click="addList(c)" class="uk-button uk-button-default" uk-tooltip="title: グループを追加します。; pos: bottom"><span uk-icon="icon: plus-circle; ratio: 1.0" type="button" class="cursor_to_point"></span> 追加</button>
                        </div>
                        <div class='uk-padding-small uk-padding-remove-vertical'>
                            <button v-show="minus_circle" v-on:click="delList(c)" class="uk-button uk-button-default " uk-tooltip="title: このグループを削除します。; pos: bottom"><span uk-icon="icon: minus-circle; ratio: 1.0" type="button" class="cursor_to_point"></span> 削除</button>  
                        </div>                  
                    </div>

                </div>
            </div>

            <hr>
            <div class='uk-h4 uk-margin-small ' align="right">全グループ参加費合計: {{calc_total_price|number_format}} 円</div>
            <div class='uk-h4 uk-margin-small ' align="right">全グループ参加人数合計: {{calc_total_person|number_format}} 人</div>

            <div v-if="sub_total_price > 0">
                <div class="uk-alert-warning uk-text-center" uk-alert>
                    予約に対して<font color="#ff4500"> {{sub_total_price|number_format}}円</font> 多く回収しています。
                    端数の場合は幹事が貰ってしまいましょう。
                </div>
            </div>
            <div v-else-if="sub_total_price < 0">
                <div class="uk-alert-danger uk-text-center" uk-alert>
                    予約に対して<font color="#ff4500"> {{-sub_total_price|number_format}}円</font> 少なく回収しています。
                </div>
            </div>
            <div v-else>
                <div class="uk-alert-success uk-text-center" uk-alert>
                    予約上の参加費合計と全グループ参加費合計は一致しています。
                </div>
            </div>

            <div v-if="sub_total_person > 0">
                <div class="uk-alert-warning uk-text-center" uk-alert>
                    予約に対して<font color="#ff4500"> {{sub_total_person|number_format}}人</font> 多く参加しています。
                </div>
            </div>
            <div v-else-if="sub_total_person < 0">
                <div class="uk-alert-danger uk-text-center" uk-alert>
                    予約に対して<font color="#ff4500"> {{-sub_total_person|number_format}}人</font> 少なく参加しています。
                </div>
            </div>
            <div v-else>
                <div class="uk-alert-success uk-text-center" uk-alert>
                    予約上の参加人数と全グループ参加人数は一致しています。
                </div>
            </div>
            <textarea id="copyTarget" class="uk-textarea" v-model="outputText"  rows="5" placeholder="Textarea" readonly></textarea>
            <div class='uk-flex uk-flex-center uk-margin-small' >   
            <button v-on:click="copyResult" class="uk-button uk-button-default " uk-tooltip="title: 結果をクリップボードにコピーします; pos: bottom" ><span uk-icon="icon: copy; ratio: 1.0" type="button" class="cursor_to_point"></span> 結果をコピー</button> 
            </div>
        </div>

    </div>
    <div class="uk-flex uk-flex-center uk-margin">
        <a class="uk-button uk-button-secondary" href="#topanchor" uk-scroll>ページトップへ</a>
    </div>

    <script>
        Vue.filter('number_format', function (value) {
            return addComma(value);
        }); 
        var addComma = function(value){
             if (! value) { return 0; }
            return value.toString().replace( /([0-9]+?)(?=(?:[0-9]{3})+$)/g , '$1,' );
        }
        new Vue({
            el: "#app",
            data: {
                price: null,
                person: null,
                tax: false,
                calcs: [{c_name:"",c_price:null,c_person:null,c_total:0,c_auto:false}],
            },
            computed :{
                total_price: function(){
                    var total = this.price * this.person;
                    if (this.tax){
                        total *= 1.1;
                    }
                    return Math.round(total);
                },
                calc_total_price: function(){
                    var tmp_total = 0;
                    for (var i = 0; i < this.calcs.length; i++ ){
                        tmp_total += this.calcs[i].c_total;
                    }
                    return tmp_total;   
                },
                calc_total_person: function(){
                    var tmp_person = 0;
                    for (var i = 0; i < this.calcs.length; i++ ){
                        tmp_person += this.calcs[i].c_person;
                    }
                    return tmp_person;  
                },
                sub_total_price: function(){
                    return this.calc_total_price - this.total_price;
                },
                sub_total_person: function(){
                    return this.calc_total_person - this.person;
                },
                minus_circle: function(){
                    if (this.calcs.length > 1){
                        return true;
                    }else{
                        return false;
                    }
                },
                outputText: function(){
                    var resultText = "";
                    resultText += "◆予約情報◆\n";
                    resultText += "1人分のコース料金:" + addComma(this.price) + "\n";
                    resultText += "参加人数:" + addComma(this.person) + "\n";
                    resultText += "予約上の参加費合計:" + addComma(this.total_price) + "\n";
                    resultText += "--------------------\n";
                    resultText += "◆グループ情報◆\n";
                    for (var i = 0; i < this.calcs.length; i++ ){
                        if(this.calcs[i].c_name == ""){
                            resultText += "◇グループ" + (i+1) + "\n";
                        }else{
                            resultText += "" + this.calcs[i].c_name + "\n";
                        }
                        resultText += "参加費:" +addComma(this.calcs[i].c_price) + "";
                        resultText += "人数:" +addComma(this.calcs[i].c_person) + "";
                        resultText += "合計:" +addComma(this.calcs[i].c_total) + "\n";
                    }
                    resultText += "--------------------\n";
                    resultText += "全グループ参加費合計:" + addComma(this.calc_total_price) + "\n";
                    resultText += "全グループ参加人数合計:" + addComma(this.calc_total_person) + "\n";
                    if(this.sub_total_price > 0){
                        resultText += "※予約に対して " + addComma(this.sub_total_price) + "円 多く回収\n";
                    }else if(this.sub_total_price < 0){
                        resultText += "※予約に対して " + addComma(-this.sub_total_price) + "円 少なく回収\n";
                    }
                    if(this.sub_total_person > 0){
                        resultText += "※予約に対して " + addComma(this.sub_total_person) + "人 多く参加\n";
                    }else if(this.sub_total_person < 0){
                        resultText += "※予約に対して " + addComma(-this.sub_total_person) + "人 少なく参加\n";
                    }
                    return resultText;
                }
            },
            watch :{
                calcs: {
                    handler: function(val){
                        for (var i = 0; i < this.calcs.length; i++ ){
                            this.calcs[i].c_total = this.calcs[i].c_price * this.calcs[i].c_person;
                        }
                    },
                    deep: true
                }
            },
            methods :{
                addList: function(c){   
                    //残りの人数を計算
                    var left_person = this.person - this.calc_total_person;
                    if (left_person < 0){
                        left_person = 0;
                    }
                    this.calcs.splice(c+1,0,{c_name:"",c_price:0,c_person:left_person,c_total:0});
                },
                delList: function(c){
                    if(this.calcs.length > 1){
                        this.calcs.splice(c,1);
                    }
                },
                autoCalculate: function(target){
                    var left_person = 0;
                    var left_price = 0;
                    var conf_price = 0;
                    for (var i = 0; i < this.calcs.length; i++ ){
                        //自動計算対象外の人数と確定金額を取得
                        if (!this.calcs[i].c_person){
                            this.calcs[i].c_person = 1;
                        }
                        if (!this.calcs[i].c_price){
                            this.calcs[i].c_price = 0;
                        }
                        if (i == target){                               
                            left_person += this.calcs[i].c_person;
                        } else {
                            conf_price += this.calcs[i].c_price * this.calcs[i].c_person;
                        }
                    }
                    //残額計算
                    left_price = (this.total_price - conf_price) / left_person;
                    //空欄につめる
                    this.calcs[target].c_price = Math.round(left_price);
                },
                complementPriceReserve: function(){
                    if(!this.price){
                        this.price = 0;
                    }else if (this.price < 0){
                        this.price = 0;
                    }
                },
                complementPersonReserve: function(){
                    if(!this.person){
                        this.person = 0;
                    }else if (this.person < 0){
                        this.person = 0;
                    }
                },
                complementPerson: function(target){
                    if(!this.calcs[target].c_person){
                        this.calcs[target].c_person = 0;
                    }else if (this.calcs[target].c_person < 0){
                        this.calcs[target].c_person = 0;
                    }
                },
                complementPrice: function(target){
                    if(!this.calcs[target].c_price){
                        this.calcs[target].c_price = 0;
                    }else if (this.calcs[target].c_price < 0){
                        this.calcs[target].c_price = 0;
                    }
                },
                copyResult: function(){
                    var copyTarget = document.getElementById("copyTarget");
                    copyTarget.select();
                    document.execCommand("Copy");
                }
            }
        })

    </script>

</body>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

異業種・異職種からIT業界への転職

はじめに

IT業界の有効求人倍率が上がり、IT人材の雇用待遇はどんどん良くなり、異業種からIT業界へ転職したい人が増えているかと思います。

しかし、全ての人にIT業界を進めるというようなことはしたくなく、どういう仕事であれば自分が頑張っていけるのかということを自己分析した上でIT業界が合っていると考えてくださった方へ向けた記事となります。

とういうのも、定年退職の年齢は60歳でしたが、それが65歳、70歳、・・・とどんどん引き上げられてきています。(再雇用も同様です。)
誰かが言っていた言葉ですが、労働の形が今までの長時間労働から長期間労働に変化していきます。
上記のような現状から筆者としての考えとしては、長い期間楽しく働くために、好きなことを仕事にして生きていくことがこれからの時代で一番重要なことになってくると考えています。

大学などでプログラムを扱ってきた人と比べると異業種からのIT業界への転職は積み重ねの数が圧倒的に違います。
この積み重ねの差を埋めるために、追いつくための努力は並大抵のものではありません。
IT業界への転職がうまくいったからと言って必ずしも幸せになれるとは限りません。

筆者も異業種からIT業界へ転職した人間の一人として、その経験を綴ることによって誰かの参考になることを強く望んでいます。

好きなこととしてはじめたその仕事はあなたを幸せへと導いてくれるでしょう。

関連リンク

未掲載ですが今後載せていく予定の関連リンクを下記に載せておくので、必要であれば参考にしてください。。
仮タイトルのものも含まれています。掲載し次第、こちらにもリンクを順次貼っていきます。

  • スキルアップの軌跡(未経験、転職、入社後まで)
    • URL
  • メモの魔力、活用術
    • URL
  • Progate活用術
    • URL
  • ドットインストール活用術
    • URL
  • paiza スキルチェック活用術
    • URL
  • 1ヶ月1個、アプリケーション制作
    • URL
  • Ruby Silver取得までの道のり
    • URL
  • Ruby Gold取得までの道のり
    • URL
  • 入社後の勉強方法
    • URL

転職を思いたった理由

大学で電気電子工学を修了し技術的な仕事をしたいと思い自動車メーカーへ入社したものの、配属されたのは事務職の部署でした。
部署ローテーションが3年であると言われその仕事を続けていました。
上司との面談では毎回部署異動したい旨を伝えていて、さらに合格率8%以下の難関な専門資格を取得した上で異動を願い出ましたが、それでも願いは聞き入れてもらえず3年が経ち転職するしかないと踏み切りました。

これは前職への恨みとは思っておらず、自分らしい道を進むきっかけとなったと感謝しています。

自己分析

好きなことを仕事にして生きていくために、これが一番重要かもしれません。

メモの魔力

この本を用いて自己分析をすることで、過去の自分から今の自分を振り返ることで、自分の価値観やモチベーションの源泉を知ることができます。

自分が何者なのかを知るきっかけを与えてくれたこの本と著者・前田裕司さんに感謝し、他の誰かに勧めることで返していければいいなと考えています。
みなさんもどうぞ読んでみてください。

異業種・異職種からIT業界への転職

転職をするときの難易度を並べると下記のようになるそうです。(右が難易度が高い。)

これは入社してからの難易度(大変さ)も同じ並びになるかと思います。
面接時点で落とされてしまうのは、この会社では大変だよということを教えてくれていると割り切りましょう。

まとめ - 好きなことをして生きていこう。

全てがうまくいく訳ではありません。何かを犠牲にしないと何かを達成できないといったトレードオフの関係のものもあると思います。
自己分析をして、人生の軸を見つけることで、取捨選択できる力を身につけましょう。僕も少しずつかもしれませんが進んでいます。

スキルアップの時系列を書こうと思って書き始めましたが、人生論みたいなものになってしまいました。
この記事を軸にして、どのように技術力をつけてきたのか、スキルアップの時系列など、上げていきますのでそちらも参考にしてみてください。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む