<DAY104>アプリ制作続き redcarpetとrougeの導入
学習状況
●学習日数 104日
●学習時間(本日)10時間
●累計学習時間 478.0時間
●一日あたりの平均学習時間 4.59時間
ドリルの復習(記載方法の違いについて)
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の情報分繰り返し実行されサーバーに不可がかかる為。
railsのMarkdown記載内容を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ってアプリを作り始めた。
学習状況
●学習日数 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コードと忘れていたメソッドメモ
学習状況
●学習日数 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のお作法について
学習状況
●学習日数 101日
●学習時間(本日)5時間
●累計学習時間 455時間
●一日あたりの平均学習時間 4.5時間
はじめに
スクールのカリュキラムも終了し、これからは、復習となっていく。
毎日ある気づきを言語化し、何を学んだかを記載するブログとしていく。
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 => "選択してください"
こんなフォームができる
理解していない点
(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ディレクトリです。
releasesディレクトリ
capistranoを通じてデプロイされたアプリは、releasesというフォルダにひとまとめにされます。
ここに過去分のアプリが残っていることにより、デプロイ時に何か問題が発生しても一つ前のバージョンに戻ったりすることができます。
そして、その過去分の保存数を指定しているのがdeploy.rbのset :keep_releasesの記述となります。今回は5つ、過去のバージョンを保存するよう設定しました。
currentディレクトリ
releasesフォルダの中で一番新しいものが、自動的にcurrentというフォルダ内にコピーされているような状態になります。
そのため、このcurrent内に入っているアプリの内容が、現在デプロイされている内容ということになります。
<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]
```
ローカル環境に環境変数読み込みを定義
config/database.yml(ローカル)
```
production:
<<: *default
database: ~~~(-------------)
username: root
password: <%= ENV['DATABASE_PASSWORD'] %>
socket: /var/lib/mysql/mysql.sock
```