putty のウィンドウ位置記憶で初期値を Windows デフォルトにする

iceiv+puttyにて putty のウィンドウ位置を記憶させるパッチなどを配布しているが、初期位置が (0, 0) なので画面上辺にタスクバーを置いていると隠れてしまって困る。
それを修正するパッチ。

diff --git a/settings.c b/settings.c
index 8792ba4..86b38fc 100644
--- a/settings.c
+++ b/settings.c
@@ -709,8 +709,8 @@ void load_open_settings(void *sesskey, Config *cfg)
     gpps(sesskey, "WinTitle", "", cfg->wintitle, sizeof(cfg->wintitle));
     gppi(sesskey, "TermWidth", 80, &cfg->width);
     gppi(sesskey, "TermHeight", 24, &cfg->height);
-    gppi(sesskey, "TermX", 0, &cfg->x);
-    gppi(sesskey, "TermY", 0, &cfg->y);
+    gppi(sesskey, "TermX", CW_USEDEFAULT, &cfg->x);
+    gppi(sesskey, "TermY", CW_USEDEFAULT, &cfg->y);
     gppfont(sesskey, "Font", &cfg->font);
     gppi(sesskey, "FontQuality", FQ_DEFAULT, &cfg->font_quality);
     gppi(sesskey, "FontVTMode", VT_UNICODE, (int *) &cfg->vtmode);

ついでに、iceiv+puttyのパッチ群には Recipe*1 の変更が含まれていないため、依存関係でコンパイルできないのでその修正。
ただし、Vista Aero 用の putty_glass.diff のための修正は含みません。Windows SDK for Vista いれるのがめんどくさかったわけじゃ…。

diff --git a/Recipe b/Recipe
index d64a6f0..d72ea27 100644
--- a/Recipe
+++ b/Recipe
@@ -326,7 +326,7 @@ puttygen : [G] winpgen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version
          + sshrand winnoise sshsha winstore misc winctrls sshrsa sshdss winmisc
          + sshpubk sshaes sshsh512 import winutils puttygen.res tree234
         + notiming winhelp LIBS wintime
-        + l10n
+        + l10n iso2022 wcwidth

 pfwd     : [G] pfwd wincons2 NONSSH WINSSH cproxy logging WINMISC
          + pfwd.res LIBS l10n

*1:Makefile.* 等の生成元ファイル、mkfiles.pl の実行でそれらを生成できます。

ActiveRecord@ActionController で scoped_access をいろいろな書式で

ActiveRecordを詳しく「優しいRailsの育て方」 より。
もっとシンプルにできるけど。
つい機能追加やら汎用化やらをしてしまう。
Rails 2.1.0 で動作確認。
コメントいただいたので scoped_access_filter.rb を修正しました。

使い方

基本。

class MailController < ApplicationController
  scoped_access Mail, :mine
  
  def mine
    unless user.admin?
      { :find   => {:conditions => ["owner = ?", user]},
        :create => {:owner      => user               } }
    end
  end

  def show
    @mail = Mail.find(params[:id])
  end
end

複数のモデルを対象とする。

scoped_access Mail, User, Group, :not_deleted

def not_deleted(model)
  if model.columns.any? { |c| c.name == 'deleted_at' }
    { :find => {:conditions => ["NOT deleted_at IS NULL"]} }
  end
end

条件を lambda (block) で定義する。

scoped_access Mail, lambda { {:find => {:conditions => ["updated_at < ?", Date.today]}} }
scoped_access(Mail) do |model, controller|
  # ...
end

条件を直接(Hash で)定義する。

scoped_access User, :find => {:conditions => ['admin = ?', true]}

named_scope の条件を利用する。

class User < ActiveRecord::Base
  named_scope :admins, :conditions => ['admin = ?', true]
  # ...
end

scoped_access User, :name => :admins

フィルタを適用(除外)するアクションを指定する。(before_filter 等と同様)

scoped_access Mail, :mine, :only => :show

scoped_access User, :find => {:conditions => ['admin = ?', true]}, :except => :list

scoped_access_filter.rb

class ScopedAccessFilter
  def initialize(model, *args, &block)
    options = args.extract_options!
    @constraints = case
      when options[:method]
        options[:method]
      when options[:name] # named_scope
        {:find => model.send(options[:name]).proxy_options}
      when !options.empty?
        options
    end
    @constraints ||= args.pop unless args.last.is_a?(Class) and args.last < ActiveRecord::Base
    @constraints ||= block || :method_scoping
    @models = [model, args].flatten
  end

  def filter(controller)
    scoped_models = []
    @models.each do |model|
      constraints = create_constraints(controller, model)
      next unless constraints
      ActiveRecord::Base.logger.debug("ScopedAccessFilter: %s.with_scope(%s)" % [model, constraints.inspect])
      model.instance_eval do
        scoped_methods << with_scope(constraints) { current_scoped_methods }
      end
      scoped_models << model
    end

    begin
      yield
    ensure
      scoped_models.each do |model|
        model.instance_eval do
          scoped_methods.pop
        end
      end
    end
  end

  private
  def create_constraints(controller, model)
    cproc = case @constraints
      when Proc, Method
        @constraints
      when String, Symbol
        controller.method(@constraints)
    end
    return @constraints unless cproc
    args = case cproc.arity
      when 0; []
      when 1; [model]
      else  ; [model, controller]
    end
    cproc.call(*args)
  end
end

module ActionController::Filters::ClassMethods
  def scoped_access(model, *args, &block)
    options = args.extract_options!
    scoped_options = {}
    options.reject! { |k, v| (scoped_options[k] = v; true) unless [:only, :except].include? k }
    args << scoped_options unless scoped_options.empty?
    around_filter ScopedAccessFilter.new(model, *args, &block), options
  end
end

activescaffold のソートをIEで利用した場合に無限ページ遷移

IEで発生するactivescaffoldのソート不具合 - javakariの日記 より。

getCurrentLocation() の修正でもよさそう。

--- vendor/plugins/active_scaffold/frontends/default/javascripts/dhtml_history.js
+++ vendor/plugins/active_scaffold/frontends/default/javascripts/dhtml_history.js
@@ -159,7 +159,7 @@
    /** Gets the current hash value that is in the browser's
        location bar, removing leading # symbols if they are present. */
    /** public */ getCurrentLocation: function() {
-      var currentLocation = escape(this.removeHash(window.location.hash));
+      var currentLocation = this.removeHash(window.location.hash);

       return currentLocation;
    },

ActiveRecord で関連レコードの size をプリロードする

テーブルの一覧表示で関連レコードの数を表示したい場合、
View でそのまま records[i].subrecords.size などとして繰り返し参照すると SELECT count(*) ... というようなカウント SQL が大量に実行されてしまう。

以下を利用するとカウント SQL の実行を1回にできる。

使い方

records = Record.find(:all, :include_count => :subrecords)
records[0].subrecords.size # カウント SQL が実行されない

lib/active_record_include_count.rb

require 'active_record'

class ActiveRecord::Base
  VALID_FIND_OPTIONS << :include_count

  def self.find(*args)
    options = args.extract_options!
    validate_find_options(options)
    set_readonly_option!(options)

    records = case args.first
      when :first then find_initial(options)
      when :last  then find_last(options)
      when :all   then find_every(options)
      else             find_from_ids(args, options)
    end

    if options.has_key?(:include_count)
      Array(options[:include_count]).each do |association|
        preload_sizes(records, association)
      end
    end
    records
  end

private

  def self.preload_sizes(records, association)
    class_to_reflection = {}
    records.group_by {|record| class_to_reflection[record.class] ||= record.class.reflections[association]}.each do |reflection, records|
      raise ConfigurationError, "Association named '#{ association }' was not found; perhaps you misspelled it?" unless reflection
      sizes = {}
      ids = records.map {|record| record.quoted_id}.join(',')
      reflection.klass.count(:conditions => "#{reflection.primary_key_name} IN (#{ids})",
                             :group => reflection.primary_key_name
                            ).map {|record| sizes[record[0]] = record[1]}
      records.each do |record|
        unless sizes[record.id]
          record.send(association).loaded
        else
          record["#{reflection.name}_count"] = sizes[record.id]
        end
      end
    end
  end
end

config/initializers/active_record.rb

require 'active_record_include_count'

iPhone で GMail にエイリアスをつけて送信

GMail は username+alias@gmail.com という感じに +alias を自由につけられる。

  • iPhone 用に username+i@gmail.com を用意して送受信をしたい。
  • 受信はもちろんできるが、送信しようとすると +i が取れてしまう。

解決

  1. GMail の「設定>アカウント」で「他のメールアドレスを追加」を選択。
  2. エイリアス付きのメールアドレスを追加。
  3. iPhoneGMail アカウントのアドレスをエイリアス付きにする。

上記で From: を変更できる。ただし Sender: および Return-Path: には元の username@gmail.com が設定されるため、メーリングリストなどで Sender: で投稿者を判定しているシステムにはじかれてしまう。

Compact Menu 2 2.2.0

  • アクセスキーでの操作を修正しました。
  • CompactMenu アイコンを追加しなくても、メニューツールバーを隠した状態でアクセスキーによってメニューを開けるようにしました。

6月27日現在、レビュー中。
June 27, pending review.

今回は早かった