2013年12月21日土曜日

Rails4で「The provided regular expression is using multiline anchors (^ or $), 」エラー

Rails4を使って「RailsによるアジャイルWebアプリケーション開発」を写経していたら、
7章のバリデーションの実装のところで下のエラーが発生した。

The provided regular expression is using multiline anchors (^ or $), which may present a security risk. Did you mean to use \A and \z, or forgot to add the :multiline => true option?

これは、正規表現で「^」や「$」を使って精査していると複数行とのマッチで精査が完全じゃないよってことで発生するエラーのようです。
マルチラインでも先頭、末尾を判定できる「¥A」、「¥z」を使うと解決します。

変更前

validates :image_url, allow_blank: true, format: {
      with: %r{\.(gif|jpg|png)$}i,
      message: 'はGIF、JPG、PNG画像のURLでなければなりません'
  }

変更後

validates :image_url, allow_blank: true, format: {
      with: %r{\.(gif|jpg|png)\z}i,
      message: 'はGIF、JPG、PNG画像のURLでなければなりません'
  }

stackoverflowに全く同じ本で困っている人がいて、何が問題なのか分かりやすく書かれてる。
http://stackoverflow.com/questions/17759735/regular-expressions-with-validating-in-ror-4

2013年11月19日火曜日

[ruby]正規表現で文の先頭(末尾)と行頭(行末)

Rubyの正規表現の文の先頭(末尾)と行頭(行末)

文の先頭と末尾は、\Aと\zで表現する。
行の先頭と末尾は、^と$で表現する。

lines = "line1\nline2"

# line1とline2を含め文字列全体でマッチする
puts /\A.+1.+2\z/m === lines

# line1だけでマッチする
puts /^.+1$/ === lines

2013年11月17日日曜日

[oracle12c]offsetを指定した上位n件の取得

Oracle12cの変更点のSELECT機能の強化に、下の記述がありました。
この機能を使うと、検索結果から指定した範囲のデータをねらって取得でき非常に便利だと思います。
※昔はROWNUM擬似列と副問い合わせ使って頑張って同じようなことをした記憶があります。

上位N番までの問合せの実行に、オフセットと、戻される行数または行数の割合を指定できます。

使い方

IDでソートして、11レコード目から5レコード取得する場合

開始レコード番号は、offsetに指定した値 + 1なのでoffsetには10を指定する。
select *
 from table1
order by id
offset 10 rows fetch first 5  rows only;

最後のレコードと同一のソートキーのレコードは、リミットを超えても全部取得する場合

最初のレートは異なり最後のキーワードをwith tiesにする
select *
 from table1
order by id
offset 10 rows fetch first 5  rows with ties;

注意点

ソート(order by)とセットで使わないと結果が毎回変わる可能性がある。

2013年11月10日日曜日

[Oracle12c]子表を再帰的に切り捨てできるように

Oracle12Cでは、TRUNCATE文に「CASCADE」句をつけることで、子表(孫も含む)のテーブルも含めて切り捨て出来るようになる。

小表も含めて切り捨てる方法

参照整合性制約を作成する際に「ON DELETE CASCADE」を指定する。

ALTER TABLE ACCOUNT ADD FOREIGN KEY (ADDRESS_CD) REFERENCES ADDRESS (CD) ON DELETE CASCADE;

TRUNCATE文にはCASCADE句を指定する。

TRUNCATE TABLE ADDRESS CASCADE;

2013年11月9日土曜日

[coffeescript]strictモードを使う

coffeescriptでstrictモードを使用するには、関数の先頭で、「use strict」を記述してあげれば良い。

スクリプトの場合

func = ->
  'use strict'
  arguments.callee

変換されたJavaScript

(function() {
  var func;

  func = function() {
    'use strict';    return arguments.callee;
  };

}).call(this);

2013年10月26日土曜日

[coffeescript]coffeescriptをコンパイルしてJavaScriptに変換

coffeeコマンドを使用してコンパイル(JavaScriptへの変換)を行う。

コンパイル方法

-c -> コンパイルを行う。
-w -> -cとセットで使うことでファイルを保存するたびに自動でコンパイルを行うことが出来る

2013年10月14日月曜日

[Oracle12c]auto incrementみたいな新機能

Oracle12cでは、auto incrementっぽいカラムを定義できるようなので試してみた。

auto incrementっぽいカラムを定義するには、下のSQLのように「generated as identity」を指定する。
-- 常に生成した値を設定する(明示的に値を設定しようとするとエラーとなる)
id number generated as identity not null

-- generatedの後にalwaysを指定すると、常に生成した値を使用する
-- デフォルト動作なので、上のオプション無しと同じ動きとなる
id number generated always as identity not null

-- by defaultを指定すると値の設定がない場合のみ、生成した値が設定されます。
-- on nullをby defaultの後に設定すると、挿入(更新)対象の値がnullの場合にも、生成した値が設定されます。
id number generated by default as identity not null

生成する値のルールは、オプションとして指定します。指定する値のルールはシーケンスオブジェクトと同じなので省略します。

初期値が100で、最大値が999でサイクルさせる場合の定義例
id number generated as identity(
  minvalue 100
  maxvalue 999
  cycle
  ) not null,

実行例

-- テーブル定義
create table test_table
(
  id number generated as identity(
  minvalue 100
  maxvalue 999
  cycle
  ) not null,
  name NVARCHAR2 (100) not null,
  primary key (id)
);

-- INSERTの実行結果
SQL> insert into test_table (name) values ('なまえ');

1 row created.

SQL> select id from test_table;

 ID
----------
       100

SQL> insert into test_table (name) values ('なまえ');

1 row created.

SQL> select id from test_table;

 ID
----------
       100
       101

always指定のカラムに対して値を設定しようとすると、以下の例外が発生する。
SQL> insert into test_table (id, name) values (999, 'name');
insert into test_table (id, name) values (999, 'name')
                        *
ERROR at line 1:
ORA-32795: cannot insert into a generated always identity column

値ってどうやって生成している?

値の生成自体はテーブル作成時に裏で作成したシーケンスオブジェクトを使用して行っているようです。
このシーケンスオブジェクトは、単純に「drop table テーブル名」でテーブルを削除した場合ゴミとして残ってしまいます。
テーブル削除時に「purge」を指定してセットで削除してあげましょう。