form 送信時に特定の要素の値を送らないようにするの法

<select name="foo"> な奴の <option> が 'None' だった場合は、その名前の値を送りたくないみたいな事がやりたくて、jQuery 入ってる環境だったので以下のようにした。
$(document).ready(function() {
  $('form').submit(function() {
    var $target = $(this).find('select[name=foo]');
    if ($target.val() == 'None') {
      $target.attr('disabled', 'disabled');
    }
  });
});

$(window).unload(function() {
  $('form').find('select[name=foo]').removeAttr('disabled');
});

unload の所が無いとブラウザバックした時に disabled なままで悲しいのでこんな感じになった。
もっとお手軽な方法がありそう。

nginxでDigest認証したかったけど対応して無かったよ。

nginx で autoindex + Digest認証したかったけど、この人Digest認証出来ない!

というわけでそれPla

/etc/nginx/nginx.conf

server {
    listen       80;
    server_name  private.example.com;

    access_log  logs/private.example.com.access.log  main;
    location / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://localhost:5000;
        # for Plack::Middleware::XSendfile
        proxy_set_header X-Accel-Mapping /srv/private/=/
    }
    location /data/ {
        internal;
        root /srv/private;
    }
}

/srv/private/private.psgi

use Plack::App::Directory;
use Plack::Builder;

my $users = {
    'dankogai' => 'kogaidan',
};

my $realm  = 'Private area';
my $secret = 's3cr3t';

my $app = Plack::App::Directory->new({ root => './data' })->to_app;

$app = builder {
    enable_if { $_[0]->{REMOTE_ADDR} eq '127.0.0.1' }
        'Plack::Middleware::ReverseProxy';
    enable 'Plack::Middleware::Auth::Digest', realm => $realm, secret => $secret,
        authenticator => sub {
            my ($username, $env) = @_;
            return $users->{$username};
        };
    enable 'Plack::Middleware::XSendfile', 'variation' => 'X-Accel-Redirect';
    $app;
};

autoindex を自分で書くのがめんどかったので、P::A::Directory にまかせて、
実際のファイルの配信は P::M::XSendfile を使い X-Accel-Redirect で nginx にまかせる。


こんな感じで、あとは /srv/private/data にいろいろ置けばよい。

あとがき

これぐらいなら Embedded Perl でやっても良かったのかなとか思った。

HTML::Shakan で choices が消えて困ってるの巻

[追記:2010-07-17] さっそく対応してもらいましたので、HTML::Shakan 0.06 からこの記事のテストは通るようになりました


はい、なんかタイトルで言い切った感がありますけど、だらだらと説明しちゃいますよ!

HTML::Shakan とは

id:tokuhirom さん作で Django のフォームっぽい感じの素敵な form generator / validator という感じのものです。
詳しくは日本語のドキュメント付属してるから、そっちを読むと良いよ。

どういう時に困るか

HTML::Shakan の SYNOPSIS にあるように、毎回 form を定義するような使い方をするならば困らないのですが、HTML::Shakan::Declare で form を作って、使うときは get して使いまわすような場合に困ったことになります。

とかいってもよく伝わらないでしょうから、テストケースを書きました。

{
    package My::Form;
    use HTML::Shakan::Declare;
    form 'my_form' => (
        ChoiceField(
            name    => 'foo',
            widget  => 'select',
            choices => [qw/1 one 2 two 3 three/],
        ),
        ChoiceField(
            name    => 'bar',
            widget  => 'radio',
            choices => [qw/1 one 2 two 3 three/],
        ),
    );
}

{
    package main;
    use strict;
    use warnings;
    use CGI;
    use Test::More;

    is form('my_form')->render(), form('my_form')->render();

    sub form {
        my $name = shift;
        return My::Form->get(
            $name => (
                request => CGI->new(),
            ),
        );
    }
    done_testing;
}

現状の HEAD ですとこのテストはこけてしまいます。

なぜ消えたし

HTML::Shakan::Widgets::Simple の中で choices を消すような操作をしているからですね。
widget_select() と widget_radio() がそれにあたります。

結局どうすれば

そもそも Widget は差し替え可能な作りになっているので、そこを差し替えれば良いのですが、Widget で form の定義が書き換えられて嬉しいケースっていうのが特に思い浮かばなかったので、僕は以下のような感じで凌いでいます。*1

diff --git a/lib/HTML/Shakan/Declare.pm b/lib/HTML/Shakan/Declare.pm
index 3edf8ac..45249dd 100644
--- a/lib/HTML/Shakan/Declare.pm
+++ b/lib/HTML/Shakan/Declare.pm
@@ -3,6 +3,7 @@ use strict;
 use warnings;
 use base 'Exporter';
 use HTML::Shakan ();
+use Storable qw/dclone/;
 
 our @EXPORT = qw(form get);
 
@@ -23,7 +24,7 @@ sub get {
     my ($class, $name, %args) = @_;
     $class = ref $class || $class;
     return HTML::Shakan->new(
-        fields => $FORMS->{$class}->{$name},
+        fields => dclone $FORMS->{$class}->{$name},
         %args,
     );
 }

というわけで

良かったら取り込んでもらえると嬉しいです > id:tokuhirom さん
なんか誤解していたり、普通こうやるよね!みたいなのあったら教えてください!

*1:実際は mokey patch ですよ