ポンコツ.log

ひよっこエンジニアのちょっとしたメモ。主に備忘録。たまに雑記。

2016年と2017年と

年も明けたので去年を軽く振り返りつつ、今年を考えつつ。

2016年の初めにマンダラチャートを書いていたので、それを見ながら振り返っていると、半分も出来ていない現実に出くわしてただのガチクズじゃないかと絶望しています。
中でも一番出来ていないところが、知識の「インプット&アウトプット」のアウトプット部分。
このブログを眺めるだけでも全然書けてない感がにじみ出ている(かといって他になにかしらを投稿し続けたわけでもない)ので、言い訳しようもないですね。
インプットに関しても、Web上の記事ならすぐ読んでいたものの、積ん読状態の本が発生していたので、2017年は年末に積ん読本がない状態にしたいです。
この部分は2017年も引き続き手を入れたいところ。

それと、いろいろなことに繋がるのが時間管理が下手すぎたというのも。
ワークライフバランスで言うとワークに寄ったところもあったので、うまくバランスをとって行きたかったものの、半年ぐらいしか保たず、結局ワーク寄りに…。
そもそもバランスをとりたいと思ったのも、趣味の時間を確保したい&先を考えてのことなので、ここも2017年引き続きになりそうです。

反面、エンジニアとしての技術的なところは割とできたかな…という印象です。
機械学習とかの話題の分野もちょこっとつま先突っ込んでみたり、競技プログラミング再入門してみたり。
誰でもそうだと思いますが、興味持って進められるところはやっぱり出来るんだろうなー。
今まで付け焼刃なところもあるので、2017年はもうちょっと突っ込んだところの理解もできるようにしていきたいです。サーバ周りやフロント周りを特に。
ハード関わるところが「興味ある〜」止まりだったので、何かしらのアクションを起こせるようにしたいです。

相変わらず反省するところしかないなーということに気づいたので、年末振り返る時には「ただのガチクズ」卒業できていることを祈ります。

利尻&稚内へ行ってきました - 2日目 利尻&稚内編

利尻&稚内旅メモの続編になります。
->利尻編はこちら

2日目は14時頃のフェリーで稚内へ渡る予定だったので、それまでの間に姫沼まで足を伸ばしました。
バス本数が少なく、時間が合わなかったので徒歩でフラフラと。
後から思えばフェリーのレンタルサイクル利用すれば良かったなと思いました…早く気付けよと…。

鴛泊のフェリーターミナルから姫沼までは4キロと少し。徒歩1時間ほどでした。
ところどころ、先の台風による土砂崩れの痕跡が残っていたりして、本当に台風来ていたんだなあと。
恐らく上の方にあった木が歩道の横まで滑り落ちていたり、土嚢が積まれていたり、歩道が泥だらけだったり。
台風の影響を気にしながら進むと姫沼への案内板があったので、案内の通りに右折。
山の方へ向かうのでずっと上り坂になります。上り坂の途中に展望台がありました。

▼姫沼展望台 f:id:mr_96:20160922215959j:plain

展望台を出てもう少し坂を登ると、やっと姫沼につきます。
▼姫沼 f:id:mr_96:20160924222734j:plain

姫沼からも利尻富士が見えます。
▼姫沼からの利尻富士 f:id:mr_96:20160924225128j:plain

姫沼は周回の道があったのですが、うっかり反時計回りに歩いてしまい途中団体客とすれ違う時に数分足止めになったりしました。
周回は時計回りのようです。気をつけます。
ここでも土砂崩れの影響か、大きめの木が根から横倒しになっていたりしました。

帰りは下り坂なので、行きと違って楽ですね…。
途中、海に寄って遊んだりしながらフェリーターミナルに戻り、しばし休憩タイム。

鴛泊-稚内間はフェリーで約1時間40分ほど。
ハートランドフェリーでは、2等室を指定する場合は予約不要のため、当日自動券売機にて購入するようです。
他のフェリーでは連絡先等を申込書に記入し、窓口で受付してから乗船券を発行していたので、「この簡単手続きで良いのだろか…」と不安になったものの、特に問題なく乗船できました。
時期によっては、フェリーからイルカを見ることもできるようですが…乗船後数分で寝てしまったため、今回はイルカの確認どころか景色もほとんど見ずにフェリータイム終了。

稚内に着いた時間がもう夕方だったので、この日は宿へ直行しました。

利尻&稚内へ行ってきました - 1日目 利尻編

帰省に合わせて、ふと行ってみたくなった利尻と稚内へ2泊3日で行ってきました。
その記録を兼ねた旅メモ。

13時10分新千歳空港発の飛行機で利尻空港へ。
移動時間はおよそ50分。14時に利尻空港へ到着しました。
空港出口のところに、ホテル名が書かれた旗を持った方がたくさんいらっしゃいました。
空港から宿泊地まで距離があるからか、送迎の車を出してくれるところが多いようです。
慣れない土地に来た身としては嬉しいですよね。

宿泊先で自転車が借りられたので、自転車を借りて早速観光へ。
利尻はサイクリングロードなる自転車専用道路(途中途中で、歩道との併用区間あり)があり、それも綺麗に舗装されていたりと結構良い道だったので景色を眺めながらサイクリングが楽しめました。
滅多に人も通らないので、マイペースで進んでも問題なし。
途中、野生のイタチに遭遇するというラッキーハプニングもありました。むっちゃ可愛い…。

鴛泊から出発して、沓形方面へ反時計回りにまっしぐら。
道中にちょっとした休憩スポット数箇所もありました。
▼名称忘れてしまいましたが、設置されていた日時計利尻富士
f:id:mr_96:20160922224207j:plain

出発が14時30分頃というのもあって、沓形の手前辺りで折り返して鴛泊方面へ。
夕日ヶ丘展望台へ行こうとしたところ、手前に「富士野園地」と書かれた看板が目に入ったので、フラフラと寄り道。
知らずに行っていたのですが、『北のカナリアたち』のロケ地にもなったところでした。
簡易トイレもあり、休憩スポットでもあるようです。
ポンモシリ島という小島がよく見えます。
▼ポンモシリ島
f:id:mr_96:20160922223539j:plain

そして夕陽ヶ丘展望台。 自転車で爆走した後に展望台頂上までの階段を登り、すっかり息が上がっていましたが、そんな疲労感も吹っ飛ぶような景色でした。…体力つけねば。
▼夕陽ヶ丘展望台頂上からの眺めその1 f:id:mr_96:20160922220020j:plain ▼夕陽ヶ丘展望台頂上からの眺めその2 f:id:mr_96:20160922225609j:plain ▼夕陽ヶ丘展望台頂上からの眺めその3
夕焼けには少し早めでしたが、十分綺麗でした。 f:id:mr_96:20160922225828j:plain

1日目は早々に宿泊先へ戻ったので、続きはまた後日。

【Rails】simple_form製ラジオボタンのラベルにクラスを指定する

simple_form、使うとform_forがすっきりするので良いですよね。
そんなsimple_formを使ってラジオボタンのラベルにクラスをつけようとすると、思いっきりはまって、「あれ、simple_form使えない…?」と思ってしまったのでメモ。
結果的にはsimple_formで解決しました。 github.com

※ viewテンプレートはSlimを使っています。

ノーマルラジオボタン

まず普通にラジオボタンを表示させるのであれば、下記のような書き方で問題なく表示されます。

# plans = {1 => 'もう半分終わるらしい' , 0 => 'まだ半分あるらしい'}

= simple_form_for :sample, url: test_path, html: {method: :post, class: 'sample_form'} do |f|
  p 2016年
  = f.collection_radio_buttons :plans, plans.to_a, :first, :last

実際の表示↓ f:id:mr_96:20160619231800p:plain

HTMLだとこんな感じです。

<form class="simple_form sample_form" novalidate="novalidate" action="/test" accept-charset="UTF-8" method="post">
  <input name="utf8" type="hidden" value="✓">
  <input type="hidden" name="_method" value="post">
  <input type="hidden" name="authenticity_token" value="AUTHENTICITY_TOKEN">
  <p>2016年</p>
  <span>
    <label for="payment_plans_1">
      <input type="radio" value="1" name="payment[plans]" id="payment_plans_1">
      <label class="collection_radio_buttons" for="payment_plans_1">もう半分終わるらしい</label>
    </label>
  </span>
  <span>
    <label for="payment_plans_0">
      <input type="radio" value="0" name="payment[plans]" id="payment_plans_0">
      <label class="collection_radio_buttons" for="payment_plans_0">まだ半分あるらしい</label>
    </label>
  </span>
</form>

ラジオボタンのラベルにクラスをつける

やりたいことはノーマルラジオボタンでなく、ラベルにクラスをつけて、独自のスタイルを適用することです。
この「ラベルにクラスをつける」方法がわからず、ドはまりしました。
いろいろと調べているうちに、StackOverflow内にて回答を発見。
blockを使えば良いらしい。
ruby - simple_form's collection_radio_button and custom label class - Stack Overflow

# plans = {1 => 'もう半分終わるらしい' , 0 => 'まだ半分あるらしい'}

= simple_form_for :sample, url: test_path, html: {method: :post, class: 'sample_form'} do |f|
  p 2016年
  = f.collection_radio_buttons :plans, plans.to_a, :first, :last do |b|
      - b.radio_button + b.label(class: 'sample_radio')

実際の表示↓ f:id:mr_96:20160619231903p:plain

HTMLだとこんな感じです。

<form class="simple_form sample_form" novalidate="novalidate" action="/test" accept-charset="UTF-8" method="post">
  <input name="utf8" type="hidden" value="✓">
  <input type="hidden" name="_method" value="post">
  <input type="hidden" name="authenticity_token" value="AUTHENTICITY_TOKEN">
  <p>2016年</p>
  <span>
    <label for="payment_plans_1">
      <input type="radio" value="1" name="payment[plans]" id="payment_plans_1">
      <label class="sample_radio" for="payment_plans_1">もう半分終わるらしい</label>
    </label>
  </span>
  <span>
    <label for="payment_plans_0">
      <input type="radio" value="0" name="payment[plans]" id="payment_plans_0">
      <label class="sample_radio" for="payment_plans_0">まだ半分あるらしい</label>
    </label>
  </span>
</form>

若干わかりにくいですが、無事、ラベルに「sample_radio」クラスが当たっています。

item_wrapper_classオプションでできるよ!」とか「input_htmlオプションでいけるかも!」といったものを見たので色々試してみたのですが、あえなく全滅し、「simple_form全然シンプルじゃない!」と思って一瞬form_forに傾きかけました。
シンプルじゃないとか思ってスミマセン。

【Itamae】remiリポジトリのPHPをインストールする

1ヶ月ほど前にItamae入門しました。

Itameを使ってvagrant(centOS6.5)上にphpをいれようとすると、バージョン5.3.3がインストールされるのですが、諸事情により5.3.6以上のバージョンを使いたかったので、remiリポジトリからインストールすることに。
そのときのItamaeレシピメモ。

ちなみに、諸事情というのは、PDO×MySQLPHPのプロジェクトで、インスタンス指定時にcharsetが使われていたため。
5.3.6以上であればcharset指定が有効なので、文字化けが回避できる。
5.3.6以前のバージョンでは、charsetではなくSET NAMESで指定することで回避できるらしいです。
参考:MySQLとPDOの組み合わせでcharsetを指定する - Qiita

remiリポジトリの追加

epelリポジトリのインストール+rpmコマンドでremiリポジトリを追加する。

# cookbooks/yum/default.rb

package 'epel-release' do
  action :install
end

package "http://rpms.famillecollet.com/enterprise/remi-release-#{node[:platform_version][0]}.rpm" do
  not_if 'rpm -q remi-release'
end

phpをインストール

追加したremiリポジトリからphpをインストール
ついでに必要なパッケージ群もインストール

# cookbooks/php/default.rb

%w( php php-mbstring php-xml php-gd php-pear php-mysql ).each do |pkg|
    package pkg do
      options '--enablerepo=remi'
      action :install
    end
end

確認

あとはinclude_recpephpインストールするdefault.rbを指定して、itamaeコマンドを実行すると、remiリポジトリからのphpインストールが完了する。
itamaeが無事終了後、phpバージョンを確認

[vagrant@vagrant-centos65 ~]$ php -v
PHP 5.4.45 (cli) (built: May 29 2016 09:17:38)
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2014 Zend Technologies

5.3.6以上のバージョン。勝てる。
ついでにinfoも。

[vagrant@vagrant-centos65 ~]$ yum info php
Installed Packages
Name        : php
Arch        : x86_64
Version     : 5.4.45
Release     : 9.el6.remi
Size        : 9.4 M
Repo        : installed
From repo   : remi

remiリポジトリからインストールされていることを確認。

capistranoでデプロイしたときにunicornが再起動しない対応

capコマンドを使ってデプロイしたあと、unicornが再起動していないことが頻発します。

$ ps -ef | grep unicorn | grep -v grep
user  1234     1  0 19:08 ?        00:00:03 unicorn master -E staging -c <PRJ_ROOT>/current/config/unicorn/staging.rb -D
user  5678  1234  0 19:08 ?        00:00:00 unicorn worker[0] -E staging -c <PRJ_ROOT>/current/config/unicorn/staging.rb -D
user  9102  1234  0 19:08 ?        00:00:00 unicorn worker[1] -E staging -c <PRJ_ROOT>/current/config/unicorn/staging.rb -D

プロセスの起動時間がデプロイ時間より古ければ明らかにおかしいので、ひとまずログを確認。
すると、下記のようなログがあります。

I, [2016-06-06T16:01:57.399854 #26684]  INFO -- : forked child re-executing...
<HOME_DIRECTORY>/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/bundler-1.12.5/lib/bundler/definition.rb:23:in `build': <PRJ_ROOT>/releases/20160603064119/Gemfile not found (Bundler::GemfileNotFound)

Bundler::GemfileNotFound なんて言われているけれど、確認するとちゃんとGemfileはあるのでオカシイ。
よく見ると、Gemfileを読み出そうとしている/releases以下のディレクトリ、この時点では既に過去のバージョンのものなので、ディレクトリ自体なかったりします。
なぜか古いGemfileを読み出そうとして、GemfileNotFoundを引き起こしている模様。

調べてみると、ENV['BUNDLE_GEMFILE']の値に古いGemfileのパスが入っていて、その値を利用してプロセスを起動するため「Gemfileないよ!」と言われているらしい。
対応として、before_execで明示的にパスを指定してあげれば、新しいGemfileを読みだすようになる。

# config/unicorn/staging.rb
current_dir = "<PRJ_ROOT>/current"
before_exec do |server|
  ENV['BUNDLE_GEMFILE'] = File.expand_path('Gemfile', current_dir)
end

なんで起きるんだろう。

参考:
Capstarano3でデプロイ時にUnicornが再起動しているようで失敗している時の対処法 - Qiita

S3上にあるファイルがうまく参照できないときのCORS設定

RailsでassetsファイルをS3に上げて、そこにある画像を参照しようとすることはよくあると思うのですが、その際にCORSではまったので対応メモ

Font-Awesomeを使おうとしてエラー

Font-Awesomeを使って表示しているところが、いわゆる豆腐状態(本来フォントが表示されて欲しいところが、□しか表示されない残念な状態)になっていたので開発者ツールのConsoleを確認。
すると、下記のようなエラーが表示されていました。

Font from origin 'https://hoge-bucket.s3.amazonaws.com' has been blocked from loading by Cross-Origin Resource Sharing policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://hogehuga.com' is therefore not allowed access.

※ URLはダミーのものです

エラー対応

おとなしくググってみると、S3上でAccess-Control-Allow-Originを設定しなければないけない、とのこと。

S3のバケット一覧へアクセスし、該当のバケットのプロパティを表示。
プロパティを表示すると画像のような表示が見えるので、アクセス許可のメニューを展開し、CORS設定の編集を選択。 f:id:mr_96:20160601235329p:plain

すると、CORS 構成エディターなるモーダルが表示されるので、テキストフォームにCORSルールを記述します。 <サンプル>

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Authorization</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

f:id:mr_96:20160602000020p:plain

S3側での設定は終わったので、Web上で確認すると、期待した通りに表示されています。
一件落着。

参考:
Cross-Origin Resource Sharing (CORS) - Amazon Simple Storage Service

CORSについて:
CORSまとめ - Qiita

【Rails】sitemap_generatorでsitemapを生成して、S3AdapterでS3にアップロードする

sitemap_generatorを使って生成したsitemapをS3にアップロードする方法で、S3Adapterを使った方法の実装メモ github.com

sitemap生成準備
Gemfileにsitemap_generatorを追加してbundle install

# Gemfile
gem 'sitemap_generator' 

sitemapをインストールして設定ファイルを生成する

$ bundle exec rake sitemap:install
#=> config/sitemap.rbが生成される

設定
生成された設定ファイルにsitemapに出力するパスなどを記述する
ここでSitemapGenerator::Sitemap.adapterS3Adapterを指定するとCarrierwaveを使わずに指定S3へアップロードできる

# config/sitemap.rb
# 自分のサイトURL
SitemapGenerator::Sitemap.default_host = "http://hoge.com"
# アップロード先になるS3のURL
SitemapGenerator::Sitemap.sitemaps_host = "https://BUCKETNAME.s3.amazonaws.com/"
# アプリケーション内のsitemap生成先ディレクトリ
SitemapGenerator::Sitemap.public_path = 'public/'
# sitemap配置ディレクトリ
SitemapGenerator::Sitemap.sitemaps_path = 'sitemaps/'

# S3Adapterを利用してS3へアップロードする
SitemapGenerator::Sitemap.adapter = SitemapGenerator::S3Adapter.new({
  fog_provider: 'AWS',
  fog_directory: BUCKETNAME,
  fog_region: REGION,
  aws_access_key_id: ACCESS_KEY_ID,
  aws_secret_access_key: SECRET_ACCESS_KEY
})

SitemapGenerator::Sitemap.create do
  Article.find_each do |article|
    add article_path(article), lastmod: article.updated_at, changefreq: 'daily'
  end
end

参考:ECサイトの開発運用に必要になった技術メモ: Railsでsitemap_generator使ってS3にサイトマップを作成する方法

確認
sitemapの生成はrake sitemap:refresh
rake sitemap:refresh:no_pingのようにするとGoogleなどの検索エンジンに更新通知せずに、sitemapだけ更新できる

$ bundle exec rake sitemap:refresh:no_ping
#=> public/sitemaps/sitemap.xml.gzが生成される(public_path + sitemaps_path + sitemapファイル)

周辺設定
/sitemap.xml.gzにアクセスされたら、S3上のsitemapにリダイレクトさせる設定を追加

# config/routes.rb
get 'sitemap.xml.gz', to: redirect('https://BUCKETNAME.s3.amazonaws.com/sitemaps/sitemap.xml.gz')

public/robots.txtファイルにsitemapの場所を指定することで、検索エンジンにsitemapの参照場所を伝えることができる

# robots.txt
Sitemap: https://BUCKETNAME.s3.amazonaws.com/sitemaps/sitemap.xml.gz

参考:robots.txt ファイルについて - Search Console ヘルプ
参考:robots.txtファイルでサイトマップの場所を指定 - Google Search Consoleの使い方(旧ウェブマスターツール)