【Gem】【Rails】RubyGemsにあるcarrierwaveをインストールすると最新バージョンなのに古い内容になってしまう

はじめに

Webサービスを開発していて、ハマったところなのでメモ。

環境

詳細

Amazon S3に対して、画像アップロード機能を作成したかったため
「carrierwave」を追加しました。

バリデーションエラーがなければ、指定したディレクトリに画像がアップロードされ
問題なかったのですが、バリデーションに引っかかった場合、画像が消えないように
一時ディレクトリに格納されるようにしていました。

しかし、画像が格納されず機能が実装されていない?と思い、ライブラリを調査しました。

コードに機能が実装されているか確認

GitHubに公開されているので、ソースを確認します。

github.com

途中、調査していたところ、0.10でAmazon S3に一時的にファイルが
アップロードされるようになったようなので機能はありそうです

github.com

バージョンの確認

bundle installした際に古いライブラリがインストールされている可能性があるため
アンインストールして、再度実行する。

...中略...
Installing carrierwave 0.11.2
...中略...

RubyGemsのサイトを見に行くと0.11.2が最新っぽいので大丈夫そうです。

carrierwave | RubyGems.org | your community gem host

ここまでやっても解決しません。

インストールされたライブラリを確認

実装したロジックがおかしいのかな?と考え、1つ1つ確認したところ問題なし。
そして、せっかくRubyMineを使っているのでIDEから該当箇所のロジックが
ないかどうかを確認しました。

確認したところ、追加されたロジックに関する内容がすべてありませんでした。
バージョンは確かに0.11.2というのに。

解決策

Gemfile

gem 'carrierwave'

上記の記述を以下のように修正

gem 'carrierwave', github: 'carrierwaveuploader/carrierwave'

ライブラリを直接GitHubから取ってくるようにしました。

Install carrierwave 0.11.0 from git://github.com/carrierwaveuploader/carrierwave.git (at master@b31f7ce)

原因

原因を探ろうと思ったのですが、検討がつかず時間が経ってしまったので
一旦前に進むようにします。謎すぎる。。。

【Rails】Capistranoでデプロイするとき「Devise.secret_key was not set. Please add the following to your Devise initializer:」が発生する

はじめに

Webサービスを開発していて、ハマったところなのでメモ。

環境

前提条件

エラーが出るところ以外、デプロイできる状態とします。

原因(なぜ、今までできていたか?)

config/secret.ymlに文字列を直接記述していたため。

staging:
  secret_key_base: 'test'

さらにdevise.rbの記述でsecret_key_baseを使うようにしていたため。

Devise.setup do |config|
  # The secret key used by Devise. Devise uses this key to generate
  # random tokens. Changing this key will render invalid all existing
  # confirmation, reset password and unlock tokens in the database.
  # config.secret_key = aqwsedrftgyhujikolp;''

  ...以下略....

改修した経緯

さすがに直接書くのはどうなの?という疑問からとなります。

改修

config/secret.yml

staging:
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>

config/deploy.rb

# Default value for default_env is {}
set :default_env, {
  rbenv_root: "/usr/local/rbenv",
  path: "/usr/local/rbenv/shims:/usr/local/rbenv/bin:$PATH",
  DEVISE_SECRET_KEY: ENV["DEVISE_SECRET_KEY"]
}

devise.rb

Devise.setup do |config|
  # The secret key used by Devise. Devise uses this key to generate
  # random tokens. Changing this key will render invalid all existing
  # confirmation, reset password and unlock tokens in the database.
  config.secret_key = ENV["DEVISE_SECRET_KEY"]

  ...以下略...

さらにWebサーバの環境変数にSECRET_KEY_BASE, DEVISE_SECRET_KEYの内容を記述する。

例:.bash_profile

export SECRET_KEY_BASE='secret_key'
export DEVISE_SECRET_KEY='devise_secret_key'

なぜ、このようにしたか?

改修は、見た通りやればいいと思うのですが、上記のようにした理由を書きます。
ある意味、ここからが本題です。

まず、すぐに思いつくのが以下のGemです。

github.com

自分も「これが手っ取り早いよなぁ?」と思っていたのですが、以下のエントリーを発見。

t-cyrill.hatenablog.jp

記事の最後の方に書いてありますが、StagingやProductionでは使われることは
望まれていないようです。確かに管理が簡単で.envに書けばすべて解決して、
わざわざ環境変数を設定する手間も省けてとても魅力的なものです。

ただ、運用するという面で見るとProduction環境は楽するよりも、
強固なシステムを作ることにウェイトを置くべきだと思うので、
これが今のところベストかな?と考えています。

【アジャイル】【設計】設計、実装に曖昧なところがあったので、スパイクを実施してみた

はじめに

備忘録レベルですが、同じような思いをしている方たちが
たくさんいるはずなので自分がやったことを書きます。

経緯

先月の話になりますが、転職をしまして職場に慣れるという意味で
実装を任されるとばかり思っていました。

しかし、経歴の考慮、タイミングにより基本設計から
アサインされることになりました。

いきなり設計?

今までの経験上、実装は追っていればすぐにわかる内容だったので
良かったですが、業務知識、システム知識がない状態でのアサインだったため
不安が先行していました。

まずは要件確認

設計、実装するのにもまず「何がやりたいのか?」ということを
はっきりさせて、自分の中に落とし込まなければいけないので
リーダーから事前にMTGがあり、それを復唱するような形で
要件を再確認しました。

設計と見積りの間に実施したこと

要件は確認できて、さてどうしたものか?と考えました。
まず、自分で設計して実装するだけなら自分であーだこーだやれば
いいのですが、今回は若手メンバー含めての対応なのでそうはいきせん。

そこで、設計と見積りの期間を多めにもらい(もらっていたとも言う)
実施したのが、アジャイルプラクティス(スクラム)のスパイクです。

Spikes « Scaled Agile Framework

これは技術的なリスク、機能的なリスクが事前にわかっている場合に
実際の実装行程ではなく、最初に「動くもの」を作るというものです。
さらに心配症な人に取っては、ありがたいもので少しでも「これでいける!」
と思えれば自信を持って案件に着手できます。
さらにメンターに取っては事前に技術的、機能的な道筋が立っているので
教える立場となったときも「教える計画」を立てることができます。

そして、最後に自分の中で考えついた設計、見積りを共有して
「こんな感じでやります」というのを実施しました。

スパイクをやってみて

結局、メンバーは2人にしてもらい、案件リーダー兼技術リーダーっぽい
状況になりましたが、自分である程度、道筋を立てているので予定通りにいけば
それで問題ないです。

ただし、スパイクで実装したときはあくまで「プロトタイプ」の位置づけなので
実際に実装行程となった場合、考慮していなかったことや疑問点が必ずと言っていいほど出てきます。
しかし、道筋を立てているので、少しのズレがあっても修正できますし
大きなズレがあった場合も気づきやすいという点も大きなメリットがありました。

まとめ

アジャイルプラクティス」というのはすべてをいっぺんにやろうとすると
崩壊する確立が高いですし、計画倒れ、形骸化する傾向があります。
ただ、自分だけでやれることがあれば、自分の頭の整理になったり
プロジェクトの計画も立てやすくなると思うので、小さいプラクティスを
少しずつ導入して、効率が良く不安要素がない開発にしていければと考えています。

最後になりましたが「スパイク」という単語が出てこないため
Twitterでぼやいたところ、プラクティス名を教えていただいたぺらさんに感謝です。

【転職】転職しました。

はじめに

今年の4月1日から新しい会社で働くことになりました。

経歴

  • 新卒としてSIerに就職
  • 様々な現場に出向して、システム開発に携わる。
  • 3/31限りで、今の会社を退職しました。
  • 4/1から新しいところで仕事をしています。

前職を振り返ってみて

システム開発とはこういうもんじゃ!」というのを教えてもらった
偉大なる方たちと共に仕事をしたり、若手の教育を任せてもらい
教えることの難しさや自分がいかに理解できていないことを身をもって
知れたところがとても大きかったです。

なぜ、転職したか?

SIerのときは「何でもいいからプログラムを組んでいたい!」と感じていたので
あまり苦ではなく「設計書書こう!プログラム書こう!テスト書こう!いろいろやろう!」
という思いでやってきました。

ただ、ここ最近になって「それだけでいいのか?」ということを
強く思うようになり、一大決心をした次第です。

どうやって転職活動したか?

同じような境遇にあたる人もいるかと思うので
どうやって活動したか簡単に説明します。

まず、どんな企業があるかどうか研究をしたかったため以下のサイトを活用しました。

www.wantedly.com

Wantedlyは、いきなり「面接」ではなく「会社見学(面談)」から
始めることができ、良い会社であればそのまま選考にいける
ソーシャル・リクルーティング・ツールです。

スケジュールを自分で調整でき、カジュアルな感じ会うことができるので
企業研究という意味でもかなりハードルは低いと思います。

「転職活動とは言えないまでも、他の会社はどういうところだろう?」
という活動には持って来いだと思います。

その後、本格的にエージェントを通じていろいろと研究をして
今の会社から、無事に内定をいただき、転職活動終了となりました。

今後、どうしていきたいか?

Webサービスのノウハウを貯めつつ、ふと思いついたものを
どんなに小さなものでも形にしていき、自分が作ったもので
世の中を便利にしていけるようなものを作っていければと考えています。

さらにSIerのときに培ったものを別の場所で発揮して
今までやってきたことの復習とさらなる磨きをかけるようにしていきます。

一言で言ってしまうと
システム開発」ではなく「サービス開発」をしていく。

次はどこ?

次はSIerではないところで働きます。いわゆるWeb系というところです。 本当に0からスタートなので、ビクビクしていますが
成長する上で必要なことなので、必至になって頑張っていきます。

さらに外部での勉強会や内部の勉強会にもかなり好意的な面があるので、
今はまだ転職したばかりなので様子見な状態ですが、前の会社より
積極的に動けると考えています。

現状

ちょうど1ヶ月終わったので、振り返りをしてみます。

新しい職場ですが、新しいところでやり方も違いますし
新しい方たちとの業務なので慣れるので精一杯だったな
というのが第一印象です。

しかし、前職での反省点をいかして
「なぜ、この会社はこういう制度(開発)なのか?」
「自分の実力はこういう感じなので、ここにコミットできます」
「今後、こういうことをやりたいので既存で何かいい方法ありますか?」
など、1つ1つ共有をして自分を知ってもらいつつ、自分がやりたいことに
少しでも前に進んでいる状況です。

【Rails】【Bower】Staging(Production)環境でAsset PipelineでFont,Imageパスが取得できず404なってしまう場合

はじめに

AdminLTEはGemとしてもあったのですが、勉強も兼ねてbower-railsを使って
個人プロジェクトでbower-railsを使いつつ、AdminLTEを使って
管理画面を作成した際にハマったことをメモします。

なお、bower-railsとAdminLTEの初期インストールなどは割愛します。
HTMLテンプレートはSlimを使用しています。

結論

bowerのAdminLTEのものを使わず、FontやImageのパスを
Railsの機能で置き換え済みのGemを使用して解決した。

なお、Bootstrapのglyphiconは解決できなかったため
アイコン系は、font-awesomeに置き換えた

環境

Capistranoを使い、Vagrantに対してデプロイする設定をしています。

原因

Bowerで取得したライブラリのFontパスとImageパスが相対パスとなっていて プリコンパイルされた際にapplication.css, application.jsにすべて集約されてしまうため
パスがおかしくなってしまう。

詳細

以下の様な状態でbowerで設定していた。

f:id:fujikawa-y:20160421093602p:plain

「application.css.scss」は以下の通り

/*
 *= require admin-lte/bootstrap/css/bootstrap
 *= require admin-lte/dist/css/AdminLTE
 *= require admin-lte/dist/css/skins/skin-blue
 *= require admin-lte/plugins/iCheck/minimal/blue.css
 *= require fontawesome/css/font-awesome
 */

「application.js」は以下の通り

//= require jquery
//= require jquery-ujs
//= require admin-lte/bootstrap/js/bootstrap
//= require admin-lte/dist/js/app.js
//= require admin-lte/plugins/iCheck/icheck.min.js

上記の状態でデプロイをすると以下の様なエラーが発生してしまう。
f:id:fujikawa-y:20160424072533p:plain f:id:fujikawa-y:20160424072546p:plain

理由

Bowerでライブラリをインストールした場合、application.css, application.jsに
まとめられてしまいAsset Pipelineの考慮がされていないため。

調査

実際にbower_componentsのAdminLTEを参照すると以下のように記述してある。 例1:/bower_components/admin-lte/bootstrap/css/bootstrap.css(抜粋)

@font-face {
  font-family: 'Glyphicons Halflings';

  src: url('../fonts/glyphicons-halflings-regular.eot');
  src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
}
.glyphicon {
  position: relative;
  top: 1px;
  display: inline-block;
  font-family: 'Glyphicons Halflings';
  font-style: normal;
  font-weight: normal;
  line-height: 1;

  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

例2:/bower_components/fontawesome/css/font-awesome.css(抜粋)

@font-face {
  font-family: 'FontAwesome';
  src: url('../fonts/fontawesome-webfont.eot?v=4.6.1');
  src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.6.1') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.6.1') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.6.1') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.6.1') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.6.1#fontawesomeregular') format('svg');
  font-weight: normal;
  font-style: normal;
}

問題なのは以下の箇所

url('xxx');

Qiitaに記事が書かれている。 qiita.com

qiita.com

また、公式ドキュメントも確認する。 railsguides.jp

解決方法

Railsのためにパスを置き換え済みのGemを使用する。

Gemfile

gem 'icheck-rails'
gem 'font-awesome-sass'

bundle installを行い、css, jsは以下の通りに記述する。

application.css

@import "icheck/minimal/blue";
@import "font-awesome-sprockets";
@import "font-awesome";

application.js

//= require icheck

まとめ

RailsJavascript, css周りはAsset Pipelineで意図しない動きになってしまうことが
よくわかった今回の内容でした。ローカル環境で動いたと喜んでいないで
サーバにデプロイして、ちゃんと動く、表示されたら喜ぶようにしようと思いました。

【Rails】【Capistrano】Capistranoでmasterブランチ以外のブランチでデプロイしたい場合

はじめに

デプロイの成功例と失敗例を試したいときに
「失敗したところのブランチでデプロイしたい」
ということが自分の中であったのでメモ。

※大体、勢いで直してしまうので「よし記事にしよう!」と思ったときに
その状態が残っておらず、失敗したところを再現しなければいけないと思ったため。

環境

前提条件

Capistranoでデプロイできている状態とします。

やり方

deploy.rbに以下のように記述します。

set :branch, ENV['BRANCH'] || "master"

そして、実行する際は以下のように書きます。 例:developブランチでStaging環境の場合

$ BRANCH=develop cap staging deploy

指定したブランチでデプロイされます。
以下、その時のログの抜粋

$ DEBUG [1e078acd] Command: cd /var/www/sample/repo && ( RBENV_ROOT=/usr/local/rbenv PATH=/usr/local/rbenv/shims:/usr/local/rbenv/bin:$PATH RBENV_VERSION=2.3.0 GIT_ASKPASS=/bin/echo GIT_SSH=/tmp/sample/git-ssh.sh /usr/bin/env git rev-list --max-count=1 --abbrev-commit develop )

...中略...

$ INFO [xxxxxx] Running /usr/bin/env echo "Branch develop (at develop) deployed as release 20160422001729 by FujiYasu" >> /var/www/sample/revisions.log as www@192.168.33.20
$ DEBUG [xxxxxx] Command: echo "Branch develop (at develop) deployed as release 20160422001729 by FujiYasu" >> /var/www/sample/revisions.log

この辺の設定は、Jenkinsでのデプロイ時に使える手だと思うので
必須の手だと思いました。覚えておきます。

【Rails】URLでlocaleがある場合、Deviseのリダイレクトでlocaleが外れてしまう

Railsで管理画面を作っている際に発見した現象をメモ

現象

以下の様なルーティングを設定した場合
※ディレクトリは自分でわかりやすいようにカスタマイズしています。

Rails.application.routes.draw do

  scope "(:locale)" do
    namespace :admin do
      devise_for :admin_users, controllers: { sessions: 'admin/devise/sessions' }
      get '/', :to => 'home#index'
    end
  end
end

ルーティングは以下のようになります。
※ディレクトリは自分でわかりやすいようにカスタマイズしています。

        new_admin_admin_user_session GET    (/:locale)/admin/admin_users/sign_in(.:format)       admin/devise/sessions#new
            admin_admin_user_session POST   (/:locale)/admin/admin_users/sign_in(.:format)       admin/devise/sessions#create
    destroy_admin_admin_user_session DELETE (/:locale)/admin/admin_users/sign_out(.:format)      admin/devise/sessions#destroy
                               admin GET    (/:locale)/admin(.:format)                           admin/home#index

ApplicationControllerは、以下の通り

class ApplicationController < ActionController::Base

  before_action :set_locale

  def set_locale
    I18n.locale = params[:locale] || I18n.default_locale
  end

  def default_url_options(options = {})
    { locale: I18n.locale }.merge options
  end

  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception
end

この設定で、未ログインで管理画面に行くとログイン画面に
リダイレクトされるのですが、URLのlocaleが外れてしまいます。

解決策

ApplicationControllerに以下の記述をすれば、localeが外れずに済むようです。

  def self.default_url_options
    { :locale => I18n.locale }
  end

ただし、なぜクラスメソッドにすると大丈夫なのか理由がわからず・・・
こういうところをスムーズに解決、理由を話せるようになりたいです。

stackoverflow.com