• Ruby で IPアドレスからロケーション情報を拾ってみる
    Ruby で IPアドレスからロケーション情報を拾ってみる
    No Comments on Ruby で IPアドレスからロケーション情報を拾ってみる

    なんとなくできるかなと思って試したら、Mechanizeで簡単に実装できたので紹介。 以下のソースを test.rbなどとして保存し、コマンドライン引数にIPアドレスを与えて実行すると、ロケーション情報を出力する。実装方法はWebでロケーション情報を提供しているページに対して、POSTでリクエストを投げつけて、Responseを拾うという方式。なので、ループ処理などでやたらめったらリクエストを投げ続けたら、多分文句言われますので、利用はほどほどに。 第一引数: IPアドレス 第二引数: サイトNo (1 or 2 default 1) ソースコード (test.rb) [ruby] require ‘mechanize’ require ‘json’ client = Mechanize.new ipaddr = ARGV[0] siteno = ARGV[1].nil? ? 1 : ARGV[1] pp “siteno=” + siteno.to_s if siteno == 1 url = “http://ip2loc.jerodsanto.net/lookup” ret = client.post(url,{ip: ipaddr}) else url = “http://www.yougetsignal.com/tools/network-location/php/get-network-location-json.php” ret = client.post(url,{remoteAddress:ipaddr,geoSource:”geoip”}) end json_data = JSON.parse(ret.body) json_data.each do |key,value| p key + “–” + value.to_s end [/ruby] 実行結果1 (ip2loc.jerodsanto.netを利用) [bash] $ ruby test.rb 42.83.7.20 1 “siteno=1” “request–42.83.7.20” “ip–42.83.7.20” “country_code2–JP” “country_code3–JPN” “country_name–Japan” “continent_code–AS” “region_name–25” “city_name–Miyazaki” “postal_code–” “latitude–31.911100000000005” “longitude–131.4239” “dma_code–” “area_code–” “timezone–Asia/Tokyo” [/bash] 実行結果2 (www.yougetsignal.comを利用) [bash] $ ruby test.rb 42.83.7.20 2 “siteno=2” “status–Success” “ipAddress–42.83.7.20” “hostname–42-83-7-20.btvm.ne.jp” “baseDomain–ne.jp” “countryCode–Unknown” “countryFlag–<img src=\”/img/flags/.gif\” alt=\”\” />” “countryName–Unknown” “region–Unknown” “city–Unknown” “latitude–Unknown” “longitude–Unknown” “areaCode–Unknown” “postalCode–Unknown” [/bash] 以上

    Read more
  • How to debug Rails app with eclipse on Ubuntu.(steps into,steps over,steps out)
    How to debug Rails app with eclipse on Ubuntu.(steps into,steps over,steps out)
    22 Comments on How to debug Rails app with eclipse on Ubuntu.(steps into,steps over,steps out)

    I introduce you, how to debug Ruby on Rails Application with Eclipse. Hi,I’m japanese. So my english ability is poor. Just be patient. Install Eclipse and JDK Download JDK from Oracle web site. Download Eclipse from Eclipse web site. I install JDK and Eclipse into /usr/java. [bash] $ sudo mkdir /usr/java $ sudo mv ~/Downloads/eclipse-standard-kepler-SR1-linux-gtk.tar.gz /usr/java $ sudo mv ~/Downloads/jdk-7u51-linux-i586.tar.gz /usr/java/ $ cd /usr/java $ sudo tar xvzf jdk-7u51-linux-i586.tar.gz $ sudo tar xvzf eclipse-standard-kepler-SR1-linux-gtk.tar.gz [/bash] Setting environment variables add this settings into ~/.bashrc [bash] JAVA_HOME=/usr/java/jdk1.7.0_45 PATH=$PATH:$JAVA_HOME/bin CLASSPATH=$JAVA_HOME/jre/lib/rt.jar export JAVA_HOME PATH CLASSPATH [/bash] refresh environment variables and check JAVA_HOME. [bash] $ source ~/.bashrc $ echo $JAVA_HOME /usr/java/jdk1.7.0_45 [/bash] Install Aptana plugin On Eclipse Menubar, Help > Install New Software. push Add button and input this url. http://download.aptana.com/studio3/plugin/install and click OK to install plugin. Creating Rails project On Eclipse Menubar, File > New > Other select Rails Project and click Next. input Project Name “testproj” . Click Finish. Start webric server [bash] $ cd ~/workspace/testproj $ rails s Could not find a JavaScript runtime. See https://github.com/sstephenson/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable) [/bash] if “Could not find a JavaScript runtime” is shown ,install nodejs. [bash] $ sudo apt-get install nodejs [/bash] if you use mysql, install libmysqlclient-dev. [bash] $ sudo apt-get install libmysqlclient-dev [/bash] Test Running [bash] $ rails s => Booting WEBrick => Rails 4.0.0 application starting in development on http://0.0.0.0:3000 => Run `rails server -h` for more startup options => Ctrl-C to shutdown server [2014-01-16 16:59:59] INFO WEBrick 1.3.1 [2014-01-16 16:59:59] INFO ruby 2.0.0 (2013-11-22) [i686-linux] [2014-01-16 16:59:59] INFO WEBrick::HTTPServer#start: pid=19531 port=3000 [/bash] Access Rails app with your browser. URL is http://localhost:3000 if the top page is shown,please shutdown rails server with Ctrl + C key. Debugging with Eclipse On Eclipse Menubar, Window > Show View > Servers. Bottom…

    Read more
  • jquery Pluginでシンプルなローディング機能を作ってみた。(jquery.simpleProgress)
    jquery Pluginでシンプルなローディング機能を作ってみた。(jquery.simpleProgress)
    No Comments on jquery Pluginでシンプルなローディング機能を作ってみた。(jquery.simpleProgress)

    Ajaxでそれなりに時間がかかる非同期処理実行中に、ユーザーに処理が進行中ですよと理解してもらうためのちょっとしたプラグインを作りました。良かったら使ってみてください。ページ最下部からダウンロードできます。 動作イメージ プラグイン名 jquery.simpleProgress 必要なファイル jquery.simpleProgress.js ani.png 使い方 HTML 非表示のDIVを作ります。 [html mark=”3,7″] <html> <head> <script type=”text/javascript” src=”jquery.simpleProgress.js”></script> </head> <body> <div id=”spProgress” style=”display:none”></div> </body> </html> [/html] JavaScript 非同期処理を行うイベントの先頭で、プラグインを起動。非同期処理終了時にセレクターを非表示に。 [js mark=”2,7″] function 非同期処理イベント(){ $(“#spProgress”).simpleProgress(); $.ajax({ url: “/xxxx/xxxx”, success: function(json, dataType){ $(“#spProgress”).css(“display”,”none”); }); } [/js] オプション [js] //表示座標指定 $(“#spProgress”).simpleProgress({top:100,left:100}); //画像ファイルの相対位置指定 $(“#spProgress”).simpleProgress({relpath:”../../”}); //表示文字列指定 $(“#spProgress”).simpleProgress({message:”処理実行中”}); //タイマー処理感覚指定 $(“#spProgress”).simpleProgress({interval:500}); [/js] ソース全文 [js] /* usage //html //start progress $(“#spProgress”).simpleProgress(); //stop progress $(“#spProgress”).css(“display”,”none”); //options $(“#spProgress”).simpleProgress({message:”updating”,interval:200,top:100,left:100,relpath:”../../”}); */ (function($){ $.fn.simpleProgress = function(options){ var target = this; var defaults = { interval : 100, message : “Progress”, top: (screen.height /2), left: (screen.width /2) , relpath: “../” }; var settings = $.extend(defaults, options);; var timer = null; var elementFunc = function(elem){ //init var cnt = 0; var init = function (){ $(elem).empty(); $(elem).append(““); $(elem).css(“display”,”block”); $(elem).css(“position”,”absolute”); $(elem).css(“top”,settings.top); $(elem).css(“left”,settings.left); $(elem).css(“z-index”,100); $(elem).append(“” + settings.message + ““); $(elem).children(“.pg-message”).css(“display”,”block”); $(elem).children(“.pg-message”).css(“float”,”left”); $(elem).children(“.pg-message”).css(“padding”,10); timer = setInterval(function(){ var wk = “”; for (var i = 0 ; i < cnt ;i++){ wk += "."; } $(elem).children(".pg-message").text(settings.message + wk); var trf = "transform: rotate(@@@deg);-ms-transform: rotate(@@@deg);-moz-transform: rotate(@@@deg);-webkit-transform: rotate(@@@deg);" trf = trf.replace(/@@@/g,cnt*45); $(elem).children("img").attr("style","float:left;" + trf); cnt++; if ($(elem).css("display") == "none"){ clearInterval(timer); } if (cnt == 8){ cnt = 0; } } ,settings.interval); $(elem).click(function(){ cnt = 0; }); }; init(); }; var ret = $(this).each(function(){ elementFunc(this); }); return ret; } })(jQuery); [/js] ダウンロード jquery.simpleProgress size:2kb

    Read more
  • Rails require_treeを排除し、アセットパイプラインで、コントローラー固有のCSS、JavaScriptを組み込む
    Rails require_treeを排除し、アセットパイプラインで、コントローラー固有のCSS、JavaScriptを組み込む
    No Comments on Rails require_treeを排除し、アセットパイプラインで、コントローラー固有のCSS、JavaScriptを組み込む

    Railsのプロダクションモードでは、デフォルトで app/assetsフォルダ配下にあるCSSとJavaScriptを全てまとめて圧縮し、それぞれ application_xxxxx.css、application_xxxxx.jsファイルを作成する。実行時にはこの圧縮されたCSSとJSだけ読み込むので軽量でいいよ!という仕様のようである。この機能を実現しているのがアセットパイプラインというやつで、アセットパイプラインはマニフェストファイルに記載された内容を見て、どのファイルを対象とするか判断している。 マニフェストファイルとは  app/assets/stylesheets/application.css app/assets/javascripts/application.js の2つである。 そのファイルの中にインクルードすべきファイルが特殊なコメント記法で記載されている。 イメージとしては以下のような感じ。 [js mark=”4″] //= require jquery //= require jquery_ujs //= require turbolinks //= require_tree . [/js] これで、jqueryとjquery_ujsとturbolinksの JavaScriptを全Viewに組み込む。これはまぁ良しとしよう。問題は最後の1行である。このrequire_tree . この命令は、app/assets/javascripts/ フォルダ配下にある全ファイルを対象とするよという意味を持つ。これはいくら何でも気持ち悪い。実際に試したことがないので、正確なところは把握していないが、プロジェクトで利用する自作のJavaScriptファイルを全部まとめちゃうということになるので、変数名がバッティングしたり、function名がバッティングしたり、ページロード時にやたらと多くのfunctionが実行されたりすることになるんじゃないだろうか?? CSSの方についても、同じような不具合が考えられる。自分で記述したCSSですら、別ページで利用するものと内容がバッティングしていないかなどいちいち構っていられないのに、プロジェクトの別のメンバーが書いたCSSともバッティングを避けてCSSを記述するなんて芸当はまず無理である。と、思うんだが、みなさんどうお考えですか? require_tree を生かしたまま実際に開発なんて出来るんでしょうか?? で、どうするのがベストか対策をあれこれ考えました。 パターン1 ・ require_tree は取っ払う ・ コントローラー毎に固有のCSS、JSは Viewの html.erb内でインクルードする ・ CSS、JSの配置場所は assets配下とする パターン2 ・ require_tree は取っ払う ・ コントローラー毎に固有のCSS、JSは Viewの html.erb内でインクルードする ・ CSS、JSの配置場所は public配下とする 開発モード(development) では、どちらの対応でもOKなんですが、プロダクションモードにした際に、パターン1の方法では、CSS、JSがインクルードされないという現象が起こります。仕方がないので publicフォルダに直接配置するパターン2の方法を取りました。が、ここでも問題が発生します。 ・publicフォルダはアセットパイプラインの対象外なので、SCSSでCSSを記述できなくなります。 ・publicフォルダはアセットパイプラインの対象外なので、JavaScriptが圧縮されず、丸裸でクライアントに配布されることになります。 いまいちな対応ですね。でも、うまい解決法がわからなかったので、仕方なくこの方法で運用していました。で、やっぱり気持ち悪いので、気合を入れて、あれこれ調べた結果、ようやく望ましい解決方法が見つかりましたので、紹介してみます。 パターン3 ・ require_tree は取っ払う ・ layoutファイルを調整し、コントローラー名と一致する CSS/JSをインクルードする ・ CSS、JSの配置場所は assets配下とする ・ コントローラー名と一致するCSS/JSには直接、CSSとJSを記載するのではなく、マニフェストファイルとする ・ production.rbを調整し、アセットパイプラインの対象ファイルを拡張する 例)コントローラー名 aaas の場合。 ファイル名: application.js このファイルにはプロジェクト全体で共通利用するJavaScriptを記述する。 [js] //= require jquery //= require jquery_ujs //= require turbolinks [/js] ファイル名: application.css このファイルにはプロジェクト全体で共通利用するCSSを記述する。 [css] /* *= require_self *= require font-awesome *= require_tree ./pepper-grinder *= require ./ui.jqgrid */ [/css] ファイル名: layouts/application.html.erb レイアウトファイルには、application に加えて、コントローラー名に合致する CSS/JSをインクルードする。 [html mark=”6,8″] Log Analyzer true %> true %> true %> true %> [/html] ファイル名: app/assets/javascripts/aaas.js コントローラー名に合致するJSファイルには直接JavaScriptは記載せず、このコントローラーで利用したい汎用的なJSと、このコントローラー固有で利用するJSのファイル名を記載する。 [js] //= require jquery-ui-1.10.3.custom.min //= require grid.locale-ja //= require aaas_main [/js] ファイル名: app/assets/stylesheets/aaas.css コントローラー名に合致するCSSファイルには直接CSSは記載せず、このコントローラーで利用したい汎用的なCSSと、このコントローラー固有で利用するCSSのファイル名を記載する。 [css] /* *= require_self *= require aaas_main */ [/css] ファイル名: config/environments/production.rb アセットパイプライン対象としたいマニュフェストファイルを追記する。今回のケースでは コントローラー aaas に対応する2ファイルを追記したが、必要に応じて、どんどん追記していけばOKでしょう。 [ruby] #コメントアウト #config.serve_static_assets = false config.assets.precompile += %w( aaas.js ) config.assets.precompile += %w( aaas.css ) [/ruby] 動作確認 実際にアセットをコンパイルして、プロダクションモードで動作確認してみてください。 [bash] $ rake assets:precompile RAILS_ENV=production [/bash] [bash] $ rails s -e production [/bash] application-xxxxx.js、application-xxxxx.cssに加えて、 コントローラー名-xxxx.js、コントローラー名-xxxx.css のみがインクルードされる形でページがロードされていたらメデタシメデタシです。

    Read more
  • RubyでWebページからトピック一覧を取得してみよう。 Mechanize/nokogiri
    RubyでWebページからトピック一覧を取得してみよう。 Mechanize/nokogiri
    1 Comment on RubyでWebページからトピック一覧を取得してみよう。 Mechanize/nokogiri

    Webページからトピック一覧を引っこ抜くテクニックです。一般的にはスクレイピングと言われるらしいですが、名前はさておき、適当なページからニューストピック一覧なんかを引っこ抜いてみましょう。 浅田真央残念!フリーで挽回できるかなぁ?? 下準備 Rubyのgem nokogiriとmechanizeをインストールします。 [bash] $ gem install nokogiri $ gem install mechanize [/bash] 取得対象とするページ 今回は朝日新聞さんのサイトからトピックを抜き取ってみます。赤く囲んだところがターゲットです。 HTMLの構造を目視でチェック トピック欄のHTMLの構造をチェックし、どんなCSSセレクターで一覧を引っこ抜くことができるかを確認します。今回の場合はクラスList/ListSideImage/ListHeadlineをもつULタグの下に存在する aタグの情報を抜けば良いというのがわかりました。 Rubyのソース test.rb とか 適当なファイル名で保存してください。 [ruby] require ‘mechanize’ client = Mechanize.new url = “http://www.asahi.com” page = client.get(url) atags = page.search(“ul.List.ListSideImage.ListHeadline a”) p atags.length atags.each do |atag| p atag.inner_text end [/ruby] トピック一覧取得 さて、ソースを実行してみましょう! めでたくトピック一覧の取得に成功しました。簡単ですね。 [bash] $ ruby test.rb 7 “フィギュア3人娘に何が… ことごとくミス、負の連鎖(08:22)” “まさかのSP16位” “真央、震える声 「自分が弱かった」 心技体整わず暗転(08:23)” “鈴木、情感たっぷりに舞う ミスには「悔しい」(08:57)” “トヨタ、6年ぶりにベア実施へ 中小企業に波及するか(07:58)” “USJ、新テーマパーク建設へ 東北・九州など候補か(06:32)” “中国、外国記者に対日宣伝戦 南京案内、国際世論に訴え(09:50)” [/bash]

    Read more
  • Rails scssでドロップダウンメニューを作ろう!
    Rails scssでドロップダウンメニューを作ろう!
    No Comments on Rails scssでドロップダウンメニューを作ろう!

    エンジニアというものは基本デザインに弱い。Bootstrapを使うと、そこそこ簡単に綺麗なデザインを作ることはできますが、やっぱりCSSの基本をマスターしておかなきゃなと思い、CSSをそこそこ真面目に学習中。あちこちのサイトからカットアンドペーストしても良いのですが、基本を理解をするには、1からコツコツとCSSを手書きするほうが堅いので、そんなスタイルで学習しています。 今回はRailsでデフォルトになっている scssを使って、上辺右寄せ+ドロップダウンありのメニューを作ってみましょう。 scssについては詳しくわかっていないのですが、大雑把にいうと、Railsが実行時にCSSにコンパイルしてくれるもので、CSSと違い、構造のネストや変数が使えたり、何かと便利なやつです。 では、まず完成形のメニューをご紹介。 今回は、下図の黄色く囲んだメニュー部分を実装します。 この部分です。 まず、ど基本ですが、ページに対してdivを定義し、上辺にぴったりくっつくようにします。 htmlはこんな感じ。 [html] <div id=”wrapper”> <div id=”top”> <div class=”logo”> <h2> REVERA </h2> <ul id=”nav”> </ul> </div> </div> [/html] では、このHTMLをSCSS(CSS)でぴったり上辺にくっつくようにしてみましょう。 [css] body{ padding: 0; margin: 0; } div#wrapper{ width: 100%; margin: 0px auto; padding: 0px; } div#top{ width:100%; div.logo{ margin: -5px 10px; } } ul#nav{ float:right; } [/css] ポイントは 2点。 1つは、bodyのmarginとpaddingを0として、隙間なくコンテンツがうまるようにします。 もう1つは、ul を float:right しているところぐらいでしょうか。 ではULタグの内部に LIタグを追加し、メニューを構築します。ここでのポイントは、ULタグは子供であるLIタグを下方へ下方へと追加するタグであるということです。この基本の動作をCSSで変更して、右へ右へコンテンツを追加していくようにします。 HTML [html] <ul id=”nav”> <li><a href=”#” class=”active”>Home</a></li> <li><a href=”#”> <em class=”popup”>new</em> SamplePage </a> </li> <li><a href=”#”>Portfolio</a></li> <li><a href=”#”>About</a></li> <li><a href=”#”>Blog</a></li> <li><a href=”#”>ParentPage</a> <ul> <li><a href=”#”>サブメニュー</a></li> <li><a href=”#”>サブメニューxxxxxxxxxxxxxccccccccccc</a></li> <li><a href=”#”>サブメニュー</a></li> </ul> </li> <li><a href=”#”>Contact</a></li> </ul> [/html] SCSS [css] ul#nav{ float:right; li{ list-style: none; display: inline-block; padding-right: 10px; [/css] 次に メニューのアクティブな要素に色を付け、ホバーした際も色を付けるようにしてみます。 SCSS [css] ul#nav{ li{ a{ text-decoration: none; color: #000000; } a.active{ color: $base-color; } a:hover{ color: $base-color; } [/css] $base-color と出てきますが、これが scssの変数機能です。scssの先頭あたりに変数宣言部を作り、scss内部で使う変数を宣言します。ここでは、ベースの色となる変数 $base-colorを宣言します。その変数の値を上記の記述で参照できるということになります。 次に、サブメニューの基本CSS。 ポイントは displayをnoneにしておくこと。サブメニューの文字が折り返してしまうと見栄えが不細工になるので、overflow/whitespaceなどを設定。 [css highlight=”3,13-17″] ul#nav{ li ul { display: none; padding-left: 0px; line-height: 28px; margin-left: -30px; li { font-size: 14px; width: 150px; display: block; border-left: 5px solid $base-color; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; -webkit-text-overflow: ellipsis; /* Safari */ -o-text-overflow: ellipsis; /* Opera */ a { padding: 5px; text-decoration: none; color: #333333; } } } [/css] トップメニューをホバーした時に、サブメニューが存在すれば、表示します。その部分のSCSSです。 ポイントは displayをblockに変え、positionをabsolute、z-indexをそれなりに大きな値いに変更することです。 [css highlight=”5-6,8″] ul#nav{ li:hover{ ul { display: block; position: absolute; background: #ffffff; z-index: 100; } li:hover { background: #57aaef; a:hover { background: #57aaef; color: #ffffff; } } } [/css] おまけです。トップメニューに新着を表すポップアップをつけてみます。 HTML [html] <ul id=”nav”> <li><a href=”#” class=”active”>Home</a></li> <li><a href=”#”> <em class=”popup”>new</em> SamplePage </a> </li> [/html] CSS [css] em.popup { position: absolute; background: #d53c3c; color: #ffffff; margin-left: 50px; margin-top: -15px; padding: 0px 5px; font-size: 12px; } em.popup:after { top: 100%; left: 50%; border: solid transparent; content: ” “; height: 0; width: 0; position: absolute; pointer-events: none; border-color: rgba(213, 60, 60, 0); border-top-color: #d53c3c; border-width: 5px; margin-left: -5px; } [/css] なんとか理解出来ましたか? 以下にメニュー部分のHTML全文、SCSS全文を示しておきます。 HTML全文 [html] <div id=”wrapper”> <div…

    Read more
  • jQuery Plugin作成 初歩を徹底解説!
    jQuery Plugin作成 初歩を徹底解説!
    No Comments on jQuery Plugin作成 初歩を徹底解説!

    とってもシンプルなプラグインを作ります。ただ、どういう仕組みで動いているかというのを事細かに記載しているサイトは少ないので、そのあたりにこだわって、自分なりの理解を丁寧に解説してみます。 プラグインの完成イメージは、こんな感じです。 Labelタグに対して、プラグインのメソッドを呼び出すと、タイマーで指定した間隔でLabelのTextがカウントアップされていきます。実際に呼び出している部分のHTMLとJavaScriptをご紹介します。 HTML [html] aaa [/html] JavaScript [js] $(“#counter1”).simpleTimer(); [/js] これだけです。 では、プラグイン本体のソースを以下に紹介します。 [js] (function($){ $.fn.simpleTimer = function(options){ var target = this; var defaults = { interval : 1000, timerFunc: null }; var settings = $.extend(defaults, options);; var elementFunc = function(elem){ //init var cnt = 0; var init = function (){ setInterval(function(){ $(elem).text(cnt); cnt++; if (settings.timerFunc != null){ settings.timerFunc(elem, cnt, settings.interval); } } ,settings.interval); $(elem).click(function(){ cnt = 0; }); }; init(); }; var ret = $(this).each(function(){ elementFunc(this); }); return ret; } })(jQuery); [/js] 一見難しそうに見えるので、分割して説明します。 プラグイン名の決定と、プラグインを作る上での決まり まず、 [js] (function($){ })(jQuery); [/js] で囲みます。 これで、プラグイン内と外部スクリプトの干渉を抑えます。 もう少し具体的に言うと、(function($)) という関数に 引数 jQueryを渡して、実行しているという意味になります。 つまり、引数$ には jQueryというオブジェクトが飛んできていて、この関数内で $ と書くと (jQuery)と書いているのと同義になります。 [js] $.fn.simpleTimer = function(options){}; [/js] これで jQueryに simpleTimerというメソッドを追加しますという意味になります。??ちょいとわかりにくいですね。上で説明したように $は (jQuery)を意味しており、 $.fn はjQueryのメソッド定義空間となっています(jQueryの仕様でそうなってます)。その定義空間に「simpleTimer」を追加します というのが $.fn.simpleTimer の部分です。で、そのsimpleTimerというのの実態は 引数 optionsをとる functionですよ、と定義していることになります。 例えば、 Labelタグ ID=”aaa”をクリックしたというのを定義する場合は [js] $(“#aaa”).click(function(){xxxxxx;}); [/js] と記載しますよね。 これは $.fn.click というのが $.fnというメソッド定義空間に 存在しているという意味です。 jQueryのソースの中身をチェックしたわけではありませんが、クリックイベントは以下のように定義されているのでしょう。 [js] jQuery.fn.click = function(){}; [/js] 今回は clickの代わりに自分で作るプラグイン名「simpleTimer」というメソッドを定義したという意味になります。これで何ができるようになったかというと、JavaScriptで jQueryでエレメント指定して、ドットでつないで、simpleTimerメソッドを呼び出せるようになったということです。文字で書くと難しいですが、要は以下のような記述が可能になったということです。 [js] $(“#aaa”).simpleTimer(); [/js] ここまで、ご理解いただけましたか? じゃぁ次に行ってみましょう。 プラグインの実行と戻り値(メソッドチェーンを可能にする) [js] (function($){ $.fn.simpleTimer = function(options){ var elementFunc = function(elem,options){ }; var ret = $(this).each(function(){ elementFunc(this); }); return ret; }; })(jQuery); [/js] なんだか小難しいですね。simpleTimerというメソッドを プラグインを使う人が [js] $(“#aaa”).simpleTimer(); [/js] と呼びだすと、何らかの処理を実行して、戻り値を戻しているということになります。そして、 $(this).each(function(){elementFunc(this);}); という部分。 まず、jQueryプラグインにおいて、this には、指定された DOMエレメントが入ってくるという決まりになっています。 つまり、今回の例でいうと thisは ID = “aaa” というDOMエレメントということになります。 $(this)とは、 ID = “aaa” に対応する jQueryオブジェクトということになります。そのオブジェクトに対して、jQueryのeachメソッドを呼び出していると。一般的にはID指定すると1つのDOMエレメントとなりますが、ID = “aaa”のエレメントが複数ある場合、$(this)は、複数のエレメントを指しているということになります。その複数のエレメントに対して、jQueryのeachメソッドを呼んでいるという意味ですね。で、何を実行するかというと、プラグイン本体メソッド elementFuncを呼び出しているということになります。ここで注意していただきたいのが、 ここの thisは ID = “aaa” のDOMエレメント(複数のエレメントになるケースあり) [js] var ret = $(this).each(function(){ [/js] ここのthisは、 ID = “aaa” のDOMエレメント(個別のエレメント!!) [js] elementFunc(this); [/js] という違いがあるということです。 要は、jQuery(セレクター).simpleTimer() で指定されたセレクターに当てはまる DOMエレメント1つ1つに対して、elementFuncを実行するよ!という意味になります。 そして、 [js] var ret = $(this).each() return ret; [/js] jQueryのeachメソッドは 引数に与えられたfunctionを実行します。が、戻り値は、実行するfunctionの内容にかかわらず、jQueryセレクターとなります。つまり今回の場合は戻り値が、 $(this)になるということです。こうすることでどんなメリットがあるかというと、プラグインを利用する人がメソッドチェーンを利用できるということになります。 もっと具体的にいうと、こんな記述が可能になりますよ!ということです。 [js] $(“#aaa”).simpleTimer().click(function(){xxxxx;}); [/js] プラグインの機能(実行する処理) では、プラグインのメインルーチン elementFuncについて、解説しておきます。 [js] var elementFunc = function(elem){ //init var cnt = 0; var init = function (){ setInterval(function(){ $(elem).text(cnt); cnt++; if (settings.timerFunc != null){ settings.timerFunc(elem, cnt, settings.interval); } } ,settings.interval); $(elem).click(function(){ cnt = 0; }); }; init(); }; [/js] これは、何も複雑に考える必要もない、シンプルな JavaScriptの関数です。引数はelemです。 関数の先頭で cntという数値型の変数を宣言し、0で初期化します。 次に 内部関数 init を呼び出します。 init関数は setIntervalでタイマー処理を実行します。タイマーの実行間隔は、 settings.intervalです。実行する中身は、引数で与えられた DOMエレメントのTextに変数 cntをセットするという、至ってシンプルな作りです。そしてTextの値を変更した後に cnt変数をカウントアップします。そして settings.timerFuncという変数がnullでなければ、settings.timerFuncを実行する。最後にもし elemがクリックされたら、cntを0に戻すという処理が記述されています。 プラグインのオプション引数 さて、関数の内部で settingsと出てきましたが、これは何者でしょうか?これは、simpleTimerメソッドを呼び出すときに指定したオプション引数の中身となります。具体的なソースでいうと以下の部分になります。 [js] $.fn.simpleTimer = function(options){ var target = this; var defaults = { interval : 1000, timerFunc: null };…

    Read more
  • 無線LAN搭載PCでKVMを実行し、仮想OSをブリッジ接続するには
    無線LAN搭載PCでKVMを実行し、仮想OSをブリッジ接続するには
    No Comments on 無線LAN搭載PCでKVMを実行し、仮想OSをブリッジ接続するには

    ちょっとマニアックな情報なので、興味のない方は読み飛ばしてください。 最近はノートPCもマルチコアが当たり前で、メモリもふんだんにあるので、ノートPC内に仮想化環境を構築することも容易にできます。マニアックな使い方ではありますが・・、必要な人には必要なわけで・・ そこで、ノートPC内にKVMで仮想環境を構築し、ゲストOSをブリッジ接続して、LAN内のPCと直接通信するような環境を作りたいというのが今回の目標です。 ゲストOSをブリッジ接続するぐらい、VirtualPCやVMWareでも簡単にできるんだからKVMでも簡単にできるだろうと思っていたのですが、落とし穴がありました。LANに接続するインターフェイスが有線NICである場合問題なくブリッジを構成できるのですが、無線LANでLANにつながっている場合は、ブリッジ接続を作ること自体難しいようです。これはKVMに限った話ではなく、VirtualPCやVMWareでも同様です。 何がダメかって言いますと、無線LANは背後にある有線LANネットワークにあるMACアドレスなんかは感知しない模様。なんだか難しい話ですね。私もよくわからなかったので、ネットワークの基礎についてあれこれ調査しました。そこで、間違いもあると思いますが、理解した範囲で、あれこれと書いてみます。基本LAN内の通信はMACアドレスベースで行われるようですね。通信の起点は相手のPCのIPアドレスをベースにするみたいなのですが、arpという機能を使って 目的のIPアドレスのMACアドレスを解決したら、以降の通信はMACアドレスベースに通信すると・・。ちょっと図を交えてご説明します。 今回のネットワーク構成はざっと以下のようになります。 PCTest(IP 192.168.1.99)から、無線LANでつながっているPCKVM(IP 192.168.1.26)へ通信を行う場合 1.arpで 192.168.1.26のMACアドレスを知る。 2.知ったMACアドレスをもとに通信する。 ブリッジとは L2レイヤーでイーサネットフレーム(パケット)を転送するものらしく、無線LANはL2レイヤーレベルでの転送をサポートしていないというのが 無線LANでブリッジ接続ができないということの根本的な理由みたいです。 今回は、この問題を回避するために brctl/parprouted/bcrelayを用います。 無線LAN PCKVMで以下のようなコマンドを実行します。 [diff] $ sudo /sbin/sysctl net.ipv4.ip_forward=1 $ sudo /sbin/brctl addbr br0 $ sudo /usr/sbin/tunctl -t tap0 $ sudo /sbin/brctl addif br0 tap0 $ sudo /sbin/ip addr add 192.168.1.2 dev br0 $ sudo /sbin/ip link set br0 up $ sudo /usr/sbin/parprouted wlan0 br0 $ sudo /usr/sbin/bcrelay -d -i br0 -o wlan0 [/diff] 上記コマンドが、具体的に何をやっているかというと ・まず、PCKVM内で パケットフォワードを有効にする。 ・ブリッジデバイス br0を作る。 ・tunデバイス tap0 を作る。 ・br0とtap0をブリッジする。 ・br0 に IPアドレスを付与し、起動する。 ・parproutedで wlan0に飛んできたarpをbr0にも転送する。 ・bcrelayで、br0(仮想環境)から飛んできたブロードキャストをwlan0に転送する。 後は、KVMの仮想OS側のNIC設定で、下図のようにbr0を指定してやれば、PCTestから、KVMRails1やKVMRails2と通信できるようになります。 と、めでたく接続できたは良いのですが、いったい内部で何が起こっているか、理解できなかったので、ちょっと調べてみました。 PCTest側で arpコマンドを実行した結果は、図中のPCTestの右側にあるものになります。 ここで注目して欲しいのが [bash] 192.168.1.26 00:24:a5:6b:80:2a PCKVM 192.168.1.30 00:24:a5:6b:80:2a PCRails1 192.168.1.33 00:24:a5:6b:80:2a PCRails2 [/bash] PCKVM,PCRails1,PCRails2 の MACアドレスが全部同じものになっているのですね。 このMACアドレスが何者かというと、 PCKVMの無線LAN (wlan0)のMACアドレスなんです。 今度はPCKVM側でarpコマンドを実行した結果は図中のPCKVMの左斜め下にあるものとなります。 ここで注目して欲しいのが [bash] 192.168.1.30 52:54:00:f1:16:be PCRails1 192.168.1.33 52:54:00:1d:bd:a5 PCRails2 [/bash] PCRails1,PCRails2 は別々のMACアドレスが振られており、PCKVMの無線LANのMACアドレスとも異なるものとなっています。 PCTest(192.168.1.99)から PCKVM (192.168.1.26)、KVMRails1 (192.168.1.30)の 80版ポートへwgetした際の動作をなんとなく想像しています。 ■PCTest >>>> PCKVM PCTestは 192.168.1.26のMACアドレスを知るために arpコマンドを発行する。 PCKVMは自分宛のarpコマンドなので、自分のNICつまり、wlan0のMACアドレスを返す。 PCTestはPCKVMから戻ってきたMACアドレスに向け、メッセージを送信する。 PCKVMは自分のIP向けにメッセージが届いたので、返答をする。 ■PCTest >>>> PCRails1 PCTestは 192.168.1.30のMACアドレスを知るために arpコマンドを発行する。 PCKVMは自分宛のarpコマンドではないが、parproutedが機能して、arpコマンドを br0 に転送する。 arpコマンドはブロードキャストなので、仮想PC全てに転送され、192.168.1.30のIPでアドレスを持つPCRails1が私だよー!とMACアドレスを返答する。arpアドレスの返答は PCKVMのparproutedでキャッチされ、PCKVMのarpテーブルに192.168.1.30のMACアドレスを登録し、PCTestにはPCRails1からの返答に含まれるMACアドレスではなく、PCKVMのwlan0のMACアドレスを返す。 PCTestはPCKVMから戻ってきたMACアドレス(PCKVMのwlan0)に向け、メッセージを送信する。 PCKVMはメッセージを受信するが、自分のIP(192.168.1.26)宛のメッセージではないため、自身のarpテーブルをチェックし、仮想PCであるKVMRail1にメッセージを転送する。 KVMRails1は自分のIP向けにメッセージが届いたので、返答をする。 多分こんなかんじで、やりとりが行われているんだと思います。

    Read more
  • ipvsadmとkeepalived を使って Railsサーバーを負荷分散
    ipvsadmとkeepalived を使って Railsサーバーを負荷分散
    No Comments on ipvsadmとkeepalived を使って Railsサーバーを負荷分散

    Railsのアプリケーションを作ったはいいが、過負荷になった時にどうスケールしてよいか分かっていなかったので、検証環境を作って試してみることにした。高価なハードウェアの負荷分散装置なんて買って試すわけにもいかないので、Linuxの負荷分散システム(LVS)を利用して環境を構築してみることにする。用意する機器は以下となる。 ・Railsのアプリケーションが動作するPC 2台 ・負荷分散(LVS)を実装するPC 1台 ・DBサーバー用PC 1台 ・検証用PC1台 ・ブロードバンドルーター1台 実際には仮想化環境なんかも使えるので、三台ぐらいPCがあれば、なんとかなります。動きゃいいという前提ですので、古いPCでも全然OK。ネットワーク構成は以下のような感じ。ごく普通の市販のブロードバンド配下にローカルネットワークが構成されていて、その内の1台がLVS(PCLVS)、残り2台がRailsサーバー(PCRails1、PCRails2)、RailsサーバーのどちらかにDBサーバー機能(PCRails1)も付与する。 ローカルLAN以外の環境に検証用のPCを1台(PCTest)を配置するが、実際には検証用PCもローカルLAN内に配置して、SoftEtherVPNを使ってローカルネットワーク外からアクセスする環境を作ります。 具体的なテストは、検証用PCから ブロードバンドルーターに割り当てられたGlobalIPに向けて HTTPリクエストを送り、ブロードバンドルーターに設定されたNAT情報に基づきリクエストがLAN内のPCLVSへ転送される。PCLVSでは、設定されたアルゴリズム、転送先に基づきリクエストを転送する。最終的にリクエストを処理するRailsサーバー(PCRails1 or PCRails2)は、通常通りリクエストを処理し、PCLVSを介さずに直接検証用クライアントへレスポンスを返す、という流れです。 では、それぞれのPCにセットアップしたOSや設定情報なんかを記載していきたいと思います。 ブロードバンドルーターの設定 ブロードバンドルーターの設定画面にログインし、80番ポートへやってきたリクエストを、PCLVS(192.168.1.100)へ転送するように設定する。既に80番ポートを別の用途で利用している場合などは、1080とか2080とか適当な公開ポートを設定し、そのポートへ来たリクエストを PCLVSの80番に転送するように設定する。設定が出来たら、たいていルーターの再起動が必要なので、再起動してやってください。 Railsサーバーの設定 Railsの実行環境は Ubuntuで実装した。これは別にWindowsでも構いませんが、後でちょっと小細工をしますので、Linux系の方がよろしいかと。 最終的には Passengerなどを使ってApacheにホストさせたRailsアプリにアクセスさせたいが、いきなりそこまで行くにはちょっと敷居が高いので、Apacheを入れて、テストページを表示させて、負荷分散処理の成否を確認したいと思います。Railsサーバーへの負荷分散は後述します。 [bash] $ sudo nano /var/www/health_check.html 中身は以下 Health Check Page Alive Host portage(Apache PCRails1) [/bash] HTMLの中身はApacheにアクセスしたこと、ホスト名がPCRails1であることが、理解できれば何でもOKです。 ついでにRailsのテストページも作っておきます。 (Railsのプロジェクトフォルダが、/home/yourname/workspace/railsapp/ ) [bash] $ sudo nano /home/yourname/workspace/railsapp/public/health_check.html 中身は以下 Health Check Page Alive Host portage(Rails PCRails1) [/bash] HTMLの中身はRailsにアクセスしたこと、ホスト名がPCRails1であることが、理解できれば何でもOKです。 この2つのファイルを PCRails1とPCRails2に作成してください。 で、apacheを再起動します。 [bash] sudo apache2ctl restart [/bash] Linux負荷分散(LVS) の設定 〜 ipvsadm 今回は CentOS 6.5を利用しましたので、その手順を記載します。 ・まずは、ごく普通にMinimalインストールなんかでOSのセットアップを行なってください。私はVirtualBoxのVM環境にCentOSをセットアップしました。HDDは3G、RAM512MBぐらいで十分です。 NIC eth0 を eth0 と eth0:0 に分割し、それぞれに固定IPアドレスを割り当てます。 [diff mark=”3,10″] # nano /etc/sysconfig/network-script/ifcfg-eth0 DEVICE=eth0 HWADDR=08:00:27:55:66:B1 TYPE=Ethernet UUID=ff461a31-7788-4bb7-9489-0b94053dcb78 ONBOOT=yes NM_CONTROLLED=yes BOOTPROTO=static IPADDR=192.168.1.99 NETMASK=255.255.255.0 GATEWAY=192.168.1.1 [/diff] 実際に外部からの仮想ターゲットとなるNIC eth0:0 の設定 [diff mark=”4,9″] # nano /etc/sysconfig/network-script/ifcfg-eth0:0 DEVICE=eth0:0 TYPE=Ethernet ONBOOT=yes NM_CONTROLLED=yes BOOTPROTO=none IPADDR=192.168.1.100 NETMASK=255.255.255.0 GATEWAY=192.168.1.1 [/diff] ネットワークを再起動し、ifconfigで、設定が正しく反映されているかを確認します。 [bash] # /etc/rc.d/init.d/network restart # ifconfig eth0 Link encap:Ethernet HWaddr 08:00:27:55:66:B1 inet addr:192.168.1.99 Bcast:192.168.1.255 Mask:255.255.255.0 inet6 addr: fe80::a00:27ff:fe41:34b1/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:111269 errors:0 dropped:0 overruns:0 frame:0 TX packets:140565 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:25255122 (24.0 MiB) TX bytes:18048699 (17.2 MiB) eth0:0 Link encap:Ethernet HWaddr 08:00:27:41:34:B1 inet addr:192.168.1.100 Bcast:192.168.1.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:341 errors:0 dropped:0 overruns:0 frame:0 TX packets:341 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:24690 (24.1 KiB) TX bytes:24690 (24.1 KiB) [/bash] では、負荷分散機能を提供する ipvsadmとkeepalived などをインストールしましょう。Keepalivedはバージョン違いで動作に不具合が出ることもあるそうですが、CentOS 6.5の環境ではデフォルトのrpmで問題なく動作しました。 [bash] # yum -y install ipvsadm keepalived iproute curl [/bash] インストールが終わったら以下のコマンドで負荷分散設定を確認します。 当然、何もセットされていません。 [bash] # ipvsadm -Ln IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn [/bash] 仮想ターゲットNIC(192.168.1.100) にアルゴリズム rr(ラウンドロビン)を設定し、負荷分散をONにします。 [bash] # ipvsadm -A -t 192.168.1.100:80 -s rr [/bash] 実際のサービスを提供するリアルサーバー(Railsサーバー、PCRails1とPCRails2)のIPアドレスを DRで登録します。 [bash] # ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.22:80 -g # ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.25:80 -g [/bash] 以下のコマンドで、設定が有効になっているか確認してください。 [bash] # ipvsadm -Ln IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn…

    Read more
  • Deviseのユーザー登録時に、独自の処理を追加する。
    Deviseのユーザー登録時に、独自の処理を追加する。
    No Comments on Deviseのユーザー登録時に、独自の処理を追加する。

    Railsの認証処理にdeviseを用いている場合、新規ユーザーの登録は自動的に行われます。デフォルトではUsersテーブルに設定したemailとpasswordが保存されます。これはこれでOKなのですが、アプリケーションの仕様上、ユーザーを新規に追加したタイミングで別の処理を実行したいケースがあると思います。今回はそんなケースに対応する方法を説明します。 deviseのソースをチェックすると RegistrationsControllerの createメソッドで、ユーザーの登録処理が行われているようです。ですので、今回はこのメソッドをオーバーライドして、追加の処理も実行します。 DeviseのRegistrationsControllerを継承するクラスを定義する。 ファイルの場所は app/registrations_controller.rb とします。 [ruby mark=”15-16,29-31″] class RegistrationsController < Devise::RegistrationsController # POST /resource def create build_resource(sign_up_params) if resource.save yield resource if block_given? if resource.active_for_authentication? set_flash_message :notice, :signed_up if is_flashing_format? sign_up(resource_name, resource) respond_with resource, :location => after_sign_up_path_for(resource) #独自の処理を追加 createXXXX(resource) else set_flash_message :notice, :”signed_up_but_#{resource.inactive_message}” if is_flashing_format? expire_data_after_sign_in! respond_with resource, :location => after_inactive_sign_up_path_for(resource) end else clean_up_passwords resource respond_with resource end end def createXXXX(resource) ここに追加の処理を記述 end end [/ruby] routes.rbを調整し、新規ユーザー登録時に、上記のメソッドが呼ばれるようにする。 [diff] – devise_for :users + devise_for :users, controllers: {registrations: “registrations”} [/diff] 以上です。

    Read more

Back to Top