railsのモデルに、特定の条件下で動くvalidationを追加
ifを使用した条件分岐
例えば、bという項目がtrueの場合のみaの値は必須にしたい、とかあると思う。
with_optionsメソッドを使用して以下のように実装することができる。
class Post < ActiveRecord::Base # ifオプションで条件に合致する場合のみvalidatesを実行(published?はメソッド名またはmodelのboolean項目) validates :name, presence: true if: published? # 複数valitatesをまとめたい場合はwith_optionsを使用 with_options if: :published? do validates :name, presence: true validates :category, presence: true end # unlessで条件に合致しない場合のみvalidatesを実行 # lambdaを使うことで複数条件を指定できる with_options unless: -> { :hoge? || :foo? } do validates :name, presence: true end end
ただし、この場合、with_optionsブロック内部で更にif: を使用してしまうと、
内部のif条件の場合にしかvalidatesが実行されなくなる。
# hogeの時しかwith_options内部が実行されない with_options if: :published? do validates :name, presence: true validates :category, presence: true, if: hoge end # with_optionsで定義したものと逆のもの(この場合はunless)を使用すれば問題ない with_options if: :published? do validates :name, presence: true validates :category, presence: true, unless: 'hoge.blank?' end
ネストしたvalidationを記載するなら、メソッドを一つ作って指定した方が良さそう。
validates :name, presence: true, if: :require_validation? def require_validation? return true if aaa? && bbb? false end
onを使用した条件分岐
例えば新規登録(create)の場合のみバリデーションをかけたい時は、onオプションを使用する。
class Post < ActiveRecord::Base # createの時のみ実行 validates :name, presence: true on: :create # if同様with_optionsを使用できる with_options on: :create? do validates :name, presence: true validates :category, presence: true end # こうすることで、pattern_hogeコンテキストが渡された時のみvalidatesが実行される validates :hoge, presence: true, length: { maximum: 3000 }, on: :pattern_hoge end
class PostsController < ApplicationController def hoge # pattern_hogeコンテキストを指定 post.save(context: :hoge.save(context: :pattern_validation)) end end
railsでenumを使う
modelに記述する。
class Post < ActiveRecord::Base enum status: { created: 0, drafted: 1, canceled: 2 } end
こうすることで、Post.statusesとして、各Enumにアクセスすることができる。
pry(main)> Post.statuses # => {"created"=>0, "drafted"=>1, "canceled"=>2} pry(main)> Post.statuses[:drafted] # => 1 pry(main)> @post = Post.new pry(main)> @post.status = Post.statuses[:drafted]
また、インスタンスに対して、enumの各要素をメソッドとして使用することができる。
pry(main)> @post = Post.new pry(main)> @post.status = Post.statuses[:drafted] pry(main)> @post.drafted? # => true pry(main)> @post.canceled! pry(main)> @post.canceled? # => true pry(main)> @post.drafted? # => false
modelとの関連付けはせず、Enumとしてだけ使用したい場合、
locales下のymlファイルに記述する方法もあり。
ja: Enum: status: created: 0 drafted: 1 canceled: 2
pry(main)> Enum.codes(:status) => ["created", "drafted", "canceled"]
選択肢が限られているセレクトボックスの検証とかで、inclusionと合わせて使えそう。
シェルでディレクトリ内のファイルの数を調べる
例えばシェルでディレクトリ内に何ファイル存在するか調べるには以下の方法でチェックをする。
ls -FU1 '対象のパス' | grep -v / | wc -l
ざっと解説すると、lsの結果をgrepに渡し、grep -vで不要な情報を削除し、
wcコマンドにわたし、数をカウントしている。lsオプションは以下の通り。
- -F:ディレクトリが存在する場合は/を付与して表示する。
- -1:lsの結果を1行ずつ表示
- -U:lsの結果をソートしない(速度向上)
上記の例だとディレクトリを省いてファイルの数を調べている。
また、wcコマンドは、渡されたファイルのバイト数も表示するため、
-lオプションは、渡されたファイルの個数のみを表示させている。
ブックマークレットでフォームに自動的に入力するスクリプトを作りたい
テストとかで画面に値を入力する場合、 繰り返しテストをしていると、
毎回フォームに値を入力しないといけないのがダルい。
ブックマークレットで1クリックだけでフォームに値をセットできるスクリプトを作りたい。
とりあえずフォームの要素に値をセットする方法。
javascript:(function(){ document.getElementById("srchtxt").value = "てすと";}())
ついでに画面内のID全て取得するブックマークレット
javascript:(function() {var elements = document.getElementsByTagName("input");var i = 0; var ids = "";for (i = 0 ; i < elements.length ; i++){ids += elements[i].id + "\r\n";}alert(ids)}());
コマンドプロンプトでgrep
コマンドプロンプトでgrepするならfindstr
Windowsのコマンドプロンプトでgrepと同じことをしたい。
findstrコマンドが良さげ。
findstr [オプション] "検索対象文字列" "検索対象のファイル"
以下よく使いそうなオプション
デフォルトでは正規表現での検索をしてくれないので、/Rオプションを使用する。
/I 大文字小文字を区別しない /S ディレクトリを再帰的に検索する /R 正規表現を使用する /C 空白を含む文字を検索する場合に指定する /N 一致した行数を表示 /V 指定した文字を含まない行をすべて表示
使用例
カレントディレクトリ以下で、”This is〜"という文字が含まれている箇所をresult.txtに出力する。
findstr /R /S /C "This is.*" * > result.txt
Oracleでテーブルのカラム名表示
- 全ての詳細表示
DESC テーブル名;
- テーブルの物理名の表示
SELECT USER_TAB_COMMENTS;
- テーブルの項目の物理名表示
SELECT USER_COL_COMMENTS WHERE TABLE_NAME = 'テーブル名';
システムテーブルも表示したい場合は、ALL_TAB_COMMENTS、ALL_COL_COMMENTSにすればOK。
JavaでのZipファイル作成
JavaでのZipファイル作成方法を調査した。
一例なので、他の方法もあるかも。
肝心なのは、ZipArchiveOutputStreamのflush()を使用して、1ファイルずつZipに書き込んでいるところ。
flushを使わず、全てのファイルをメモリに格納し、 Zipを生成すると、
OutOfMemoryExceptionが発生する可能性がある。
public String downloadZip() throws Exception { //対象年月のFileオブジェクト取得 File downloadTargetDir = new File("/var/local/testDir/"); ByteArrayOutputStream zipBAOS = new ByteArrayOutputStream(); ZipArchiveOutputStream zipArchiveOS = new ZipArchiveOutputStream(zipBAOS); // ヘッダー情報設定 try { this.response.setHeader("Content-Transfer-Encoding", "binary"); this.response.setHeader("Content-Type", "application/zip;charset=UTF-8"); this.response.setHeader("Content-Disposition", "attachment; filename=\"" + "test.zip" + "\""); this.response.setHeader("Cache-Control", "private"); this.response.setHeader("Pragma", "private"); // ディレクトリを圧縮 this.recursiveArchive(outZip, downloadTargetDir); } catch ( Exception e ) { // ZIP圧縮失敗 e.printStackTrace(); throw new Exception(e); } finally { // ZIPエントリクローズ try { outZip.closeArchiveEntry(); } catch (Exception e) {} try { outZip.close(); } catch (Exception e) {} try { zipBAOS.close(); } catch (Exception e) {} } } /** * ディレクトリ圧縮のための再帰処理 * * @param outZip ZipOutputStream * @param targetFile File 圧縮したいファイル * @param parentFilepath String */ private void recursiveArchive(ZipArchiveOutputStream outZip, File targetFile) { if ( targetFile.isDirectory() ) { File[] files = targetFile.listFiles(); for (File file : files) { if ( file.isDirectory() ) { recursiveArchive(outZip, file, parentFilepath); } else { String entryName = file.getName(); // 圧縮処理 archive(outZip, file, entryName); } } } } /** * 圧縮処理 * @param outZip ZipOutputStream * @param targetFile 圧縮したいファイル * @param entryName 保存ファイル名 * @return */ private boolean archive(ZipArchiveOutputStream outZip, File targetFile, String entryName) { // 圧縮レベル設定 outZip.setLevel(5); try { // ZIPエントリ作成 outZip.putArchiveEntry(new ZipArchiveEntry(entryName)); // 圧縮ファイル読み込みストリーム取得 BufferedInputStream in = new BufferedInputStream(new FileInputStream(targetFile)); // 圧縮ファイルをZIPファイルに出力 int size = 0; //byte buffer[] = new byte[1024]; // 読み込みバッファ byte[] bff = new byte[1024]; while ((size = in.read(bff, 0, bff.length)) != -1) { outZip.write(bff, 0, size); } in.close(); outZip.closeArchiveEntry(); try { outZip.flush(); } catch (Exception e) { } } catch ( Exception e ) { // ZIP圧縮失敗 return false; } return true; }