railsでバイナリー画像データの表示メソッドを共通化する方法

railsはやっぱ楽しい!
最近、ようやくrails wayに乗れるようになって来たなと実感しているGakuです。

今回は、よく実装することがあるバイナリー画像データの表示メソッドについて、良いなと思った書き方を見つけたのでご紹介します。

良く紹介されている画像表示

railsでDBに格納している画像をWebページ上に表示しようと思うと、少々めんどくさいです。
良く他の方のブログページを漁っていると見つかるコードは以下のようなものです。

<%= image_tag(avatar_for_user_path, alt: @user.name, :size => '40x40') %>
Rails.application.routes.draw do
  resources :users do
    member do
      get 'avatar_for'
    end
  end
end
def avatar_for
  @user = User.find(params[:id])
  send_data(@user.avatar)
end

こんな感じです。アバター画像を表示するのはいいのですが、コントローラー部分でModelと表示する画像データが入っているcolumnを決め打ちで実装しているので、これ以外の画像データを表示しようと思うと、routingのコードとcontrollerのコードに新たにコードを追加しなければいけません。
これは太っちょコントローラーパターンに陥る危険性もあるため、何としてでも共通化しておきたいところです。

バイナリ画像データ表示メソッドの共通化

ってことで今回は以下のようなコードを書いて共通化してみました。

<%= image_tag(url_for(:controller => 'application', :action => 'show_image', :id => @user.id,:model => "User", :column => "avatar"))%>
Rails.application.routes.draw do
  get '/show_image', to: 'application#show_image'
end
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception

  def show_image
    @model = params[:model].constantize.find(params[:id])
    send_data @model[params[:column]], :type => 'image/jpg,image/jpeg,image/png,image/gif', :disposition => 'inline'
  end
end

applicationコントローラへshow_imageというメソッドを作成し、そこにモデル名とカラム名とidを渡し、send_dataで返却するというコードです。
こうすることでview部分は従来コードより肥大化しますが、コントローラとルーティングコードはどれだけ表示する画像カラムが増えても追記する必要はありません。
共通化万歳です( ^∀^)b

おわりに

railsは早いし、書き方覚えると気持ちよく書ける非常に楽しいフレームワークだなと再実感しています。
逆にrails wayに乗れないと途端に気持ち悪いコードになるので、すぐに「対処しよう!」という気にもなります。

本当最速で書けるので、PJなんて一人で回せばいいんじゃね?納期なければ。。。と考える今日この頃です。

docker-composeを使用し、最速でrails5+postgresqlを導入する

Gakuです。

ひっっさしぶりのrailsです!
会社でrails5を使用したWebシステムの構築を検討しているため、ひっさしぶりにrailsを触ることになりました。
以前のようにvagrantで開発環境を構築してもいいのですが、めんどうです。
また、他の開発者にも速攻で開発環境を導入できるということからdockerを使用して開発環境を構築してみました。

前提

これはdockerとdocker-composeが既に導入されていることを前提に進めていきます。
まだ入れていないよ〜という方は、こちらの記事を参考にして導入してみて下さい。

構築

ファイル構成

./
|-docker-compose.yml
|-web/
|  |-Dockerfile
|-app/    //共有フォルダ

以上です。

docker-compose.ymlの編集

docker-compose.ymlを以下のように編集します。

version: "3"

services:
  web:
    build: web
    ports:
      - "3000:3000"
    links:
      - db
    volumes:
      - "./app:/app" #共有フォルダの設定(ホストdir:クライアントdir)
    stdin_open: true
  db:
    image: postgres
    expose:
      - "5432"

volumesの部分はホストとクライアントのフォルダを共有する設定になっています。
このフォルダ以下にrailsappを作成していくため、適宜お好きなところに変更して下さい。

Dockerfileの編集

次にrailsを導入するdockerコンテナのDockerfileを編集します。

FROM ruby:2.4

RUN apt-get update && apt-get install -y build-essential libpq-dev postgresql-client
RUN gem install rails
RUN mkdir /app
WORKDIR /app

railsとpostgresの接続系ライブラリを導入しています。
また、ここでホストフォルダと共有するappフォルダも作成しておきます。

設定は終わりです( ´Д`)y━・~~

railsappを作成してみる

とりあえず、おきまりの以下のコマンドで各コンテナを起動します。

docker-compose build
docker-compose up -d

これでコンテナが立ち上がったはずです。
立ち上がったrailsコンテナに以下コマンドでログインします。

docker-compose exec web bash

ここまでくればrailsのいつもの作法です。
あとはrailsのアプリケーションを作成し、そのままではGemのエラーが出るので修正、bundle installしてrails起動!

rails new app -d postgresql
source 'https://rubygems.org'

git_source(:github) do |repo_name|
  repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
  "https://github.com/#{repo_name}.git"
end


# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.1.2'
# Use postgresql as the database for Active Record
gem 'pg', '~> 0.18'
# Use Puma as the app server
gem 'puma', '~> 3.7'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 5.0'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# See https://github.com/rails/execjs#readme for more supported runtimes
gem 'therubyracer', platforms: :ruby #ここのコメントを外す!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# Use CoffeeScript for .coffee assets and views
gem 'coffee-rails', '~> 4.2'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.5'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 3.0'
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'

# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '~> 2.13'
  gem 'selenium-webdriver'
end

group :development do
  # Access an IRB console on exception pages or by using <%= console %> anywhere in the code.
  gem 'web-console', '>= 3.3.0'
  gem 'listen', '>= 3.0.5', '< 3.2'
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
end
bundle install
rails s -b 0.0.0.0

そしたら、ホストPCのブラウザでlocalhost:3000にアクセスして

Yay!!!!!( ^ω^ )b

おわりに

dockerの設定は多少めんどくさいかもしれませんが、一度作成しておけば以後設定する必要はありません。
docker関連のファイルを共有しておけば、他の開発者が開発環境を構築する際、最速で構築可能です。

dockerは難しく、勉強コストも結構かかるとは思います。
ただ、一度勉強してしまえば「最速」でいろいろな環境が構築できるので、お得感の高いツールだなと思うこの頃。

働き方改革でテレワークを導入できない理由

Gakuです。

最近、プレミアムフライデーやらテレワークやら「働き方改革」が良くニュースで取り上げられますよね。
その中のテレワークですが、何故導入できないのか考察したいと思います。

テレワークとは

言わば在宅ワークのことです。
会社に出社せず、自宅において仕事を行うことを指します。

会議等もTV電話でできますし、意思決定等はチャットを使えばできる昨今です。そのため、基本的にはデスクワークの人は「自宅作業」で事足りるはずなのです。

テレワークのメリット

経営層視点

社員は出社しませんので、会社のオフィス賃料を極力抑えることができます。
また、それに伴って通勤費等も削減できます。

良いことづくめです!

社員視点

出社しないため、通勤時間が削減できます。
また、満員電車によるストレスからも解放されるため、毎日気持ちよく仕事を開始することができます。

社員にとっても良いことづくめです。

では何故導入しないのか?

今の日本の雇用体制が導入できない一番の理由だと思っています。
テレワークを導入するということは、社員が仕事をやっているかやっていないか経営側は管理することができません。

本来、「仕事をやっていない人」はクビになるはずです。
ただ、日本社会では簡単に社員をクビにできませんし、減給もできません。

そのため、「会社に来てもらうことで、一定の仕事をやっているということを担保したい」という思惑が経営層にはあるため、テレワークが浸透しないんだろうなと思います。

完全「成果主義」の時代

もし、これが全社員「契約社員の完全年俸制」にした場合、どうでしょうか。
家で仕事をやっていようが、やっていまいが「成果」が上がる社員に対してはそれに応じた報酬を、「成果」が上がらない社員に対してはクビ、もしくは減給を年度ごとに言い渡せるので、これであれば経営層も安心してテレワークを導入してうまくいきそうです。

おわりに

「働き方改革」とは、裏を返せば「完全成果主義」になるということ。
まぁ、今までの考え方がおかしいわけで、「過程」を重視する傾向から「成果」を重視する時代になりつつあると思うのです。

格差を縮めるどころか、ますます格差社会に拍車をかける政策だなっと思っている今日この頃です。

docker使ってredmineプラグイン作り

Gakuです。

最近、業務でredmineを使用しており、かんばんを使用するのにbacklogsプラグインでは使い勝手が悪いため、redmineプラグインを自作してみようと考えました。
(※開発業務ではなく、一般の業務をタスク管理する上でsprintは不要ですし、sprint組まないとかんばん出ないのは使い勝手悪い。)
dockerで環境構築を行い、ホストOSからpluginを新規作成するところまでの備忘録を掲載します。

docker-compose.yml,Dockerfile

docker-compose.ymlとredmineのDockerfileは以下のように作成しました。

version: '2'

services:
  redmine:
    build: redmine
    ports:
      - 8080:3000
    environment:
      REDMINE_DB_POSTGRES: postgres
    links:
      - postgres:postgres
    volumes:
      - ./redmine/plugins:/usr/src/redmine/plugins
  postgres:
    restart: always
    image: postgres
FROM redmine

Dockerfileいらないですね。( ´Д`)
まぁ、今後の拡張性考えて作っておきます。

volumeの設定

上記docker-compose.yml内でvolumeを設定していますので、それに合わせて、/redmine/pluginsフォルダを作成します。
これで一旦

docker-compose up -d


余裕のredmine起動( ^∀^)b

redmineプラグインの新規作成

redmineプラグインを作成するのも簡単です。
以下コマンド1発です。

docker-compose exec redmine bundle exec rails generate redmine_plugin Sample

これでホストOSの/redmine/pluginsフォルダにSampleプラグインが作成されたと思います。
あとは、これをredmineに反映させるため、

docker-compose stop && docker-compose up -d

でリスタートかけて、redmineのplugin一覧を確認して表示されてればOKです。

イージーゲーム( ´Д`)y━・~~

おわりに

ちょっとずつ育てていきますw
いい感じに作れたらフリーミアムな感じで販売も考えています。

それにしても、docker便利っすね〜。vagrantで一から環境作ろうと思ったんですが、めんどくさくてdockerに切り替えたらものの30分でここまで完了。。。
なんて素晴らしき世界。。。( ´Д`)y━・~~

Vagrantで「default: Warning: Connection reset. Retrying…」が繰り返される現象の解消法

Gakuです。

最近、golangとかreactとかdockerとかばかりやってて、1年ほどvagrantを触っていませんでした。
今回、RoRやるためにちょっとvagrantを触ったら盛大にハマったので、そのハマり内容&解消法を記載したいと思います。

ハマり内容

Vagrantbox.esから、Ubuntu 16.04 with Docker enabled (based on amd64 server iso file)のファイルを追加したら、以下内容で全く処理が終了しない現象に陥りました。

takehiro-hidakanoMacBook-Pro:ubuntu gaku$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Clearing any previously set forwarded ports...
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
    default: Adapter 2: hostonly
==> default: Forwarding ports...
    default: 80 (guest) => 3000 (host) (adapter 1)
    default: 22 (guest) => 2222 (host) (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Remote connection disconnect. Retrying...
    default: Warning: Connection reset. Retrying...
    default: Warning: Remote connection disconnect. Retrying...
    default: Warning: Connection reset. Retrying...
    default: Warning: Remote connection disconnect. Retrying...
    default: Warning: Connection reset. Retrying...
    default: Warning: Remote connection disconnect. Retrying...
    default: Warning: Connection reset. Retrying...
    default: Warning: Remote connection disconnect. Retrying...
    ...

SSHあたりの設定を試みるも

文献漁っていると、「公開鍵・秘密鍵の設定を適切に設定すれば動くよ!」という助言があったため、その内容を適用したりもしましたが、結局

default: Warning: Connection reset. Retrying...
default: Warning: Remote connection disconnect. Retrying...

が永遠に繰り返される現象は解消しませんでした。

解消法

いろいろ文献漁っているとVagrantbox.esのboxはあまりよろしくないとのこと。
何やら、vagrantの公式boxサイトがあるとのことなので、以下リンク先のものを設定し、再度挑戦

すると

takehiro-hidakanoMacBook-Pro:ubuntu gaku$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Box 'ubuntu/xenial64' could not be found. Attempting to find and install...
    default: Box Provider: virtualbox
    default: Box Version: >= 0
==> default: Loading metadata for box 'ubuntu/xenial64'
    default: URL: https://atlas.hashicorp.com/ubuntu/xenial64
==> default: Adding box 'ubuntu/xenial64' (v20170626.0.0) for provider: virtualbox
    default: Downloading: https://app.vagrantup.com/ubuntu/boxes/xenial64/versions/20170626.0.0/providers/virtualbox.box
==> default: Box download is resuming from prior download progress
==> default: Successfully added box 'ubuntu/xenial64' (v20170626.0.0) for 'virtualbox'!
==> default: Importing base box 'ubuntu/xenial64'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'ubuntu/xenial64' is up to date...
==> default: Setting the name of the VM: ubuntu_default_1499084159453_22500
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 22 (guest) => 2222 (host) (adapter 1)
==> default: Running 'pre-boot' VM customizations...
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: ubuntu
    default: SSH auth method: password
    default: Warning: Remote connection disconnect. Retrying...
    default: Warning: Connection reset. Retrying...
    default: Warning: Remote connection disconnect. Retrying...
    default: Warning: Connection reset. Retrying...
    default: Warning: Remote connection disconnect. Retrying...
    default: Warning: Connection reset. Retrying...
    default: Warning: Remote connection disconnect. Retrying...
    default:
    default: Inserting generated public key within guest...
    default: Removing insecure key from the guest if it's present...
    default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
    default: The guest additions on this VM do not match the installed version of
    default: VirtualBox! In most cases this is fine, but in rare cases it can
    default: prevent things such as shared folders from working properly. If you see
    default: shared folder errors, please make sure the guest additions within the
    default: virtual machine match the version of VirtualBox you have installed on
    default: your host and reload your VM.
    default:
    default: Guest Additions Version: 5.0.40
    default: VirtualBox Version: 5.1
==> default: Mounting shared folders...
    default: /vagrant => /Users/gaku/src/vagrant/ubuntu
takehiro-hidakanoMacBook-Pro:ubuntu gaku$ vagrant ssh
Welcome to Ubuntu 16.04.2 LTS (GNU/Linux 4.4.0-83-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  Get cloud support with Ubuntu Advantage Cloud Guest:
    http://www.ubuntu.com/business/services/cloud

0 packages can be updated.
0 updates are security updates.


ubuntu@ubuntu-xenial:~$ ls

余裕の解消( ^∀^)b

おわりに

やはり、定期的にいろいろ触らないとダメですねw
vagrantの公式boxサイトがあるとは知りませんでした。昔はVagrantbox.esが主流でしたが(※僕の中では)今度からは公式サイトを使用していきたいと思います。