ダメでしょ!

プログラミングとか怒られた話とか…

Rails5 でバッチ処理を利用する際に知らないとハマるかもしれないポイント!

前提

Rails 5.0.2
Ruby 2.4.0

なににハマったのか?

Rails5 で新規アプリを作成していて、バッチ処理を作成しました。
処理は .\lib\tasks\ 配下に格納し、 .\config\application.rb に以下の設定を行いました。

class Application < Rails::Application
  ・・・
  config.autoload_paths += Dir["#{config.root}/lib"]
  ・・・
end

これで lib ディレクトリ配下は自動的に読み込まれる設定になっていると思っていました。
Rails4 時代はこれでよかったんです。。。
さらに、開発環境では問題なくバッチ処理を呼び出すことができます。
これによって問題の解消がますます困難になりました。。。

Rails5 の本番環境では autoload が無効化された

A Guide for Upgrading Ruby on Rails — Ruby on Rails Guides

上記に記載されていますが、Rails5から本番環境では、autoload が無効になっています。
これは、、、知らないと絶対ハマる。

どのように問題に対応するか

上記のURLには解決策として、.\config\application.rb

class Application < Rails::Application
  ・・・
  config.enable_dependency_loading = true
  ・・・
end

と記載することで、autoload するように変更することがあげられています。
しかし、autoload が無効化されたということは、今後使えなくなることが想定されます。
ですので、今回は eager_load を利用することにしました。 .\config\application.rb

class Application < Rails::Application
  ・・・
  config.paths.add 'lib', eager_load: true
  ・・・
end

と指定し、lib ディレクトリ配下を eager_load されるように指定することで問題を解消しました。
app ディレクトリ配下の読み込みはこの eager_load で行われているようなので、これで問題ないはずです。

Rails のルーティングに使用する id を別の内容に変更する方法

通常、edit 等に使用する URI に設定される id を、別のキー等で置き換えたい場合があります。

$ be rake routes
             Prefix Verb   URI Pattern                                        password_resets POST   /password_resets(.:format)              password_resets#create
 new_password_reset GET    /password_resets/new(.:format)          password_resets#new
edit_password_reset GET    /password_resets/:id/edit(.:format)     password_resets#edit
     password_reset PATCH  /password_resets/:id(.:format)          password_resets#update
                    PUT    /password_resets/:id(.:format)          password_resets#update

この id を code に置き換えたい場合、.\config\routes.rbに以下のようにparam: codeを設定することで、置き換えることができます。

  resources :password_resets, param: :employee_code, only: [:new, :create, :edit, :update]

上記のようにすることで、ルーティング情報は以下のようになります。

$ be rake routes
             Prefix Verb   URI Pattern                                    Controller#Action        password_resets POST   /password_resets(.:format)                     password_resets#create
 new_password_reset GET    /password_resets/new(.:format)                 password_resets#new
edit_password_reset GET    /password_resets/:code/edit(.:format) password_resets#edit
     password_reset PATCH  /password_resets/:code(.:format)      password_resets#update
                    PUT    /password_resets/:code(.:format)      password_resets#update

id とは別のキーを主キーのような形で使う際に重宝します。

Perl でパスワードZipを求められた際の対応方法

前提

Perl は初めて触りました。
対応を求められたサーバの環境は古いです。

$ perl -v
This is perl, v5.10.1 (*) built for x86_64-linux-thread-multi

QBK (急にボールが来たので)

他にヘルプできそうな人間がいなかったということで、触ったことのない Perlソースコード修正を求められました。

内容は、Webフォームに添付されたデータをメールで送信するシステムの添付ファイルをパスワードZipで圧縮すること。

Perl 触ったこともないので、極力他に影響を与えたくない一心で対応しました。
調べてみると、Perl の標準モジュールに「Archive::Zip」というものがあるのですが、これはパスワードZipに対応していませんでした。。。
どうしようかなー、と悩んだのですが、Perl からコマンドが呼び出せるらしいので、コマンドでパスワードZipを作成し、それを添付することにしました。
ということで対応したコードが以下。

#-----------------------------------------------------------
#  パスワードzip生成
#  引数: ファイル名
#  備考: $cf{upldir} には、ファイルの保管場所ディレクトリパスが入っている
#-----------------------------------------------------------
sub zip {
    my $ZIP_CMD = "/usr/bin/zip";
    my $ZIP_PASSWD = "************";
    
    my ($origin_name) = @_;
    my $zip_name = "$origin_name.zip";

    my $cmd = "$ZIP_CMD -jP $ZIP_PASSWD $cf{upldir}/$zip_name $cf{upldir}/$origin_name"; # パスワードzipの生成コマンド
    system($cmd); # コマンドの実行
}

で、これをメール送信処理中の添付ファイルをセットする前に

&zip($fname); # $fname には対象となるファイル名が格納されている

と呼び出して、生成したファイルを添付することで対応しました。

今回はパスワード自体をランダム化する必要が無いという要件だったので、ソースコード内にパスワードを埋め込んでいますが、あまりよろしくないという認識はあります。
また、system関数は便利な半面、セキュリティリスクになりそうなので、使い所を見極めて使う必要がありますね。

初めて Perl に触りましたが、デバッグ方法もよくわからないし、辛かった。。。

ActiveRecord に対する scope は条件に一致するレコードが存在しない場合 .all の結果を返却する

scope を利用していたところ、思わぬところでハマってしまいました。。 指定の条件で検索を行い、返却された結果が nil かどうかで条件分岐させようと思っていたのですが、scope を利用すると常に nil ではなく、.all の結果が返却されてきます。

scope :search_with_user, -> (user_id) { where('user_id = ?', user_id) }

よくよく調べて見たところ、 scope はメソッドチェーンを実現するために、nil を返すことはなく、.all を返すんだとか。

要は scope の利用方法に関する認識不足だったのですが、他の人も同じような勘違いをする可能性もあるかも、と思ったのでブログに残しておきます。

Sqaleがサービス終了するとのことです

PaaSとして柔軟に利用していたGMOペパボのサービスであるSqaleですが、終了するとのこと。

【サービス終了のお知らせ】 | Sqale Information

安価であったため、結構使い勝手がよく、ちょこちょこ利用させてもらっていたんですが、rubyのバージョンアップに追従してなかったんで心配していたのですが。。。 代替サービスとしてはHerokuが推奨されています。

www.heroku.com

Herokuはドル建ての請求になるだろうから、それが経理からいやがられるんだよな。。

iBatis で LIKE 文を使うときの注意点

はじめに…SQLインジェクション発生!

現在対応中の案件で、なぜか iBtais の利用が指定されている案件があるのですが、ここでSQLインジェクションを発生させてしまったので、自戒として記載します。

iBatis の動的パラメータ受け渡し

iBtaisには # と \$ が用意されていますが、# で囲まれたパラメータはエスケープされ、\$ で囲まれたパラメータはそのまま出力されます。
で、LIKE分を記述する際は、%を渡したかったので、

WHERE column1 LIKE $%value%$ 

と記述していたのですが、そうしたところ、'などを検索文字として渡した際にエラーが発生しました。
つまり、SQLインジェクションが発生してしまったわけです。

対応策

で、どうしたかというと、

WHERE column1 LIKE CONCAT('%', #value#, '%')

という風に、文字列連結を行うことで対応しました。
一部RDBではCONCATに対応していないみたいですが、MySQLOracleMSSQL等は問題なく動作するようです。
PostgreSQLはちょっとだけ微妙。
%を含んだ検索がうまくいかないようです。
実害はないようですが。

コード整形のために積極的に利用したい拡張機能 CodeMaid

Visual Studio でのコーディング時の悩み

C# での開発を行っていると、Visual Studio がいろいろな機能を持っていてデフォルトでもかなり使いやすいと感じています。(atom での開発と比較して)

しかしながら、atom のパッケージで実現できていた機能で、Visual Studio ではデフォルトではできないこともそれなりにあります。

そのうちの一つがコードの整形でした。

Visual Studio には拡張機能がある

しかし、Visual Studio にも、atom のパッケージと同じように、機能を組込むことができます。
それが「拡張機能」です。
(その他、Nugetもありますが) この拡張機能のひとつとして、コード整形の 「CodeMaid」というものがあります。

CodeMaid - Visual Studio Marketplace

CodeMaid のインストール方法

インストールは非常に簡単です。 Visual Studio の [ツール]→[拡張機能と更新プログラム]を選択し、「CodeMaid」を検索します。
すると、CodeMaidが表示されますので、[インストール]ボタンからインストールするだけです。

CodeMaid の機能

  1. Code Cleaning
  2. Code Digging
  3. Code Reorganizing
  4. Comment Formatting
  5. Joining
  6. Finding
  7. Sorting
  8. Collapsing
  9. Progressing
  10. Configuring
  11. Switching
  12. Toggling

色々ありますが、コード整形を自動で行ってくれる機能と、それ以外の付帯機能と考えていいと思います。

CodeMaid の使い方

Visual Studio のコードエディタ上で右クリックすると、[CodeMaid]が追加されています。
その中の [Cleanup Active Document] を選択することで、開いているソースコードの整形が行われます。
具体的な整形内容ですが、

  1. Remove unused using statements (不要な using の削除)
  2. Sort using statements (using の並び替え)
  3. Add unspecified access modifiers (アクセス修飾子の追加)
  4. Remove empty regions (空の region の削除)
  5. Add blank line padding (空行の追加)
  6. Remove blank lines next to braces (中括弧の次の空行を削除)
  7. Run Visual Studio formatting (Visual Studio のフォーマット)
  8. Remove consecutive blank lines (連続した空行の削除)
  9. Remove end of line whitespace (スペースのトリム)
  10. Update endregion tags (endregion タグの更新)

となっています。
具体的にどうなるのかは、公式ページがわかりやすいです。(英語ですが、わからなくても画面キャプチャだけでわかります。)

http://www.codemaid.net/documentation/#cleaning

何故使うか

これを使うことで、一定のルールが自動で施されるようになり、コードの可読性が上がります。
また、チーム開発でのソースコードレビューで些末な指摘から開放されます。
もちろん、CodeMaid はあくまでアシスト役として、静的コード解析・ソースコードレビューと組み合わせることが必要だとは思いますが、自動的に修正できることはこういったツールに任せて、人間はもっと根本的なコーディングに時間を使ったほうが、生産性の向上に寄与します。

このような補助をうまく使うことで、楽しくコーディングしたいものです。