元経理マンが27歳でエンジニアに転向してからのメモ集

元経理マンがエンジニアに転向して現在

atomのerbファイルのスニペットを有効にする。

atomのerbファイルの色が気持ち悪かったので、色々調べていたら以下の記事が見つかった。

qiita.com

ちなみに気持ち悪い色のやつ(ERBタイプ) f:id:ryomoyr:20181030144802p:plain:w500

ついでに<%%>とかも- + Tabでできることを知って導入。

いちいちatomの下の、ファイルタイプをERBからHTML(Rails)に変更するのがめんどくさかったので、 常時HTML(Rails)で読み込んでくれるように設定をしたかった。

File-Typesをインストール

atom.io

[Atom] -> [Config] でconfig.csonファイルが開かれるので、

"*":
  "file-types":
    "*.erb": "text.html.ruby"

の記述をすれば、常時HTML(Rails)ファイルで読み込んでくれるようになった。

f:id:ryomoyr:20181030145215p:plain:w500

こっちのほうがよろしい。

Railsでconcernsを使えば、application_controller.rbを汚さずに共通化できる

通常?今までRailsでapplication_controller.rbに共通化した処理を書いていたが、
エラー処理を書いてあるのでできればそちらを使わずに共通化をしたい。ということで、concernsを使ってリファクタリングする。 そもそもconcernsで共通化するのでスタンダード?かも。

お題としては、
- トップページには最新の記事を5件だけ表示したい。(about等複数ページ)
- 記事一覧ページでは最新の記事を20件表示したい。
- 記事は@latest_entriesというインスタンス変数でViewに渡したい。

こちらをリファクタリングしていく様子を記述する。

通常の無駄な記述 (リファクタリング前)

home_controller.rb

class HomeController < ApplicationController
  def index
    @latest_articles = Article.limit(5).order("created_at DESC")
  end
end

articles_controller.rb

class ArticleController < ApplicationController
  def index
    @latest_articles = Article.limit(20).order("created_at DESC")
  end
end

DRYの哲学があるので、共通化をする。

application_controller.rbでリファクタリング(今まで)

application_controller.rb

class ApplicationController < ApplicationController

  def error_hogehoge
  end

  def error_fugafuga
  end

  def latest_articles(num)
    @latest_articles = Article.limit(num).order("created_at DESC")
  end
end

error_hogehogeはエラー処理のメソッドとして、サンプルとして記述してある。

home_controller.rb

class HomeController < ApplicationController
  before_action -> { latest_articles(5) }, only: [:index]

  def index
  end
end

articles_controller.rb

class ArticleController < ApplicationController
  before_action -> { latest_articles(20) }, only: [:index]

  def index
  end
end

こんな感じで共通化していく。 が、application_controller.rbはエラー処理の記述があって、できれば汚したくない! という場合にconcernsを使って共通化もできる。

concernsでリファクタリング

latest_articles.rb

module LatestArticles
  extend ActiveSupport::Concern

  def latest_articles(num)
    @latest_articles = Article.limit(num).order("created_at DESC")
  end

end

application_controller.rb

class ApplicationController < ApplicationController

  def error_hogehoge
  end

  def error_fugafuga
  end

end

ここには何も書かなくても、大丈夫。

home_controller.rb

class HomeController < ApplicationController
  include LatestArticles
  before_action -> { latest_articles(5) }, only: [:index]

  def index
  end
end

articles_controller.rb

class ArticleController < ApplicationController
  include LatestArticles
  before_action -> { latest_articles(20) }, only: [:index]

  def index
  end
end

concernsの方にクラスとかメソッドを記述して、 controllerの方で、include クラス名を記述してあげれば利用できる。

これだけだとあまり有り難みがないかもしれないが、
application_controller.rbに記述しなくても、
concernsで共通化ができる。

使いようによってはもっと複雑なこともできる。はず。

ローカルで構築したRuby On RailsのアプリをGCPへの自動デプロイ環境を構築する。②

こちらの続き。

ryomoyr.hatenablog.com

Cicle CIのビルド

Circle CIはアカウントを作成して、GitHubと連携していれば、
リモートリポジトリを作成したらすでにプロジェクトに追加できる状態になっている。

add projectsから該当のリポジトリSetUp Project押す。 以下のようなプロジェクトの設定画面になるので、画像のように設定する。

f:id:ryomoyr:20181014152040p:plain:w400

下に出てきたコードをコピーして、
.circleci/config.ymlファイルをRails rootに作成して貼り付ける。

その後にCircle CIの画面に戻って、Start Buildを押す。
最初は失敗するので、先程コピペした内容をコミットしてプッシュする。

Circle CIを確認するとまた、エラーになるが、 pushして、Circle CIのビルドが始まればとりあえずOK

変数の設定とfinger printの生成

Circle CIと連携するのに、IPアドレスやポート番号を変数に登録しておく。
また、反映させたい本番環境にはCircle CIからsshでログインすることになるので、
秘密鍵をCircle CI側に登録しておくことで、
finger printが生成できるので、それを.circleci/config.ymlに記載する。

プロジェクトの設定画面の以下の2つから設定を行う。

f:id:ryomoyr:20181014152929p:plain:w300

Environment Variableには、IPとポート番号など見られたくない内容を登録しておく。

f:id:ryomoyr:20181014153356p:plain:w300

また、Add an SSH Keyでは、HOSTとローカルにある秘密鍵を登録しておく。

f:id:ryomoyr:20181014153229p:plain:w300

登録すると、finger printが得られるので、config.ymlに記載する。

f:id:ryomoyr:20181014153524p:plain:w300

config.ymlの記載

Environment Variable と SSH Key で登録した内容をこちらに反映。
また、config.ymlの内容を以下に変更する。

finger printは各自で違う。

# Ruby CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-ruby/ for more details
#
version: 2
jobs:
  build:
    docker:
      # specify the version you desire here
       - image: circleci/ruby:2.4.2-node-browsers
    working_directory: /home/circleci/rails.com
    steps:
      - checkout

      - setup_remote_docker:
          reusable: true

      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            - v1-dependencies-

      - run:
          name: install dependencies
          command: |
            bundle install --jobs=4 --retry=3 --clean
          #command: bundle check || bundle install --jobs=4 --retry=3

      - save_cache:
          paths:
            - ./vendor/bundle
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}

      #production
      - add_ssh_keys:
          fingerprints:
            - "fa:c0:b9:73:b5:9f:fb:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:"
      - run:
          name: Start ssh-agent
          command: |
            ssh-agent -s > ~/.ssh_agent_conf
            source ~/.ssh_agent_conf
            for _k in $(ls ${HOME}/.ssh/id_*); do
              ssh-add ${_k} || true
            done


      - deploy:
          name: Start deploy
          command: |
            if [ "${CIRCLE_BRANCH}" == "master" ]; then
                ssh-keyscan -p ${PORT} ${HOST} >> ~/.ssh/known_hosts
                ls
                # bundle exec cap production deploy
            fi

一旦これをpushして、lsコマンドが実行できていればsshでの接続もできている。

f:id:ryomoyr:20181014174423p:plain:w300

Capistrano3 による自動デプロイ

Gemfileの記載

こちらの3つを追加。 capistrano
capistrano-rails
capistrano-bundler

最終的にGemfileは以下。

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.4.2'
gem 'rails', '~> 5.2.1'
gem 'mysql2', '>= 0.4.4', '< 0.6.0'
gem 'puma', '~> 3.11'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.2'
gem 'turbolinks', '~> 5'
gem 'jbuilder', '~> 2.5'
gem 'capistrano', '~> 3.5'
gem 'capistrano-rails'
gem 'capistrano-bundler'
gem 'bootsnap', '>= 1.1.0', require: false
gem 'dotenv-rails'

group :development, :test do
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
end

group :development do
  gem 'web-console', '>= 3.3.0'
  gem 'listen', '>= 3.0.5', '< 3.2'
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
end

group :test do
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
  gem 'chromedriver-helper'
end

gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

bundleコマンドを実行してGemファイルをインストールする。

インストール

こちらのコマンドで一発で各種の設定ファイルができる。

# bundle exec cap install

mkdir -p config/deploy
create config/deploy.rb
create config/deploy/staging.rb
create config/deploy/production.rb
mkdir -p lib/capistrano/tasks
create Capfile
Capified

各種設定ファイルの記載

Capfile

require "capistrano/setup"
require "capistrano/deploy"
require "capistrano/scm/git"
install_plugin Capistrano::SCM::Git
require "capistrano/bundler"
require "capistrano/rails/assets"
require "capistrano/rails/migrations"
Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }

config/deploy.rb

set :application, "rails.com"
set :repo_url, "git@github.com:xxxxxx/xxxxxxx"
set :deploy_to, '/home/kusanagi/rails.com'
set :linked_files, fetch(:linked_files, []).push(".env", "config/master.key")

repo_urlはpushしているリモートリポジトリを入れる。

config/deploy/production.rb

server "xx.xx.xx.xx",
  user: "kusanagi",
  roles: %w{web app},
  ssh_options: {
    port: xxxxx,
    forward_agent: true,
    auth_methods: %w(publickey)
    # password: "please use keys"
  }

serverはIPアドレス、portは各自で設定したポート番号をいれる。
本当はここでも.envが使えると思っていたのだが、できないので、
公開鍵認証を行わずにpublicリポジトリで公開するのはNG。
できるのであればやり方は今後調べてみる。

デプロイ

この状態でpushするとCircleCIが反応して、デプロイサーバーにsshで入って、
自動でデプロイをしてくれる。 が、以下のエラーが最初に出る。

00:08 deploy:check:linked_files
      ERROR linked file /home/kusanagi/rails.com/shared/.env does not exist on xx.xx.xx.xx
Exited with code 1

先にpushしてsharedフォルダが作成されないとできないが、
あとは.envファイルとmaster.keyをGCPのsharedに入れて、もう一度回せば、
Circle CIでSuccessがでる。

デプロイする前に GCPのサーバーのNginxのrootをhome/kusanagi/rails.com/current/publicに置き換える。

変更が終わったらデプロイしてみる。 まずは、vagrant環境でindex.htmlを作成する。

f:id:ryomoyr:20181014190023p:plain:w300

pushすると、自動でGCPにデプロイしてくれる。

f:id:ryomoyr:20181014190308p:plain:w300

以上。

GitHub見られたらサーバー情報モロバレだし、 capistranoとか使い方全然正しくなさそうなので、

通りすがりでも正しいやり方分かる方はぜひとも教えてやっていただけますでしょうか。。。