2011年11月16日水曜日

VMWare Converter 選択したマシンのハードウェア情報を取得できません

VMWare Converter v5を使ってネットワークストレージにある
仮想イメージをEsxiに入れようとしたら
「選択したマシンのハードウェア情報を取得できません」
と先に進めない。

仮想イメージをローカルにコピーしたら動いた。
(converter v4.01でもv4.3でも同じ。)

ネットワークから変換できるものも、できないものもあると
いうことで。
仮想イメージのconfig.version=7は駄目なのかもしれない。
ドライブにマップすれば上手くいったかもしれないが、割愛。

2011年11月15日火曜日

VMWare CTRL+Zがsuspendされるのを解消する

中の人です。

VMWareは便利ですが、外と中を切り替えながら使っていると
たまに(作業内容によっては頻繁に)CTRL+ZをVMWareの
ウィンドウに対して実行してしまうことがあります・・・よね?

しかも、VMWareとしては解決方法が提供されていないに等しいです。

キー入力でフォーカスを内部に合わせる設定はありますが、
CTRL+ALTでホストOSに切り替えた直後にALT+TAB(アプリの切り替え)を
すると内部にフォーカスが戻るので使いにくくて仕方が無い。

以下のツールでCTRL+ZをVMWareの場合のみ意味の無いキーに
割り当てることで逃げました。

Yet Another Mado tsukai no Yuutsu
yamy

http://sourceforge.jp/projects/yamy/

若干、説明が分かりづらかったですが
以下の記述をすることでCTRL+ZをCTRL+ALT(左)へと振ります。
もともとVMWareにフォーカスがありますので、無意味な操作です。
中にフォーカスがある場合は影響がありません。

109.mayuをvm.mayuとしてコピー。最後に追記。

window VMWare /vmware\.exe/ : Global
key C-Z = C-LeftAlt

タスクトレイからvm.mayuを選択する。
これでイライラから開放される!

2011年10月21日金曜日

jqgridとrails link_to_remote

中の人です。

結論はlink_to_remoteをjqgridに組み込むな、jqgridの削除/挿入の仕組みでカバー。


できないなら、読み込みが終わった後でjqgridの中身をjavascriptで書き換える。
振り出しに戻ってしまったが、当初の方式でカバーするのが気楽だ。
開発コストを無視するのならだけど・・・ね。


jqgridを封印し、will_paginateをラップしたmoduleを作成することにしよう。
(辛い現実から逃避・・・)

2011年10月16日日曜日

android、titaniumで開発!?(6) MapViewを複数画面で利用するには

中の人です。

MapViewを複数画面で利用するとエラーになりますね。
Mapを複数画面で利用するにあたり以下が参考になりました。

http://ti.masuidrive.jp/topic.php?id=116

が、そのままだと表示されませんでした。
createしてもエラーにならないので、複数のMapViewが
addされているのが問題であると結論付けました。

最終的に地図を使っている別画面を表示する前に
元の地図をremoveすることで対処。

リソースも消費しないし、これで満足しておこう。

2011年10月9日日曜日

android、titaniumで開発!?(5) Windows版TitaniumStudioでEmulatorが動いたかもしれない

中の人です。

以下で述べる修正で動くようになりました
無事、ブレイクポイントでも止まりました。

application data\titanium\mobilesdk\win23\1.7.2\android\builder.py
のself.home_dirの定義を変えた。各自の環境に合わせてください。
くれぐれも空白を含んだpathにしないでください。

self.home_dir = 'c:\\titanium\\.titanium'

ここまでの投稿で修正した部分もbuilder.pyに適用してあります。
  • 「'*:d * '」 を「"'*:d'"」 へ修正。*を削り、'で括る。
c:\titanium\.titaniumは単に作るだけでOKかと。
動かなかったらここまでの投稿を参考にしてください。
試していませんが、document and settingsに作成される.titaniumへの
ハードリンクを作成する方が何かと問題がでないかもしれません。

これにより、sdcardのパスが変わりspaceを含まなくなる。
起動パスがこれまでの投稿に書いたような内容に変わるので
無事に起動する。

android、titaniumで開発!?(4) KitchenSinkでError KitchensinkActivityが無いが解決(resolve)

中の人です。

もう、○○が!と叫びたい心境ですが解決。
まだ動かないけどね。 
ここのお陰で動いた(もぎっちゃうぞもぎ私的メモ:茂木健一)。

KitchenSink/platform/android/AndroidManifest.xml


activity android:name=".KitchensinkNookActivity"


before
KitchensinkNookActivity


after


KitchensinkActivity

これ、zipから取得した奴なんだけど、何かがおかしい?

android、titaniumで開発!?(3) KitchenSinkでerror type 3

中の人です。

TitaniumのサンプルKitchenSinkについて。
githubからzipファイルをダウンロードして展開、フォルダを移動して
フォルダ名をkit(※1)にリネーム、import(titanium)。

Debugすると
error type 3 does not exist kitactivity
となる。


ログが続いていて、ファイルが見つからないと出ている。
コンソールで実際にPathを確認すると確かに無い。
よくよくPathを見ると「KitchinShink」となっている。
ビルド情報に書かれているのか!?

どこで定義されているのか分からないので
※1で設定した名称をKitchenShinkに変更した。


Debugを繰り返していると
[INSTALL_FAILED_INSUFFICIENT_STORAGE]
日本アンドロイドの会の掲示板で
アンインストールすればいいとあったのでエミュレータから
以前のものを削除。

その後、emulator側で実行しても
acore has stopped と出て動かない。

何が駄目なんだ・・・。

2011年10月7日金曜日

android、titaniumで開発!?(2) Windows版TitaniumStudioでEmulatorが動かない?

中の人です。

Windows版TitaniumStudioでEmulatorが動かない?です。
最後は新規プロジェクトで動く画面は動きましたが、
KitchenSinkは動かない状態。

(2011/10/9)デバッグもできない・・・。


とりあえず、公式の手順どおりにセットアップ。
Windows7向けだけど、XPでも同じ。もしくはサボれる。
セットアップ完了まで4時間ぐらいかかった・・・。Android SDKの
インストールが非常に時間がかかった。

SDK ManagerでSDKのダウンロード終了後、SDK Managerから
エミュレタータのデバイスを登録(名称はtest_deviceとした)して
新規プロジェクトを作成して
実行するものの、エミュレータがタイムアウトと出て動かない?

とりあえずやったこと
1.Projectのプロパティ、デバイスの所のエミュレータ名を
登録するデバイス名と一緒にする。
test_deviceへ変更。
既存のプロジェクトをインポートした場合、SDK Manager上に
デバイスが作成される。ProjectのPropertiesのデバイス名を合わせる。

2.エミュレータを手動で起動する。
SDK Managerからstart

もしくはコマンドラインから登録してあるデバイスを起動。
emulator -avd test_device

(2011/10/9 追記)
以下のパラメータで起動するようにした。必要に応じて変える。

(2011/10/9 21:27 追記)
デバッガでブレイクポイントを置いても反応する。安心して利用できる。
が、安定しないので(5)の方法で起動するように修正した方がいいね。


emulator.exe -avd titanium_9_HVGA -port 5560 -sdcard C:\titanium\.titanium\titanium_9_HVGA.sdcard -logcat '*:d' -no-boot-anim -partition-size 128
  • titanium_9_HVGAは仮想マシン名
  • sdcardの位置は既存では空白交じりのpathだったのでExploerで移動した。
  • -logcat パラメータはヘルプ(-help-logcat)ではシングルコーテーションで括るので修正。
  • -logcat パラメータは後ろの*は指定方法が良く分からないので削っている。
3.Debug - Android emulator
この時、App Exploerにあるbuild.logを開くと幸せになれる。
画面上でタイムアウトと出ても、ログはずーっと出力されている。
しばらく待つと、Deployが終了したとログに出て、エミュレータに表示された。

公式通りにセットアップしてれば関係ない、もしくは他にやったこと
  • jdkにjavacがない(多分ランタイムを入れた)のでJDKをインストール
  • Pathの再確認(コマンドラインからjavacが反応する状態に。)
  • emulatorをコマンドラインから実行すると「Windowsアプリじゃない」となっていた。
    のでSDKを展開しなおして上書き。(原因不明)
  • workspaceをc:\titaniumへ(多分関係ない)
  • builder.pyの内容を修正(max_wait = 120 max_zero = 30)
  • Gitリポジトリから取得したサンプルProject(KitchenSink)のファイルが
    一部読み取り専用。書き込みできるように変更。
頑張ろう。

というか、エミュレータを手動で実行すればいいよって誰か書けばいいのに!
Android SDKで開発する時はEclipseがエミュレータを起動してくれるからかな。
(まぁ、NULL デバイス?になって使えないとかありますけど)
エラーのタイミングも変だ・・・。
いかにも動きませんよって感じに表示される。まだ裏で動いてるのにね。
ものすごく、ものすごーく、エミュレータにインストールするまでが長い・・・。
5分ぐらいかかってるか、これ・・・。
同じ条件でも失敗することがある。
不安定な環境なのは確かだなぁ・・・・。

android、titaniumで開発!?(1) appcelaratorにログインできない。TitaniumStudioがDownloadできない。

中の人です。だらだら書きます・・・。

android向けアプリをtitaniumで開発しろと、プロジェクトが
立ち上がりました。私もリソースとして追加されました。

http://www.appcelerator.com/products/download/
(※1)

からDownloadしろとの情報があふれているのでDownloadしようと
開きましたがアカウントを登録しろとでます。
これも情報がありますので気にしずに登録。

ログイン画面が出てメールアドレスとPasswordを入力して
「さぁ、Downloadするぞー」と思ったら、パスワードが一致しないと
蹴られる。ログインできない。入れない。当然、Downloadできない。

間違えたかとPasswordをリセットするリンクからメールアドレスを
入力してメールに送られてきたURLでリセット。
アカウントのページが表示された(※2)

TitaniumStudioのLinux版をDownloadしてインストール。
まぁ、展開するだけ。
Javaなんかは入ってるから実行してみる。
ログイン画面がでるからログインしたよ(※3)

が、起動時にエラー。終了するか聞かれる。emulatorも動かない。
Windows版に浮気することに。
Downloadするぞー・・・って、ログインできない。
理由は分からないが、ログインできない状態だったので
調べた。が、該当する質問をしている人がいないorz。
「設定したパスワードが違うって出てるんだから間違えたんじゃない?」と
周りは冷たい反応。※3でログインしてるし!

結果、ヘルプデスクにメールして3日ぐらいかけてアカウントが修復された。

※2の方法でダウンロードする画面は表示できるが
※1のURLとは違うので正規のバージョンとは違うのかと混乱して半日無駄にする。
リセット直後に表示される画面が
「Download画面」(https://my.appcelerator.com/resources)なので、
ログインできない人がいたらそれで乗り切ろう。
ヘルプデスクも英語でメールすれば対応してくれるので
ログインしたいならメールしてもいい。

2011年9月27日火曜日

jqgridとrails link_to_remoteとreloadGrid

中の人です。

link_to_remoteのリンクを含んだjqgridをクリックして
サーバ側でデータを削除、グリッドに反映する処理。

jqgridにある標準の削除とは違う気がしたので別実装
したものの、削除して戻ってくるタイミングでjqgridを
reloadしたい。

  1. bindでclickしたらsetIntervalでflashの更新領域を監視開始
  2. link_to_remoteで呼び出すactionでrenderした結果で
    flashメッセージの更新領域を変更する
  3. 領域が変更されたら
    $("grid_id").trigger("reloadGrid")を呼び出す。
  4. clearInterval
うーん、これぐらいしか思いつかない・・・。

2011年9月26日月曜日

Rails controllerでviewのパーツを作り、表示する

中の人です。

引きずってます。
controllerでform_tagやlink_toなどの結果をviewに渡すには
どうするべきかを延々と考えていましたが、ある程度のパターンには
耐えられるちゃんとした方法です。
直前の記事の内容だと、ajaxとの相性最悪です。たぶん。

以降、jqgridのセルをajaxで塗り替えるには?ということで調べていた副産物です。
id付きのspanの中にform_tagを埋め込んで、hoge.jsのjQueryを
呼び出して塗り替えるなんて荒業もできなくは無いのですが
保留中・・・。すごく手間が掛かるから・・・・。

jqgridにもこれでいけるか・・・。挑戦中です。

内容

modelに(class_evalで)accessorで空の項目を追加、そこに
以下の結果を渡してjsonに含める。
value = render_to_string(:partial=>"hoge" , :object=>fuga)
jQuery、Ajax使わないなら、何も考えなくていいから楽だけど
Rails + Ajax(jRails仕様)にすると色々と混乱する。
まだ枯れてない技術だ・・・。

追記
ある程度上手くいったので更新。

  1. jqgridから呼ばれるcontrollerのmethodでrender_to_stringして
    link_to_remoteを含んだpartialを埋め込む。
  2. flashの表示領域をid="flash"としておき、link_to_remoteの更新領域として利用。
  3. リンクをクリックするとメソッドの(:layout=>falseにした)レンダリング結果が
    表示される。
form_remote_tagはテスト中





2011年9月19日月曜日

jqgridをrailsから利用して削除リンク(:method=>:delete)を埋め込む

中の人です。
前回の投稿の続き

railsから利用して削除リンク(:method=>:delete)を埋め込む別のアプローチ。

2dc_jqgrid.rbを修正して、oprionsにadd_paramsを追加、rubyに送信したい値をセットする。


結果、index.erbがすっきりした。ミスも少なくなる。
以下はコード。

(2011/10/7)
こちらの方が多分綺麗。inlineで作ってもいい。
http://seo-trial.blogspot.com/2011/09/rails-controllerview.html

index.erb
<%= jqgrid("Logs", "logs", "/logs" ,
[
{ :field => "id", :label => "ID", :width => 35, :resizable => false },
{ :field => "control", :label => "controls"}
],{
:add_params => "&token=" + CGI.escape(form_authenticity_token.toutf8)
}
) %>
2dc_jqgrid.rb

module Jqgrid
    @@jrails_present = false
    mattr_accessor :jrails_present
    def jqgrid_stylesheets
      css  = stylesheet_link_tag('jqgrid/jquery-ui-1.7.1.custom.css') + "\n"
      css << stylesheet_link_tag('jqgrid/ui.jqgrid.css') + "\n"
    end
    def jqgrid_javascripts
      locale = I18n.locale rescue :en
      js =  ''
      js << javascript_include_tag('jqgrid/jquery.js') + "\n" unless Jqgrid.jrails_present
      js << javascript_include_tag('jqgrid/jquery-ui-1.7.1.custom.min.js') + "\n"
      js << javascript_include_tag('jqgrid/jquery.layout.js') + "\n"
      js << javascript_include_tag("jqgrid/i18n/grid.locale-#{locale}.js") + "\n"
      js << javascript_include_tag('jqgrid/jquery.jqGrid.min.js') + "\n"
      js << javascript_include_tag('jqgrid/jquery.tablednd.js') + "\n"
      js << javascript_include_tag('jqgrid/jquery.contextmenu.js') + "\n"
    end
    def jqgrid(title, id, action, columns = [], options = {})
   
      # Default options
      options =
        {
          :rows_per_page       => '10',
          :sort_column         => '',
          :sort_order          => '',
          :height              => '150',
          :gridview            => 'false',
          :error_handler       => 'null',
          :inline_edit_handler => 'null',
          :add                 => 'false',
          :delete              => 'false',
          :search              => 'true',
          :edit                => 'false',        
          :inline_edit         => 'false',
          :autowidth           => 'false',
          :rownumbers          => 'false',
        }.merge(options)
      add_params = ""
      if options[:add_params].present?
        add_params = options[:add_params]
      end
   
      # Stringify options values
      options.inject({}) do |options, (key, value)|
        options[key] = (key != :subgrid) ? value.to_s : value
        options
      end
   
      options[:error_handler_return_value] = (options[:error_handler] == 'null') ? 'true;' : options[:error_handler]
      edit_button = (options[:edit] == 'true' && options[:inline_edit] == 'false').to_s
      # Generate columns data
      col_names, col_model = gen_columns(columns)
      # Enable filtering (by default)
      search = ""
      filter_toolbar = ""
      if options[:search] == 'true'
        search = %Q/.navButtonAdd("##{id}_pager",{caption:"",title:"Toggle Search Toolbar", buttonicon :'ui-icon-search', onClickButton:function(){ mygrid[0].toggleToolbar() } })/
        filter_toolbar = "mygrid.filterToolbar();"
        filter_toolbar << "mygrid[0].toggleToolbar()"
      end
      # Enable multi-selection (checkboxes)
      multiselect = "multiselect: false,"
      if options[:multi_selection]
        multiselect = "multiselect: true,"
        multihandler = %Q/
          jQuery("##{id}_select_button").click( function() {
            var s; s = jQuery("##{id}").getGridParam('selarrrow');
            #{options[:selection_handler]}(s);
            return false;
          });/
      end
      # Enable master-details
      masterdetails = ""
      if options[:master_details]
        masterdetails = %Q/
          onSelectRow: function(ids) {
            if(ids == null) {
              ids=0;
              if(jQuery("##{id}_details").getGridParam('records') >0 )
              {
                jQuery("##{id}_details").setGridParam({url:"#{options[:details_url]}?q=1#{add_params}&id="+ids,page:1})
                .setCaption("#{options[:details_caption]}: "+ids)
                .trigger('reloadGrid');
              }
            }
            else
            {
              jQuery("##{id}_details").setGridParam({url:"#{options[:details_url]}?q=1#{add_params}&id="+ids,page:1})
              .setCaption("#{options[:details_caption]} : "+ids)
              .trigger('reloadGrid');
            }
          },/
      end
      # Enable selection link, button
      # The javascript function created by the user (options[:selection_handler]) will be called with the selected row id as a parameter
      selection_link = ""
      if options[:direct_selection].blank? && options[:selection_handler].present? && options[:multi_selection].blank?
        selection_link = %Q/
        jQuery("##{id}_select_button").click( function(){
          var id = jQuery("##{id}").getGridParam('selrow');
          if (id) {
            #{options[:selection_handler]}(id);
          } else {
            alert("Please select a row");
          }
          return false;
        });/
      end
      # Enable direct selection (when a row in the table is clicked)
      # The javascript function created by the user (options[:selection_handler]) will be called with the selected row id as a parameter
      direct_link = ""
      if options[:direct_selection] && options[:selection_handler].present? && options[:multi_selection].blank?
        direct_link = %Q/
        onSelectRow: function(id){
          if(id){
            #{options[:selection_handler]}(id);
          }
        },/
      end
      # Enable grid_loaded callback
      # When data are loaded into the grid, call the Javascript function options[:grid_loaded] (defined by the user)
      grid_loaded = ""
      if options[:grid_loaded].present?
        grid_loaded = %Q/
        loadComplete: function(){
          #{options[:grid_loaded]}();
        },
        /
      end
      # Enable inline editing
      # When a row is selected, all fields are transformed to input types
      editable = ""
      if options[:edit] && options[:inline_edit] == 'true'
        editable = %Q/
        onSelectRow: function(id){
          if(id && id!==lastsel){
            jQuery('##{id}').restoreRow(lastsel);
            jQuery('##{id}').editRow(id, true, #{options[:inline_edit_handler]}, #{options[:error_handler]});
            lastsel=id;
          }
        },/
      end
   
      # Enable subgrids
      subgrid = ""
      subgrid_enabled = "subGrid:false,"
      if options[:subgrid].present?
     
        subgrid_enabled = "subGrid:true,"
     
        options[:subgrid] =
          {
            :rows_per_page => '10',
            :sort_column   => 'id',
            :sort_order    => 'asc',
            :add           => 'false',
            :edit          => 'false',
            :delete        => 'false',
            :search        => 'false'
          }.merge(options[:subgrid])
        # Stringify options values
        options[:subgrid].inject({}) do |suboptions, (key, value)|
          suboptions[key] = value.to_s
          suboptions
        end
     
        subgrid_inline_edit = ""
        if options[:subgrid][:inline_edit] == true
          options[:subgrid][:edit] = 'false'
          subgrid_inline_edit = %Q/
          onSelectRow: function(id){
            if(id && id!==lastsel){
              jQuery('#'+subgrid_table_id).restoreRow(lastsel);
              jQuery('#'+subgrid_table_id).editRow(id,true);
              lastsel=id;
            }
          },
          /
        end
       
        if options[:subgrid][:direct_selection] && options[:subgrid][:selection_handler].present?
          subgrid_direct_link = %Q/
          onSelectRow: function(id){
            if(id){
              #{options[:subgrid][:selection_handler]}(id);
            }
          },
          /
        end  
     
        sub_col_names, sub_col_model = gen_columns(options[:subgrid][:columns])
     
        subgrid = %Q(
        subGridRowExpanded: function(subgrid_id, row_id) {
            var subgrid_table_id, pager_id;
            subgrid_table_id = subgrid_id+"_t";
            pager_id = "p_"+subgrid_table_id;
            $("#"+subgrid_id).html("<table id='"+subgrid_table_id+"' class='scroll'></table><div id='"+pager_id+"' class='scroll'></div>");
            jQuery("#"+subgrid_table_id).jqGrid({
              url:"#{options[:subgrid][:url]}?q=2&id="+row_id#{add_params},
              editurl:'#{options[:subgrid][:edit_url]}?parent_id='+row_id#{add_params},                          

              datatype: "json",
              colNames: #{sub_col_names},
              colModel: #{sub_col_model},
                rowNum:#{options[:subgrid][:rows_per_page]},
                pager: pager_id,
                imgpath: '/images/jqgrid',
                sortname: '#{options[:subgrid][:sort_column]}',
                sortorder: '#{options[:subgrid][:sort_order]}',
                viewrecords: true,
                toolbar : [true,"top"],
                #{subgrid_inline_edit}
                #{subgrid_direct_link}
                height: '100%'
            })
            .navGrid("#"+pager_id,{edit:#{options[:subgrid][:edit]},add:#{options[:subgrid][:add]},del:#{options[:subgrid][:delete]},search:false})
            .navButtonAdd("#"+pager_id,{caption:"Search",title:"Toggle Search",buttonimg:'/images/jqgrid/search.png',
              onClickButton:function(){
                if(jQuery("#t_"+subgrid_table_id).css("display")=="none") {
                  jQuery("#t_"+subgrid_table_id).css("display","");
                } else {
                  jQuery("#t_"+subgrid_table_id).css("display","none");
                }
              }
            });
            jQuery("#t_"+subgrid_table_id).height(25).hide().filterGrid(""+subgrid_table_id,{gridModel:true,gridToolbar:true});
          },
          subGridRowColapsed: function(subgrid_id, row_id) {
          },
        )
      end
      # Generate required Javascript & html to create the jqgrid
      %Q(
        <script type="text/javascript">
          var lastsel;
          #{'jQuery(document).ready(function(){' unless options[:omit_ready]=='true'}
          var mygrid = jQuery("##{id}").jqGrid({
              url:'#{action}?q=1#{add_params}',
              editurl:'#{options[:edit_url]}#{options[:edit_url].blank? ? "" : add_params}',
              datatype: "json",
              colNames:#{col_names},
              colModel:#{col_model},
              pager: '##{id}_pager',
              rowNum:#{options[:rows_per_page]},
              rowList:[10,25,50,100],
              imgpath: '/images/jqgrid',
              sortname: '#{options[:sort_column]}',
              viewrecords: true,
              height: #{options[:height]},
              sortorder: '#{options[:sort_order]}',
              gridview: #{options[:gridview]},
              scrollrows: true,
              autowidth: #{options[:autowidth]},
              rownumbers: #{options[:rownumbers]},
              #{multiselect}
              #{masterdetails}
              #{grid_loaded}
              #{direct_link}
              #{editable}
              #{subgrid_enabled}
              #{subgrid}
              caption: "#{title}"
            })
            .navGrid('##{id}_pager',
              {edit:#{edit_button},add:#{options[:add]},del:#{options[:delete]},search:false,refresh:true},
              {afterSubmit:function(r,data){return #{options[:error_handler_return_value]}(r,data,'edit');}},
              {afterSubmit:function(r,data){return #{options[:error_handler_return_value]}(r,data,'add');}},
              {afterSubmit:function(r,data){return #{options[:error_handler_return_value]}(r,data,'delete');}}
            )
            #{search}
            #{multihandler}
            #{selection_link}
            #{filter_toolbar}
          #{'})' unless options[:omit_ready]=='true'};
        </script>
        <table id="#{id}" class="scroll" cellpadding="0" cellspacing="0"></table>
        <div id="#{id}_pager" class="scroll" style="text-align:center;"></div>
      )
    end
    private
 
    def gen_columns(columns)
      # Generate columns data
      col_names = "[" # Labels
      col_model = "[" # Options
      columns.each do |c|
        col_names << "'#{c[:label]}',"
        col_model << "{name:'#{c[:field]}', index:'#{c[:field]}'#{get_attributes(c)}},"
      end
      col_names.chop! << "]"
      col_model.chop! << "]"
      [col_names, col_model]
    end
    # Generate a list of attributes for related column (align:'right', sortable:true, resizable:false, ...)
    def get_attributes(column)
      options = ","
      column.except(:field, :label).each do |couple|
        if couple[0] == :editoptions
          options << "editoptions:#{get_sub_options(couple[1])},"
        elsif couple[0] == :formoptions
          options << "formoptions:#{get_sub_options(couple[1])},"
        elsif couple[0] == :searchoptions
          options << "searchoptions:#{get_sub_options(couple[1])},"
        elsif couple[0] == :editrules
          options << "editrules:#{get_sub_options(couple[1])},"
        else
          if couple[1].class == String
            options << "#{couple[0]}:'#{couple[1]}',"
          else
            options << "#{couple[0]}:#{couple[1]},"
          end
        end
      end
      options.chop!
    end
    # Generate options for editable fields (value, data, width, maxvalue, cols, rows, ...)
    def get_sub_options(editoptions)
      options = "{"
      editoptions.each do |couple|
        if couple[0] == :value # :value => [[1, "Rails"], [2, "Ruby"], [3, "jQuery"]]
          options << %Q/value:"/
          couple[1].each do |v|
            options << "#{v[0]}:#{v[1]};"
          end
          options.chop! << %Q/",/
        elsif couple[0] == :data # :data => [Category.all, :id, :title])
          options << %Q/value:"/
          couple[1].first.each do |obj|
            options << "%s:%s;" % [obj.send(couple[1].second), obj.send(couple[1].third)]
          end
          options.chop! << %Q/",/
        else # :size => 30, :rows => 5, :maxlength => 20, ...
          if couple[1].instance_of?(Fixnum) || couple[1] == 'true' || couple[1] == 'false' || couple[1] == true || couple[1] == false
            options << %Q/#{couple[0]}:#{couple[1]},/
          else
            options << %Q/#{couple[0]}:"#{couple[1]}",/          
          end
        end
      end
      options.chop! << "}"
    end
end
module JqgridJson
  include ActionView::Helpers::JavaScriptHelper
  def to_jqgrid_json(attributes, current_page, per_page, total)
    json = %Q({"page":"#{current_page}","total":#{total/per_page.to_i+1},"records":"#{total}")
    if total > 0
      json << %Q(,"rows":[)
      each do |elem|
        elem.id ||= index(elem)
        json << %Q({"id":"#{elem.id}","cell":[)
        couples = elem.attributes.symbolize_keys
        attributes.each do |atr|
          value = get_atr_value(elem, atr, couples)
          if value.nil?
            begin
              value = elem.try(atr) if value.blank?
            rescue
            end
          end
          value = escape_javascript(value) if value and value.is_a? String
          json << %Q("#{value}",)
        end
        json.chop! << "]},"
      end
      json.chop! << "]}"
    else
      json << "}"
    end
  end

  private

  def get_atr_value(elem, atr, couples)
    if atr.to_s.include?('.')
      value = get_nested_atr_value(elem, atr.to_s.split('.').reverse)
    else
      value = couples[atr]
      value = elem.send(atr.to_sym) if value.blank? && elem.respond_to?(atr) # Required for virtual attributes
    end
    value
  end

  def get_nested_atr_value(elem, hierarchy)
    return nil if hierarchy.size == 0
    atr = hierarchy.pop
    raise ArgumentError, "#{atr} doesn't exist on #{elem.inspect}" unless elem.respond_to?(atr)
    nested_elem = elem.send(atr)
    return "" if nested_elem.nil?
    value = get_nested_atr_value(nested_elem, hierarchy)
    value.nil? ? nested_elem : value
  end
end

2011年9月18日日曜日

rails jqgrid controllerでlink_to :method=>:deleteは動かない

jqgridをrailsから利用して削除リンク(:method=>:delete)を埋め込む。

苦労したので投稿しよう・・・。

  1. 調査
  2. 方向性の転換
  3. 結果

(2011/10/7)
こちらの方が多分綺麗。inlineで作ってもいい。
http://seo-trial.blogspot.com/2011/09/rails-controllerview.html



1.調査
Railsと親和性が高そうなjqgrid(http://www.2dconcept.com/jquery-grid-rails-plugin)を調査。
jsonで表示する値を取得するのはajax系gridの定番の処理なので気にしない。

リンクを埋め込むにはcontrollerでlink_toをするのが簡単かな?書いてみた。
  • h=ApplicationController.helpers
  • h.link_to('Destroy',:confirm => 'Are you sure?', :method => :delete)
結果、「undefined method `protect_against_forgery?' for nil:NilClass」
調べると、url_helper.rb内のjavascriptを出力する関数で
authenticity_tokenが取得できずに動かない。

2.方向性の転換
showなどは動くので「仕様」として受け止め、解決策を見つけることにした。
独自のhelperでLINK_TOが出力する内容を(token以外)そのまま出力するものを用意。
出力するauthenticity_tokenにはhtml内で重複しないであろう値をダミーで出力。
jqgridがjsonの値を読み込み終えた段階(grid_loaded)でjQueryで塗り替えることとした。
以下、紆余曲折の結果。

(scriptタグ付けると削除する仕様ですか、googleさん・・・orz)


<script language="Javascript">
  function GetAuthenticity_Token() { return "<%= form_authenticity_token %>"; }
  function test() {
    var u = $('#logs a[onclick]')
    if (u) {
      u.each(function() {
        var v = String($(this).attr('onclick'))  //関数を文字列化
        v = v.replace("|authenticity_token|", GetAuthenticity_Token); //ダミーの置換
        eval("m = " + v);  //文字列を関数に変換。vはfunction(){}の形式
        $(this).removeAttr("onclick");  //onclickは不要。可読性の為削除
        $(this).bind("click",m);  //OK
      })
    }
  }
</script>

3.結果
IE8、chrome、firefoxで動いた。
ここに至るまで丸一日かかったけどね・・・。


2011年9月10日土曜日

railsのActiveRecordの、データベース項目への代入時に処理を加える(overrideする)。

中の人です。

落ち着いて考えれば大したことではないけれど、Ruby On Railsから一つ。
タイトルでネタばれなんですけど。

modelでデータベースの項目をアクセスするには
model_obj.column_nameで参照、代入できる。
代入時に手を入れるには?

accessorを書いて、super呼ぶだけ。overrideだね。
用途に応じてsuperの前後に処理を追加する。
def column_name
  super
end
def column_name=
  super
end

2011年9月8日木曜日

evalのように文字列をlambdaで実行する


中の人です。
eval用として突っ込まれている文字列を
lambdaのようにreturnを書かせろという用途で・・・。
本来、evalなのにreturnを書いてしまった!もう手遅れ!
なんとかして!Procのnextみたいなこと出来ないのか!

普通、returnはできない。
code = "puts 'before';return false;puts 'after'"
eval code
#→LocalJumpError
def test
code = "puts 'before';return false;puts 'after'"
#eval code #return しているのでtestを抜けてしまう。
lmd = lambda {eval code}
lmd.call
puts 'important Process'
end
test

eval恐いよ。

2011年9月5日月曜日

国内の記事が見当たらない?Facebookで訪問社名をWelcomePageに表示する「getProfileLink」

中の人です。

googleで記事が検出されないので。
Facebookで訪問社名をWelcomePageに表示する「getProfileLink」の投稿です。

FacebookでFacebookページを開くと
「中の人さん、いらっしゃい」風味のメッセージが出ます。
あれ、Trackできるのか?とか思います。
jQueryとAjaxなんか使えばできそうな感じですね。しませんが。
の中にある
getProfileLink
が、回答になるようです。
とりあえず投稿。


追記。こちらの方が簡単だ・・・。読み込むファイルでgetProfileLink.phpとかはこれかな。
PHP SDK
http://developers.facebook.com/docs/reference/javascript/
https://github.com/facebook/php-sdk.git

2011年9月1日木曜日

Facebookの検索って変だね

中の人です。

検索窓が二種類ある。

初期レイアウトの一番上にある検索窓は広告対応。
ビックワードなどにお金を払った結果として表示される。

その検索窓でそのままEnterして表示される
「ジャンル別」検索窓。
こちらの検索ロジックが非常に謎仕様。

現在研究中なり。

(2011/9/10)
googleからsite:www.facebook.comを使って検索すると
同じ検索単語でも大量のページが見つかる。
だが、ユーザが登録したものが大半で
運用されている、企業が必要としている情報としては物足りない。
結局、Facebook内で検索したものを元に分類する方が効率が良かった。

Facebookの検索結果のURLをCrawlerでFile出力。
URLを表示して住所や地域がターゲットであればFile出力、mailアドレスなどを取得する。
作成したCrawlerの使い勝手が悪いので改良が必要だ。

2011年8月30日火曜日

phpが動かない、変。ライブラリが既に読み込まれている?

PHP (linux centos 5)をコマンドラインで入力すると
PHP Warning: Unknown(): Unable to load dynamic library
となる。php.dを使用していてincludeは指定していない。
php.iniを修正すると既に読み込まれていると警告がでる。
yumで全てのphp関連のパッケージをremove。
試しにphpをコマンドラインで実行すると反応がある。which php・・・

結論は実行ファイルが二箇所に存在していた。
/usr/local/bin/php
/usr/bin/php
残っていたphpを削除して、再度phpをインストール。

なおった・・・動かなかったコマンドラインが動くように。

ImageMagick、またお前なのか

結局、ソースから入れるときにjpeg2000削るだけで入るんだ。
linux(centos5)

yumでremiリポジトリ使えば楽かもしれない。