2011-02-25

ActiveScaffoldでsum

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
RailsのScaffoldをステキにするActiveScaffoldで特定のカラムの合計値を表示したいなぁと思ったわけです。

以下のようなテーブルがあるとします。
users
id
name

orders
id
user_id
amount

このようなテーブルがあっとしてuser毎のorderのamount合計を表示したいと思ったわけです。

とりあえず二つ方法がある感じです。

(1)userコントローラからorderコントローラをネスト表示してorderコントローラのリストに合計値を表示。
以下のような感じでコントローラーを準備します。
class UsersController < ApplicationController
  active_scaffold :users do |config|
    config.nested.add_link("オーダー", [:orders])
  end
end

class OrdersController < ApplicationController
  active_scaffold :orders do |config|
    config.columns[:amount].calculate = :sum
  end
end
これでhttp://budanters.blogspot.com/2009/10/adding-multiple-column-calculations-to.htmlにあるような感じでリストの下に合計値が表示されます。
合計値意外に、calculateが対応しているものとして:avgがあるようです。

この方法で表示すると合計値がSumと表示されるので、これを日本語にするには
vendor/plugins/active_scaffold/frontends/default/views/_list_calculations.html.erb
を対象のviewにコピーしていじってやればOKです。
この場合だと
app/view/order
の下にコピーとなります。

これでもよいっちゃぁよいのですが、できるならばuserコントローラに表示したいです。
というわけで、もう一つの方法です。
(2)モデルに合計値を定義しておいて表示する
まずはuserモデルに合計値を定義します。
class User < ActiveRecord::Base
  has_many :orders

  def order_total
    self.orders.sum(:amount)
  end
end
で、以下のようにuserコントローラを準備します。
class UsersController < ApplicationController
  active_scaffold :users do |config|
    config.list.columns << :order_total
  end
end

これでuserのリストのユーザ毎の合計値が表示されます。

なかなか便利なActiveScaffoldです。

2011-02-21

pythonでISBN、JANコードの有効性をチェックする

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
ISBNやJANコードの最後の一桁がチェックデジットになっているので、適当に与えられたものでないかどうかをチェックする関数をpythonで作ってみました。

ちなみにJANコードは、8桁13桁が有効として
ISBNは古い体系の10桁のものをチェックしています。
ISBNの新しい体系の13桁のものはJANコードと同じなのでJANコードの関数の方でチェックできます。

まずはJANコードの版はこんな感じです。
def check_jan_code(code):
    if code.isdigit() == False :
        return False
    if len(code) == 8 or len(code) == 13 :
        pass
    else :
        return False
        
    cd = code[-1]
    data = code[0:-1]
    total = 0
    for i in range(0,len(data)):
        if i%2 ==0 :
            total = total + int(data[i])
        else:
            total = total + int(data[i]) * 3
    dig = total % 10
    dig = 10 - dig
    if dig == 10 :
        dig = 0
    if dig == int(cd) :
        return True
    else :
        return False

そしてISBNはこんな感じです。
def check_isbn(code):
    pattern = "^[0-9]{9}[0-9X]{1}$"
    if re.match(pattern,code) :
        pass
    else :
        return False
        
    cd = code[-1]
    data = code[0:-1]
    total = 0
    w = 10
    for i in range(0,len(data)):
        total = total + int(data[i]) * w
        w = w - 1
    dig = total % 11
    dig = 11 - dig
    if dig == 10 :
        dig = "X"
    if str(dig) == cd :
        return True
    else :
        return False

ちなみに、うまい棒チョコレート味のJANコードは49480764です。



※JANコードチェックでCDが0の時の処理が間違っていたので修正しました(2011/9/16)

2011-02-18

jQuery BlockUI Pluginで確認ダイアログ

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
ちょっと長い処理を実行するときに、時間がかかるから実行中ということがわかる状態にするとあわせて、
他のボタンとかをさわっちゃイヤんなことがあると思います。

そんな時に便利なのが
jQuery BlockUI Plugin
です。

これを使うと、ボタンを押したら画面全体を使えなくしたり、画面の一部だけを使えなくしたりすることができます。

demoがあるので、こちらを見るとどういうものかすぐわかります。

画面を触れないようにできるのは、よいのですが
長い処理をするので、うっかりクリックなどをして後悔しないように
実行するかどうかの確認ダイアログを出したいなぁとか思ってみたのですが、
ちゃんと、確認ダイアログ的なメッセージを出すこともできるようです。

ちゃんとサンプルもあります。

とてもステキなjQuery BlockUI Pluginを確認ダイアログを出す形で使ってみたのですが、私の利用したいケースでサンプルとまったく同じ使い方だとどうもキャンセルしてもsubmitしてしまっているような感じでした。

なので、ちょろっと以下のように変えてみました。

<script type="text/javascript"> 
    $(document).ready(function() { 
 
        $('#test').click(function() { 
            $.blockUI({ message: $('#question'), css: { width: '275px' } }); 
        }); 
 
        $('#yes').click(function() { 
            // update the block message 
            $.blockUI({ message: "<h1>Remote call in progress...</h1>" }); 
            $('#go_go').submit();
        }); 
 
        $('#no').click(function() { 
            $.unblockUI(); 
            return false; 
        }); 
 
    }); 
</script> 
 
... 
<form action="go" id="go_go" > 
<input id="test" type="button" value="Go Go Go" /> 
</form> 
 
... 
 
<div id="question" style="display:none; cursor: default"> 
        <h1>Would you like to contine?.</h1> 
        <input type="button" id="yes" value="Yes" /> 
        <input type="button" id="no" value="No" /> 
</div>


2011-02-03

rake db:migrateは成功しているのにindexが作られない

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
DBがmysqlで以下のような感じのmigrationを作りました。
create_table :hogehoge_mogemoges do |t|
  t.column :ahaha_id, :integer
  t.column :ihihi_id, :integer
  t.column :uhuhu_id, :integer
  t.column :ehehe_id, :integer
  t.column :ohoho_id, :integer
  t.column :valval,   :string
end
add_index :hogehoge_mogemoges,[:ahaha_id,:uhuhu_id,:ohoho_id],:unique => true

rake db:migrate
は普通に成功したのですが、indexが作成されていませんでした。

indexが作成されない理由は、作成されるindex名に原因があります。
この場合は、
index_hogehoge_mogemmoges_on_ahaha_id_and_ihihi_id_and_uhuhu_id_and_ehehe_id_and_ohoho_id
という名前のインデックスを作成をすることになります。

mysqlに直接、このインデックスを作成しようとすると

ERROR 1059 (42000): Identifier name 'index_hogehoge_mogemmoges_on_ahaha_id_and_ihihi_id_and_uhuhu_id_and_ehehe_id_and_ohoho_id' is too long
とエラーが出てて作れません。

たしかにtoo longです。
mysqlでは、インデックスに使えるのは最大64文字のようです。

でこれを解決するには、以下のようにadd_indexで名前を渡せばよいだけです。
add_index :hogehoge_mogemoges,[:ahaha_id,:uhuhu_id,:ohoho_id],{:unique => true, :name =>
"ind_hogemoge_aiueo"}