yujiroのプログラミング

勉強内容をアウトプットし、サボらないようにする為のブログ

<DAY104>アプリ制作続き redcarpetとrougeの導入

f:id:yujiro0320:20190512223713p:plain

ドリルの復習(記載方法の違いについて)

2種類の記載があります。どちらも同じ表示をしますが、片方の表記
が好まれます。どちらが良いか、またその理由を述べよ。

#Aパターン
@users = User.all
@users.each do |user|
= renser 'user', user: user

#Bパターン

@user = User.all
 =render 'user', users: @users

結論はBパターンが望ましい。
理由は、renderで情報を渡す前にeachをかけてしまうと、
renderで情報を渡す際に、eachの情報分繰り返し実行されサーバーに不可がかかる為。



railsMarkdown記載内容をhtmlに出力する


gemを使用する。でもはまった。原理を理解するのに務める。
まだよくわかっていないが、欲しい機能の実装はできたので、メモ。
隙間時間に何をしていたのかを理解していく。

参考文献

これめっちゃわかりやすい
https://www.tmp1024.com/programming/rails-use-markdown-of-redcarpet/

redcarpet
GitHub - vmg/redcarpet: The safe Markdown parser, reloaded.


rouge
https://github.com/rouge-ruby/rouge


gemの導入

#htmlを解析してmarkdownに変換してくれる優れもの
gem 'redcarpet'

#言語を判別して色付けしてくれる(シンタックスハイライト)
gem 'rouge'

導入後bundle install

markdown記載用のhelper.rbを作成

app/helper/markdown_helper.rbを作成し、コードを記述する

module MarkdownHelper
  def markdown(text)

    #rougeのオブジェクトにまず渡すオプション
    render_options = {
      filter_html: true,
      hard_wrap: true
    }

    # マークダウンオブジェクトに渡すオプション。この渡し方でハマった
    extensions = {
      autolink: true,
      fenced_code_blocks: true,
      lax_spacing: true,
      no_intra_emphasis: true,
      strikethrough: true,
      superscript: true,
      tables: true
    }

    renderer = RougeConfig::RougeRender.new(render_options)
    Redcarpet::Markdown.new(renderer, extensions).render(text)
  end

end

libファイルを作成する

lib/rouge_config/rouge_render.rbを作成。クラスを記述

require 'redcarpet'
require 'rouge'
require 'rouge/plugins/redcarpet'

module RougeConfig
  class RougeRender < Redcarpet::Render::HTML
    include Rouge::Plugins::Redcarpet
  end
end

libファイルの内容を読みこます

このファイルを読みこます為にconfig/application.rbのクラス内の記述を変更

module (作成したアプリ名)
  class Application < Rails::Application
 #クラス内省略  
 #以下を追加!
    config.autoload_paths += %W(#{config.root}/lib/)
  end
end

railsの変更をしたので、サーバーは再起動させる。

シンタックハイライトを適用させる

capp/assets/stylesheets/rouge.css.erbを作成

<%= Rouge::Themes::Monokai.render(:scope => '.highlight') %>

ビューにマークダウン記載反映されたのを表示

<%= sanitize markdown(tweet.content) %>

<DAY103>ruby likeってアプリを作り始めた。

f:id:yujiro0320:20190512223713p:plain

学習状況

●学習日数 103日

●学習時間(本日)6.5時間

●累計学習時間 468.0時間

●一日あたりの平均学習時間 4.52時間

自分が今欲しいアプリ

rubyの問題文をクイズ形式で出し合い理解を深めるゲーム
単語帳のように気軽に使う事ができ、覚えていたいメソッドや型を理解できる

アプリの仕様

  • (1)問題を投稿、削除、編集ができる
  • (2)問題を解く事ができる
  • (3)答えとその問題のポイントを知る事ができる
  • (4)問題の理解度に合わせてタグつけができる
  • (5)rubyコードに対応した投稿画面である
  • (7)理解度が低い問題を上位に表示する機能がある
  • (8)といた問題を一覧で表示できる
  • (9)投稿したユーザーのみが編集と削除ができる

今後の投稿について

1週間かけて実装していく。
アプリを作りながら実装の復習をしてゆき、実装時に復習かねてあやふやであった点を羅列しメモしていく。

モデルオブジェクトに追加情報を与えたい時

fromで入力されたデーターなど、情報を加えたい時は可動性を高める為に
モデルに記載する。

(例)入力された金額データーに消費税を追加したのを保存したい

#モデルに記載
#priceをキーとして情報が飛んでいる状態

def add_tax

self.price = (price * 1.08).round

end

コントローラではこのように記載

@project = create(project_params)
@project .add_tax

もちろんコントローラにも記載はできる。
ただ、可動性が低くなるので、記入は避けたい。
このような書き方になる

def add_tax(project)

project.price = (price * 1.08).round

end

def create
@project = Project.create(project_params)
@project.price = add_tax(@project) 
end

コントローラーにはアクションできるだけアクションだけでまとめたいところ。

eachを使ってdivタグで要素を囲みたい

なぜかあんまりわかっていなかったけど、配列データーが
eachで生成されるわけなので、生成したいdivタグも
eachで囲んでしまわないといけない。

 <% @tweets.each do |tweet| %>
   <div class="content_message">
    <div class="content_message_text"><%=tweet.content%>
    </div>
    <div class="content_message_option">
    <%= link_to "削除", tweet_path(tweet), method: :delete %>
    <%= link_to "編集", edit_tweet_path(tweet) %>
    </div>
   </div>
  <%end%>

<DAY102>rubyコードと忘れていたメソッドメモ

f:id:yujiro0320:20190512223713p:plain

学習状況

●学習日数 102日

●学習時間(本日)6.5時間

●累計学習時間 461.5時間

●一日あたりの平均学習時間 4.52時間

はじめに

昨日は勉強進まず、だらけた1日だった。
気を取り直し、疑問を解消すべく取り組んでいく。

追加で学んだメソッド

メソッド名 効果 式の例 式の実行結果
select 配列に入った対象を1づつ取り出し条件に合えばあっている分のみ入れ直す arrays.select{(array) array == 0,()ではないからね!} [0,0,0]
include?() 要素に()が含まれているか。true,falseで判断 "kawa".include("kawa") true
empty? 要素に()が含まれているか。true,falseで判断 "kawa".include("kawa") true

rubyの問題から。

<実装条件>
入力されたデータを検索し表示するには?
本の著者とタイトルが登録できる事
著者とタイトルが検索できる機能がある事
登録している本の数が表示できる事
終了できること

自分で書いた答え。

def register_book (books)
   book = {}
   puts "タイトルを入力して下さい"
   book[:title] = gets.chomp
   puts "著者を入力して下さい"
   book[:author] = gets.chomp

   books << book
end

def search_book(books)

  puts "本の登録数は#{books.length}冊あります"
  return if books.length ==0
  books.each_with_index do |book,i|
    puts "#{ i +1 }番:タイトル:#{book[:title]}著者:#{book[:author]}"
  end
  puts "検索したい番号を入力して下さい"
  number = gets.to_i
  puts "タイトルもしくは著者を入力して下さい"
  keyword = gets.chomp
  if books[number-1][:title].include?(keyword) || books[number-1][:author].include?(keyword)
    puts <<~EOS
         ----------検索結果---------------- 
         タイトル:#{books[number-1][:title]}
         
         著者は: #{books[number-1][:author]}

         ---------------------------------
         EOS
  else
    puts "検索できない"
  end
end

books = []

loop do  
  puts <<~EOS

      [1]本の登録を行う

      [2]本のタイトルと著者を検索する

      [3]本を終了する
      EOS
      input = gets.to_i

  if  input == 1
   register_book(books)
  elsif input == 2
    search_book(books)
  elsif input == 3
    exit
  else
    puts "無効な値です"
  end
end

rubyのメソッド

昔やって理解していたはずなのにすっかり忘れていた人たち

メソッド名 効果 式の例 式の実行結果
reverse 文字列の並びを反転させる事ができる "abcde".reverse "edcba"
"abcde".sort 条件指定して並び替え["a","b","c","d","e" ].sort{ a,b b<=>a }
upcase 文字列の小文字を大文字に "aaaa".upcase "AAAA"
downcase 文字列の大文字を小文字に "AAAA".dowmcase "aaaa"
capitalize 先頭の文字のみを変換する "hello".capitalize "Hello"

<DAY101> rubyメソッド、railsのお作法について

f:id:yujiro0320:20190512223713p:plain

はじめに

スクールのカリュキラムも終了し、これからは、復習となっていく。
毎日ある気づきを言語化し、何を学んだかを記載するブログとしていく。
AWSあたりは非同期通信あたりから学びを言語化する時間もなく愚直に課題をこなしていく形であったが、
定着しているスキルが薄いと感じる。

なので、改めて言語化する作業を注力してやっていく事にした。


文字を変換し出力する方法について(Ruby)

問題文

シーザー暗号と呼ばれる暗号があります。これはアルファベットをある文字数分ずらすという暗号方式で、例えば「a」を2文字分ずらす(進める)と「c」になります。
「frqjudwxodwlrq」という文字列があり、これを3文字ずらす(戻す)と復号できることがわかっています。それを実現させるコードを記述してください。

回答

word = "frqjudwxodwlrq"

nums = word.chars

chnage_word = []
nums.each do |num|
  chnage_word << (num.ord-3).chr
end

p chnageword.join

追加で覚えたメソッド

メソッド名 効果 式の例 式の実行結果
chars 文字列を一文字づつ取り出し配列に返す "aaa".chars ["a", "a", "a"]
ord 文字を数値に変換 "a".ord 97
chr 数値を文字に変換 97.chr "a"

ストロングパラメーターに追加で受け取るparamsを追記する(rails

中間テーブルのカラムを追加する時にやや引っかかりがあった。

入力フォームにてカラム名の指定を行うがtag_idsと複数形に記載しないとエラーになる。
実際のカラム名はtag_idなので、少しごっちゃになった。
中間テーブルにて定義したカラムは複数形にすると理解しておく。

colleciton_select :tag_ids, Tag.all,:id, :name, :prompt => "選択してください"

こんなフォームができる

f:id:yujiro0320:20190531154343p:plain


理解していない点

(1)ルビーのインクルメンタルサーチを使った記法

<DAY100>復習アウトプット用 Capistranoを利用した自動デプロイ

学習状況

●学習日数 100日

●学習時間(本日)8時間

●累計学習時間 450時間

●一日あたりの平均学習時間 4.5時間

Capistranoの導入

group :development, :test do
  gem 'capistrano'
  gem 'capistrano-rbenv'
  gem 'capistrano-bundler'
  gem 'capistrano-rails'
  gem 'capistrano3-unicorn'
end

読み込ませてコマンド打ちます。
ファイルを生成させる

bundle install
bundle exec cap install


Capfile
require により、引数としておかれた文字列が指すディレクトリが読み込まれ、
その中にデプロイに際して必要な動作が一通り記述

require "capistrano/setup"
require "capistrano/deploy"

require 'capistrano/rbenv'
require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano3/unicorn'

Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }

config/deploy/production.rb
本番環境に関する記述を追加する。

server '<用意したElastic IP>', user: 'ec2-user', roles: %w{app db web}

ここには、production環境、staging環境どちらにも当てはまる設定を記述することとなります。
具体的には下記のような項目があります。

アプリケーション名
gitのレポジトリ
利用するSCM
タスク
それぞれのタスクで実行するコマンド


config/deploy.rb

# config valid only for current version of Capistrano
lock '<Capistranoのバージョン>'

set :application, '自身のアプリケーション名'
set :repo_url,  'git@github.com:<Githubのユーザー名>/<レポジトリ名>.git'

set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system', 'public/uploads')

set :rbenv_type, :user
set :rbenv_ruby, '<このアプリで使用しているrubyのバージョン>

set :ssh_options, auth_methods: ['publickey'],
                  keys: ['<ローカルPCのEC2インスタンスのSSH鍵(pem)へのパス>']  

set :unicorn_pid, -> { "#{shared_path}/tmp/pids/unicorn.pid" }
set :unicorn_config_path, -> { "#{current_path}/config/unicorn.rb" }
set :keep_releases, 5

after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
  task :restart do
    invoke 'unicorn:restart'
  end
end

unicornも手動設定の時より一段ディレクトリが深くなっているため変更

config/unicorn.rb

app_path = File.expand_path('../../', __FILE__)

worker_processes 1

working_directory app_path
pid "#{app_path}/tmp/pids/unicorn.pid"
listen "#{app_path}/tmp/sockets/unicorn.sock"
stderr_path "#{app_path}/log/unicorn.stderr.log"
stdout_path "#{app_path}/log/unicorn.stdout.log"

 ↓↓↓↓↓↓↓ 以下のように変更 ↓↓↓↓↓↓

app_path = File.expand_path('../../../', __FILE__)

worker_processes 1

working_directory "#{app_path}/current"
listen "#{app_path}/shared/tmp/sockets/unicorn.sock"
pid "#{app_path}/shared/tmp/pids/unicorn.pid"
stderr_path "#{app_path}/shared/log/unicorn.stderr.log"
stdout_path "#{app_path}/shared/log/unicorn.stdout.log"

nginxの設定ファイルも同様に設定変更

location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }
      
 ↓↓↓↓↓↓↓ 以下のように変更 ↓↓↓↓↓↓

location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
    root   /var/www/<アプリケーション名>/current/public;
  }

自動デプロイ前の注意

Nginxの設定を変更したら、再起動
自動デプロイを実行する前にunicornのコマンドをkill
全てmasterにpushされていることを確認

sudo service nginx reload
 cd /var/www/<アプリ名>
kill -QUIT `cat tmp/pids/unicorn.pid`  #Unicornの停止

capistranoした場合、本番環境のディレクトリが一段深くなる件にについて

一度Capistranoによる自動デプロイを実行すると、本番環境のアプリケーションのディレクトリが変化します。
Capistranoによるアプリのバックアップなど、複数のディレクトリが作成されます。その中でも特に重要なのが、releases、current、sharedディレクトリです。


f:id:yujiro0320:20190821163756p:plain

releasesディレクト

capistranoを通じてデプロイされたアプリは、releasesというフォルダにひとまとめにされます。
ここに過去分のアプリが残っていることにより、デプロイ時に何か問題が発生しても一つ前のバージョンに戻ったりすることができます。
そして、その過去分の保存数を指定しているのがdeploy.rbのset :keep_releasesの記述となります。今回は5つ、過去のバージョンを保存するよう設定しました。

currentディレクト

releasesフォルダの中で一番新しいものが、自動的にcurrentというフォルダ内にコピーされているような状態になります。
そのため、このcurrent内に入っているアプリの内容が、現在デプロイされている内容ということになります。

sharedディレクト

バージョンが変わっても共通で参照されるディレクトリが格納されるディレクトリです。具体的には、log、public、tmp、vendorディレクトリが格納されます。

<DAY99>Nginxの導入(WEBサーバー)

*学習状況

●学習日数 99日

●学習時間(本日)11時間

●累計学習時間 442時間

●一日あたりの平均学習時間 4.46時間

要点まとめ

アプリケーションサーバとは、動的なコンテンツを生成し、処理結果をWebサーバの返すプログラム アプリケーションサーバには2つの役割が存在する Webサーバから依頼された情報を元に、動的なコンテンツの生成を行う。 処理結果を、Webサーバに返す処理 Unicornアプリケーションサーバの一種 NginxはWebサーバの一種

ターミナル(サーバ)

$ sudo yum install nginx

エディタを開いて

$ sudo vim /etc/nginx/conf.d/rails.conf

rails.conf

upstream app_server {
  # Unicornと連携させるための設定。アプリケーション名を自身のアプリ名に書き換えることに注意。
  server unix:/var/www/<アプリケーション名>/tmp/sockets/unicorn.sock;
}

# ()で囲った部分をブロックと呼ぶ。サーバーの設定ができる
server {
  # このプログラムが接続を受け付けるポート番号
  listen 80;
  # 接続を受け付けるリクエストURL ここに書いていないURLではアクセスできない
  server_name <Elastic IP>;

# 接続が来た際のrootディレクトリ
  root /var/www/<アプリケーション名>/public;

# assetsファイル(CSSやJavaScriptのファイルなど)にアクセスが来た際に適用される設定
  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  try_files $uri/index.html $uri @unicorn;

  location @unicorn {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://app_server;
  }

  error_page 500 502 503 504 /500.html;
}

POSTメソッドでもエラーが出ないようにする

[ec2-user@ip-172-31-25-189 ~]$ cd /var/lib
[ec2-user@ip-172-31-25-189 lib]$ sudo chmod -R 775 nginx  

。Nginxを再起動して設定ファイルを再読み込み

[ec2-user@ip-172-31-25-189 ~]$ sudo service nginx restart

<DAY98>unicoronを用いた本番環境構築

学習状況

●学習日数 98日

●学習時間(本日)9.5時間

●累計学習時間 431.0時間

●一日あたりの平均学習時間 4.39時間

unicoronの要点まとめ

unicoronって何??

アプリケーション本体を格納して、
動的処理を行うためのサーバー。

railsで使うまでの流れ

gem導入

```
group :production do
gem 'unicorn', '5.4.1'
end
```
bundle install

config/unicorn.rbファイルの設定

手動で上記ディレクトリに作成する。
これはunicornの動きを設定する内容
```
app_path = File.expand_path('../../', __FILE__)

worker_processes 1

working_directory app_path
pid "#{app_path}/tmp/pids/unicorn.pid"
listen "#{app_path}/tmp/sockets/unicorn.sock"
stderr_path "#{app_path}/log/unicorn.stderr.log"
stdout_path "#{app_path}/log/unicorn.stdout.log"

listen 3000
timeout 60

preload_app true
GC.respond_to?(:copy_on_write_friendly=) && GC.copy_on_write_friendly = true

check_client_connection false

run_once = true

before_fork do |server, worker|
defined?(ActiveRecord::Base) &&
ActiveRecord::Base.connection.disconnect!

if run_once
run_once = false # prevent from firing again
end

old_pid = "#{server.config[:pid]}.oldbin"
if File.exist?(old_pid) && server.pid != old_pid
begin
sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
Process.kill(sig, File.read(old_pid).to_i)
rescue Errno::ENOENT, Errno::ESRCH => e
logger.error e
end
end
end

after_fork do |_server, _worker|
defined?(ActiveRecord::Base) && ActiveRecord::Base.establish_connection
end

```

設定を済ませたコードをgithubにクローンする

以下のコマンドを入力して、ディレクトリを作成
ターミナル(サーバー)
```
~$ sudo mkdir /var/www/
~$ sudo chown ec2-user /var/www/
```

gituhubからコードのURLをコピーして

以下ディレクトリにクローンさせる
```
~$ cd /var/www/
www]$ git clone https://github.com/<レポジトリ名>.git
```

クローンしたディレクトリに移動し、

rbenvでインストールされたRubyが使われているかチェック

```
[ <レポジトリ名>]$ gem install bundler
[<レポジトリ名>]$ bundle install
```

環境変数に設定

データベースのパスワードなど、Githubにアップロードすることができない情報は、環境変数というものを利用して設定
これらの情報は、Railsからは ENV['<環境変数名>'] という変数からアクセスできる
環境変数は /etc/environment というファイルに保存

エディタを立ち上げて
```
sudo vim /etc/environment
```
書き込む内容はこれ
```
DATABASE_PASSWORD='MySQLのrootユーザーのパスワード'
SECRET_KEY_BASE='先程コピーしたsecret_key_base'
```

secret_key_baseを生成

ターミナル(サーバー)
```<レポジトリ名>]$ rake secret
```

環境変数設定後

一度ログアウトしてさらにログインしなおす

```
ssh -i [ダウンロードした鍵の名前].pem ec2-user@[作成したEC2インスタンスと紐付けたElastic IP]

```

環境変数確認のコマンド

```
env | grep SECRET_KEY_BASE
env | grep DATABASE_PASSWORD

```

ローカル環境に環境変数読み込みを定義

config/database.yml(ローカル)

```
production:
<<: *default database: ~~~(-------------) username: root password: <%= ENV['DATABASE_PASSWORD'] %>
socket: /var/lib/mysql/mysql.sock
```

本番環境に変更内容をPULLしてDATABASE作成

ターミナル(サーバー)
```
<レポジトリ名>]$ rails db:create RAILS_ENV=production
Created database '<データベース名>'<レポジトリ名>]$ rails db:migrate RAILS_ENV=production
...
```

アセットファイルをコンパイルする

本番環境では自動でしてくれないために手動で設定が必要

RAILS_SERVE_STATIC_FILES=1とつける事でアセットされたデーターを見つけてくれる
```
$ rails assets:precompile

$ RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production
```



railsの起動

```
unicorn_rails -c config/unicorn.rb -E productio

```

Nginxの導入と設定

補足(SSHキー鍵の登録)

githubの場合
EC2インスタンスSSH鍵ペアを作成.

```
ssh-keygen -t rsa -b 4096
```

以下のコマンドで生成されたSSH公開鍵を表示

```
cat ~/.ssh/id_rsa.pub
```
githubに登録

github.com

実際に登録できているかどうか確認
```
ssh -T git@github.com```