俺でもできるもんな

独立系SI企業から完全異業種のベンチャー企業に転職、社内のITインフラを整えるべく颯爽と登場した自称天才プログラマー俺のハートフルブログ

Rails 多言語化対応

はじめに

このグローバル社会!
開発するサービスによっては多言語化対応が必要になりますよね?
今回自社の開発で多言語化対応をしたので簡単ではありますが導入を紹介します。

参考サイト

以下のサイトを参考にしました。
記事を読む前に一読お願いします。

before_action以外

i18nについて
特にこの2つ
i18nのベーシックな使い方
辞書ファイルを分割して管理をしやすくする

before_action

Ruby on Railsで言語切り替え機能を作る

実装

config

config/application.rbにデフォルトの言語と複数のロケールファイルを読み込む設定を記述します。

config/application.rb

module TestProject
  class Application < Rails::Application
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded.
    config.i18n.default_locale = :ja
    config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]
  end
end

before_action

controller/application_controller.rbにbefore_actionとして、localeの指定があった場合変更する処理を書きます。
ログイン情報と一緒にlocale情報を持っておいてページを読み込むたびにチェックするイメージです。

controller/application_controller.rb

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  
  before_action :set_locale

  def set_locale
    I18n.locale = locale
  end

  def locale
    # ここで言語の切り替えを行う
    @locale ||= params[:locale] || I18n.default_locale
  end
end

dictionary

1つのファイルに全文言をかくと意味不明状態になるので、
参考サイトに倣って然るべき場所に然るべきファイルを作成し文言を記述していきます。
今回はbrandのviewで使いたかったので

  • config/locales/views/brands/ja.yml
  • config/locales/views/brands/en.yml

を作成しています。

config/locales/views/brands/ja.yml

ja:
  brand_index_title: "ブランド一覧"

config/locales/views/brands/en.yml

en:
  brand_index_title: "Brand List"

これ以外にも階層を持った書き方もできたりします。
詳しくは調べてください。

view

書き方はいろいろありますが、階層を持たない場合はこれで統一してください。
(この例にはslimを使用しています)

view/brands/index.rb

h1 = t(:brand_index_title)

結果

locale = :jaの場合 a552ecf6-da35-7015-cacd-c512c6dee036.png

locale = :enの場合 aa1e6ef6-fc11-a1fe-5b8e-3eca219de7bf.png

補足

今回はviewでの利用方法でしたが、modelでも利用することになります。
(validのエラーメッセージで使うはず)

Git 間違ってaddしてしまったものを取り消す方法

はじめに

軽快にaddしていた時に間違ってaddする必要もないものをaddしてしまった経験はないでしょうか?

$ git add -p

「y」、「Enter」、「y」、「Enter」、「y」、「Enter」….あっ(察し) 僕はよくあります。

そんな時にaddを取り消す方法を共有します。

コマンド

コマンドは実にシンプルです。

$ git reset HEAD config/database.yml

以上です。

Rails kaminariを使用したページネーションにBootstrapデザインを適用させる

前提環境

  • RoRプロジェクト
  • プロジェクトにBootstrapの環境が整っている
  • プロジェクトにkaminariでページネーションが生成できる環境が整っている

kaminariを用いたページネーションのソースはとてもシンプル

<%= paginate @pagination %>

このどこにBootstrapを適用させる余地があるんだ…と頭を2秒ほど抱えた。

kaminariにBootstrapを適用させる

Bootstrap用のViewテンプレートをジェネレートする

rails g kaminari:views bootstrap3
Running via Spring preloader in process 68165
      downloading app/views/kaminari/_first_page.html.erb from kaminari_themes...
      create  app/views/kaminari/_first_page.html.erb
      downloading app/views/kaminari/_gap.html.erb from kaminari_themes...
      create  app/views/kaminari/_gap.html.erb
      downloading app/views/kaminari/_last_page.html.erb from kaminari_themes...
      create  app/views/kaminari/_last_page.html.erb
      downloading app/views/kaminari/_next_page.html.erb from kaminari_themes...
      create  app/views/kaminari/_next_page.html.erb
      downloading app/views/kaminari/_page.html.erb from kaminari_themes...
      create  app/views/kaminari/_page.html.erb
      downloading app/views/kaminari/_paginator.html.erb from kaminari_themes...
      create  app/views/kaminari/_paginator.html.erb
      downloading app/views/kaminari/_prev_page.html.erb from kaminari_themes...
      create  app/views/kaminari/_prev_page.html.erb

テンプレートが作成される。

スクリーンショット 2017-07-12 16.16.47.png

これだけ

スクリーンショット 2017-07-12 16.18.24.png

一瞬で適用できた。

懸念点

逆にこのページだけBootstrapのデザイン使いたくないとなった時の対処方法が今の所わからない…

参考サイト

http://morizyun.github.io/blog/kaminari-gem-paginator-rails/

Rails MySQLを使用するアプリケーションでMSSQLServreにも接続する

カオスじゃないかこれは

前提条件

  • 新アプリケーションではRails + MySQLを使用する。
  • 既存のアプリケーションはSQLServreを使用している。
  • SQLServreはWindowsServerに配置されている。

実現したいこと

新アプリケーションで登録があった場合、 新アプリケーションDB・既存アプリケーションDB共に更新する。

実装

SQLServerを使うためのgemを導入する

# SQLServer用
gem 'tiny_tds'
gem 'activerecord-sqlserver-adapter'

そしていつもの

$ bundle install

しかしこれはエラーとなる。 tiny_tdsを使用するにはFreeTDSが必要。

$ brew install freetds
# または
$ yum install freetds freetds-devel

そのあとに

$ bundle install

これでgemの導入は完了。

SQLServreの情報をセット

database.ymlにSQLServreの情報をセットする。

# ここら辺はMySQL用の設定
default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: [username]
  password: [password]
  host: [host]

development:
  <<: *default
  database: management_development

test:
  <<: *default
  database: management_test

production:
  <<: *default
  database: management_production
  username: management
  password: <%= ENV['DATABASE_PASSWORD'] %>
# 以下を追加
# MSSQLサーバー用
sqlserver:
  adapter: sqlserver
  host: [host]
  database: [database]
  port: [port]
  username: [username]
  password: [password]

Modelの作成

SQLを実行するだけの機能を実装。 ApplicationRecordは継承しない。

# MSSQLServerにつなぐもの
class Msss
  # SQL文を実行する
  def self.exec(sql)
    sscnf = Rails.configuration.database_configuration['sqlserver']
    client = TinyTds::Client.new(
      adapter: sscnf['adapter'],
      host: sscnf['host'],
      database: sscnf['database'],
      port: sscnf['port'],
      username: sscnf['username'],
      password: sscnf['password']
    )
    client.execute(sql)
  end
end

使用例

単純なSELECT文を実行し、その結果を取得する例

class TestController < ApplicationController
    def test
        result = Msss.exec("SELECT * FROM [list] ")
        result.each do |row|
            puts row["name"]
        end
        render :text => "text"
    end
end

もちろんUPDATEやINSERTも可能。

参考にさせていただいたサイト

Rails3でSQLServerに接続してみたよ [Rails][AzureSQLデータベース]Macでtiny_tdsのbundle installが通らない時の対処法

Rails マイグレーションでintegerを使う時の注意点〜integerのlimitはバイト数だった〜

limitの定義に注意

マイグレーションファイルでintegerのカラムにlimitを定義する際に注意しないといけないことがある。

integerのlimitとstringのlimitでは意味合いが違う

例えば以下のように記述する。

t.integer :num, limit: 11, null: false, comment: "integerカラム"
t.string :str, limit: 100, null: false, comment: "stringカラム"

一見何も問題ないように見えるが以下のようなエラーがでる。

StandardError: An error has occurred, all later migrations canceled:
No integer type has byte size 11
/prj/db/migrate/20170620050536_tests.rb:3:in `change'
ActiveRecord::ActiveRecordError: No integer type has byte size 11

integerのlimitはバイト数だった

integerのlimitは桁数ではない。バイト数だった!
stringのlimitは桁数なのにね!

な!の!で!

num | int(11)    

というカラムを作りたい場合のlimitは4です

t.integer :num, limit: 4, null: false, comment: "integerカラム"

limitに4以外を指定した場合に生成されるカラムは以下を参照してください。
Rails | マイグレーションで integer カラムを作る時の :limit は、桁数指定ではない ( バイト数指定だ )

Unicorn+Nginx+Rails タイムアウトの設定方法

やりたいこと

サーバーのデフォルトタイムアウトが60秒に設定されていた。
スクレイピングやバッチサーバーでは60秒以内に完了しないものが多いのでタイムアウトの時間を設定したい。

設定方法

NginxとUnicornタイムアウト値を設定する必要がある。

Unicornタイムアウト値変更(999999999999秒)

$ vi /projects/config/unicorn.rb

 ※「timeout 999999999999」を追加。無制限

Nginxのタイムアウト値変更(3600秒)

$ vi /etc/nginx/conf.d/timeout.conf

(ファイル自体を追加) proxy_connect_timeout 3600; proxy_send_timeout 3600; proxy_read_timeout 3600; send_timeout 3600;

NginxとUnicornの再起動

$ /etc/init.d/nginx restart
$ kill -9 <Unicorn マスタープロセスPID>
$ bundle exec unicorn_rails -c config/unicorn.rb -E development -D

備考

タイムアウトの設定は「Unicorn」「Nginx」の2箇所にあります。

$ grep timeout /projects/log/development_unicorn_error.log | grep killing
E, [2017-06-15T11:30:50.803344 #23658] ERROR — : worker=0 PID:23661 timeout (61s > 60s), killing
E, [2017-06-15T11:36:41.156568 #23658] ERROR — : worker=1 PID:23663 timeout (61s > 60s), killing
E, [2017-06-15T11:43:53.542174 #23658] ERROR — : worker=1 PID:23769 timeout (61s > 60s), killing
E, [2017-06-15T11:45:32.648281 #23658] ERROR — : worker=0 PID:23720 timeout (61s > 60s), killing
E, [2017-06-15T13:36:51.095563 #23658] ERROR — : worker=0 PID:23978 timeout (61s > 60s), killing

Unicorn+Nginx+Rails サーバが起動できない場合の対処法

事象

Unicorn+Nginx+Rails サーバが起動できない
以下のコマンドでエラーとなった

bundle exec unicorn_rails -c config/unicorn.rb -E development -D

エラー内容は以下

F, [2017-06-14T16:45:08.020588 #20655] FATAL -- : error adding listener addr=/projects/scraping/tmp/development_unicorn.sock
ArgumentError: socket=/projects/scraping/tmp/development_unicorn.sock specified but it is not a socket!
  /projects/scraping/vendor/bundle/ruby/2.4.0/gems/unicorn-5.3.0/lib/unicorn/socket_helper.rb:131:in `bind_listen'
  /projects/scraping/vendor/bundle/ruby/2.4.0/gems/unicorn-5.3.0/lib/unicorn/http_server.rb:241:in `listen'
  /projects/scraping/vendor/bundle/ruby/2.4.0/gems/unicorn-5.3.0/lib/unicorn/http_server.rb:852:in `block in bind_new_listeners!'
  /projects/scraping/vendor/bundle/ruby/2.4.0/gems/unicorn-5.3.0/lib/unicorn/http_server.rb:852:in `each'
  /projects/scraping/vendor/bundle/ruby/2.4.0/gems/unicorn-5.3.0/lib/unicorn/http_server.rb:852:in `bind_new_listeners!'
  /projects/scraping/vendor/bundle/ruby/2.4.0/gems/unicorn-5.3.0/lib/unicorn/http_server.rb:140:in `start'
  /projects/scraping/vendor/bundle/ruby/2.4.0/gems/unicorn-5.3.0/bin/unicorn_rails:209:in `<top (required)>'
  /projects/scraping/vendor/bundle/ruby/2.4.0/bin/unicorn_rails:23:in `load'
  /projects/scraping/vendor/bundle/ruby/2.4.0/bin/unicorn_rails:23:in `<top (required)>'

原因と対処法

ソケットファイルが通常ファイルになっていた。
なので、ソケットファイルを一度削除してからunicornの起動コマンドを実行する。

ソケットファイルを確認

$ ls -l /projects/scraping/tmp/development_unicorn.sock
-rw-r--r1 root root 0 Jun  3 18:22 /projects/scraping/tmp/development_unicorn.sock

※「s」が付いておらず、通常のファイルになっている。

一度削除し、unicornを起動

$ rm /projects/scraping/tmp/development_unicorn.sock
rm: remove regular empty file ‘/projects/scraping/tmp/development_unicorn.sock’? y
$ bundle exec unicorn_rails -c config/unicorn.rb -E development -D

ソケットファイルを確認

$ ls -l /projects/scraping/tmp/development_unicorn.sock
srwxrwxrwx 1 root root 0 Jun 15 00:29 /projects/scraping/tmp/development_unicorn.sock

  ※「s」が付いていて、ソケットファイルになっている。

unicornの再起動確認

$ ps -ef | grep unicorn
root     22108 21797  0 00:29 pts/0    00:00:00 tail -f /projects/scraping/log/development_unicorn_error.log
root     22178     1  0 00:29 ?        00:00:00 unicorn_rails master -c config/unicorn.rb -E development -D
root     22181 22178  2 00:29 ?        00:00:01 unicorn_rails worker[0] -c config/unicorn.rb -E development -D
root     22183 22178  2 00:29 ?        00:00:01 unicorn_rails worker[1] -c config/unicorn.rb -E development -D
root     22203 21932  0 00:30 pts/1    00:00:00 grepcolor=auto unicorn
$ kill -9 22178
$ ls -l /projects/scraping/tmp/development_unicorn.sock
srwxrwxrwx 1 root root 0 Jun 15 00:29 /projects/scraping/tmp/development_unicorn.sock
$ bundle exec unicorn_rails -c config/unicorn.rb -E development -D

※正常起動できた。

ログに下記が出たときは、
ソケットファイルのパスにソケットファイルでない何かが作成されているようです。

ArgumentError: socket=/projects/scraping/tmp/development_unicorn.sock specified but it is not a socket!
...