珍しく休日にPCを起動した。
何年ぶりだろう。
自宅PCはWindows7とUbuntuのデュアルブートにしているのだけど、Ubuntuを11.04から11.10にしたら無線が遅い。
ネットには接続されるし、IPもふられてるんだけど通信速度が異常に出ない。
なんじゃこりゃ。
このフォーラムWireless Internet Connection so slow after upgrade to
11.10のとおりにコマンド打ったら、解決した。
sudo rmmod iwlagn
sudo modprobe iwlagn 11n_disable=1
注意)以下の作業はやる前に、バックアップを取ってからやってください。
Ubuntu(OS関係あるのか不明)で、Android(IS04)のSDカードをマウントして、ファイル削除したけどSDカードの容量が増えない。゚ヽ(゚´Д`)ノ゚
よく見ると
.Trash-1000
とかってゴミ箱的なフォルダがあって、そこに削除したファイルが移動してた。
んでそこのフォルダ内のファイル全部選択して削除したけど、ファイルが一向に消えないヽ( ̄д ̄;)ノ
ここ見て、ubuntuのゴミ箱を全て空にしたら消えた(´・ω・`)
http://www.google.com/support/forum/p/android/thread?tid=60747a992c0a473b&hl=en
そして再び携帯に戻ったら、破損したSDカードとか出るようになってフォーマットしますかの一択となった。
色々やってたから、なんかまずいの消したのか?
それともまさか上の操作がNGなんだろうか?
めんどいので調査しないけど。
っていう投げっぱなしのどうしようもない記事。
初期値を指定して配列を作りたいならこうできる。
1
2
| Array.new(3, nil) # => [nil, nil, nil]
Array.new(2, "foo") # => ["foo", "foo"]
|
んで、指定した値で要素数Nの配列を要素数Mにしたい場合。
1
| 変数.fill(指定した値,変数.size..(N-1))
|
で出来る。
例)とりあえずMを5とする場合。
1
2
3
4
5
6
7
8
| ary = [1]
ary.fill(nil,ary.size..4) #=> [1, nil, nil, nil, nil]
ary = [1,2]
ary.fill("empty",a.size..4) #=> [1, 2, "empty", "empty", "empty"]
ary = [1,2,3,4,5]
ary.fill(nil,a.size..4) # => [1, 2, 3, 4, 5]
|
ちなみにfillは!ついてないけど破壊的メソッドなので、レシーバの値変わってしまうのがちょっと注意。
1
2
3
| ary = [1]
ary.fill(nil,ary.size..4) #=> [1, nil, nil, nil, nil]
p ary #=> [1, nil, nil, nil, nil]
|
リアルタイムなchatを作りたい。
そんな欲求誰にでもあるものです。
時間のない主婦の方にも手軽にパパっとチャットシステムを作る方法を紹介しようと思います。
材料は
rails
pusher
作る料理は
チャットシステム(現在の参加者表示機能付き)
の二つです。
変なテンションな書き方はここまで。
今日の記事は全面的にここを参考にさせていだきました。
Yuno
pusherはWebSocketsを利用したAPIです。
Leader in realtime technologies| Pusher
わかりやすい図はっときます。
![f:id:gogo_sakura:20120124124957p:image f:id:gogo _sakura:20120124124957p:image](http://cdn-ak.f.st-hatena.com/images/fotolife/g/gogo_sakura/20120124/20120124124957.png)
例えばブラウザがpostリクエスト投げると、それを受け取ったサーバからpusherにそのデータを加工してパス。
するとブラウザにpushしてくれるというイメージ。
pusher利用にはユーザ登録で得られるAPI Credentialsが必要です。
まずはpusherのサイトでユーザ登録して、
app _id
key
secret
をゲットしてください。
今日の記事は実際に作ったものからコピペで書いていますが。
view部分はhamlで書いてるので、見ずらくてすいません。
erbメインの方は脳内で変換かけてください。
とりあえずGemfileに記述
bundle install後、config/initializers内にpusher.rb作成
1
2
3
| Pusher.app_id = ユーザ登録でゲットしたapp_id
Pusher.key = ユーザ登録でゲットしたkey
Pusher.secret = ユーザ登録でゲットしたsecret
|
config/route.rbにauthアクションへのルーティング追加
1
2
3
| resources :chats , :only => [:index , :create , :destroy] do
post :auth , :on => :collection
end
|
現在の参加者を取得するためには、pusherのPresence
Channelsを使用しなければなりません。
Presence
Channelsを使用するためには、認証を受けること・channel名のprefixにpresence-つけないといけません。
view
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
| = javascript_include_tag "http://js.pusher.com/1.11/pusher.min.js"
:javascript
$(function(){
Pusher.channel_auth_endpoint = '/chats/auth';
var pusher = new Pusher("#{ユーザ登録でゲットしたkey }");
var channel = pusher.subscribe("presence-chat");
channel.bind("chatevent", function(html) {
$("#chat_body").val('');
$("ul").prepend(html);
});
channel.bind('pusher:subscription_succeeded', function(members){
members.each(add_member);
});
channel.bind('pusher:member_added', function(member){
add_member(member);
})
channel.bind('pusher:member_removed', function(member){
remove_member(member);
})
});
function add_member(member) {
var container = $("<span>", {
"class": "member",
id: "presence_" + member.id
});
$('.members').append(container.html(member.info.name + " "))
}
function remove_member(member) {
$('#presence_' + member.id).remove();
}
= render "form"
%div
現在の参加者
%span.members
%ul#chat_list
= render partial: "list", locals: { :chats => @chats }
|
フォームとリストの部分テンプレートは割愛。
認証は
1
| Pusher.channel_auth_endpoint = '/chats/auth';
|
で指定したエンドポイントにコールバックされます。
controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| class ChatsController < ApplicationController
protect_from_forgery :except => :auth
def create
@new_post = Chat.new(params[:chat])
@new_post.user = @current_user
if @new_post.save
Pusher["presence-chat"].trigger!(
"chatevent",
render_to_string(
file: "chats/_list.html.haml",
layout: false,
locals: { :chats => Array.wrap(@new_post) }
)
)
end
render 'index'
end
def auth
if current_user
auth = Pusher["presence-chat"].authenticate(params[:socket_id],{
:user_id => @current_user.id,
:user_info => {
:name => @current_user.name
}
}
)
render :json => auth
else
render :text => "Not authorized", :status => '403'
end
end
end
|
endpointで設定したauthアクションでは、コールバックされた際に渡されるsocket _idを引数authenticateを実行しています。
ちなみに自分はこの認証ではまりました。
1
| protect_from_forgery :except => :auth
|
でコールバックで呼び出された際に、CSRFを無効にしてあげる必要があったんですねぇ。
以上で多分動くはずです。
railsのobserverでユーザ情報とプロフィール情報を監視していて、
例えば1つのフォームにユーザ情報とプロフィール情報の編集項目があった場合。
after saveでフックした際には
after saveは2回。それぞれのモデルで呼ばれる。
んでその二つ呼ばれたafter _saveが同じ処理で呼ばれたのかってわかんないと思っていた。
先日入れたuserstampの処理がどうなっているのだろうかと見たら、
ActionControllerのbefore _filterでThread.currentにuserのIDを押し込んでいた。
実際のソースは以下のとおり。
1
2
3
4
5
6
7
8
| def stamper=(object)
object_stamper = if object.is_a?(ActiveRecord::Base)
object.send("#{object.class.primary_key}".to_sym)
else
object
end
Thread.current["#{self.to_s.downcase}_#{self.object_id}_stamper"] = object_stamper
end
|
キーにはobject id(デフォルトではUserのobject id)使ってる。
controller側で毎回Thread.currentに操作者のidを保存して、それをmodelで取り出している。
んでobserverで同一の処理で呼ばれたのか判定する方法は。
同じようにThread.currentに設定してるキーと値を任意の値にすれば良さそう。
ActionControllerのbefore filterでキーはuserstampと同じようにobject idを使って、適当にkey _とかprefixつけてみる。
んで値はユニークな値を設定する。
1
2
3
| def set_key
Thread.current["key_#{User.object_id}"] = Time.now.strftime("%Y%m%d%H%M%S") #ミリ秒まで含めた方がいいと思われ。
end
|
observerでは
1
2
3
4
5
6
7
8
9
10
| observe :user,:user_profile
def after_save(model)
case model
when User
p Thread.current["key_#{User.object_id}"]
when UserProfile
p Thread.current["key_#{User.object_id}"]
end
end
|
で同じ値が取得できた場合には同一の操作から呼ばれたものと考えられる。
この方法は副作用とかどうなんだろう。
そしてもっとスマートな方法はあるのだろうか・・・
去年スマフォサイト作りました。
railsつかってます。
jQuery Mobileも使ってます。
mobileinitイベント内で
1
| $.mobile.ajaxEnabled = false;
|
でAjaxオフにしてます。
でもたまにページロード完了後に、
勝手にローディング画像が出てきて、全然自分が見たいページとは違うページに飛ばされることがあります。
調べた結果Android端末の沢山とiPhone4以外(というか3GS?)で起きる現状でした。
上記現象が起こる操作は
Aページ- >[Bページへのリンクをクリック]- >Bページ- >[端末のブラウザバック]- >Aページ- >[Cページをクリック]- >Cページ読み込み完了後にBページに飛ばされる。
対策としては
1
| $.mobile.pushStateEnabled = false;
|
でpushStateオフにしたら直りましたっていうお話。
またまたRubyネタ。
Rails抜きでNヶ月前の月から今日までの月を求める必要があったので考えてみました。
すっごい遠回りして考えてるかもしれません。
rubyの配列はインデックスにマイナスを指定することができます。
その場合、参照する先は後ろから数えた値となります。
今日のコードはirbだけで試せます。
REPL最高。
1
2
3
| a = [1,2,3]
a[0] # => 1
a[-1] # => 3
|
とりあえずNは3として、今月を含めて3ヶ月前を求めるには
1
2
| month = [1,2,3,4,5,6,7,8,9,10,11,12]
month[Time.now.month-3]
|
1月ならば11月が帰ってきます。
2月ならば12月。3月なら1月となります。
インデックスは0始まりなのでそのあたりを考慮しないとあかんですね。
以上です。と書こうとしたけど、3ヶ月前から今日までの月でしたね。
1
| 3.times{ |i| p month[Time.now.month-i-1] }
|
先ほど述べたようにインデックスが0始まりなので-1してます。
配列で欲しいなら
1
| 3.times.map{ |i| p month[Time.now.month-i-1] }
|
かなぁ?
わかりやすく書けるだろうか。
railsのviewでログの出力を出し分けする以下のメソッドがあります。
user profile log
use favorite log
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| def genarate_link_path(log_type,log)
case log_type
when :warm
"http://" + config[:host] + "/info/" + "warm"
when :error
"http://" + config[:host] + "/info/" + "error"
end
end
def user_profile_log(log)
disp_path = genarate_link_path(:warn,log)
case log.operation_type
when "insert"
change_value = log.inspect + "ログを新規登録しました。"
when "update"
change_value = log.inspect + "ログを更新しました。"
else
"解析に失敗しました"
end
return link_to( change_value , disp_path )
end
def use_favorite_log(log)
disp_path = genarate_link_path(:warn,log)
case log.operation_type
when "insert"
change_value = log.name + "をお気に入りに追加しました。"
when "update"
change_value = log.name + "を更新しました。"
else
"解析に失敗しました"
end
return link_to( change_value , disp_path )
end
|
DRYじゃないですよね。
それぞれのメソッドでは
disp path = genarate link path(:warn,log)
return link to( change value , disp path )
が二つのメソッドでかぶっております。
これをブロックで書き直します。
まずはブロックを引数に取るメソッド
1
2
3
4
5
| def output(log,log_type,&block)
disp_path = genarate_link_path(log_type,log)
change_value = block_given? ? block.call : "ブロックもらえてないんで表示できません"
link_to( change_value , disp_path )
end
|
&blockでブロックを引数に取れます。
受け取ったブロックはblock.callで実行できます。
ブロックがもらえたかどうかはblock _given?で判定できます。
んでブロックを引数にouput呼び出す方も修正。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| def user_profile_log(log)
output(log,:warm) do
case log.operation_type
when "insert"
change_value = log.inspect + "ログを新規登録しました。"
when "update"
change_value = log.inspect + "ログを更新しました。"
else
"解析に失敗しました"
end
end
end
def use_favorite_log(log)
output(log,:error) do
case log.operation_type
when "insert"
change_value = log.name + "をお気に入りに追加しました。"
when "update"
change_value = log.name + "を更新しました。"
else
"解析に失敗しました"
end
end
end
|
っていう。
説明できたか以前にソース汚いという。
あと思ったより再利用性の高いコードが書けなかったという。
ちなみに&blockしなくてもブロックは受け取れてその場合は
1
2
3
4
5
| def output(log,log_type)
disp_path = genarate_link_path(log_type,log)
change_value = yield
link_to( change_value , disp_path )
end
|
となります。
ブロックが渡されることが確実に保証されているならばこっちの方がいいのかな