システム・PC

rails5.2.1 対応だん

このサイトのバージョンを 5.2.1にあげました。

最初に作ったときのバージョンは1.3.6。

そこから上げつづけて最新版に追いつきました。ただ上げただけではなく、

  • tubolinksに対応
  • jquery-ujsの成仏 (rails-ujsに移行)
  • もうサポートされていないgemの大量成仏

など対応したところは数しれず。感無量だな。

いい加減 SSL化をしてみた

アドレスバーに鍵のマーク

ま、Let's Encryptですけどね。

VAIOを Windows10にしてみたら動かなかった話

そもそもVAIOは公式にWindows10のアプグレードはちょっとやめとけと言ってるのでアプデートは完全な自己責任なわけですが、右下に「入手できます」というアイコンが表示されたり「Windows10にしたよ。ひゃっほー」などというつぶやきなどを見たりするとアプグレードしたくなるというのが人情というもの。ということでアプグレードしてみました。ちなみにオイラのVAIOはWindows8プレインストールモデルのType E14(SVE14A3AJ)です。

多分簡単にいくだろうと思ってたのですが60%ほど進行したところでブルースクリーン(INTERNAL POWER ERROR)。ここでセットアップが中断し、またWindows8.1に戻るという状態になりました。

いろいろググッてみると、どうもAMDのグラフィックボードが悪さをしているようです。このVAIOには AMD Radeon HD 7600Mと Intelの HD Graphics 4000というグラボが登載されているのですが、このAMDのほうのドライバがどうもよろしくないようです。

最新版とかにしても上手くいかないのでBIOSから(電源を切ったのち、ASSISTボタンでPC起動する)で、discrete graphics adapterを disabledにしたら Windows10にアップグレードできました。

firefoxのメニューを日本語にするメモ

ここに書いてある。

https://support.mozilla.org/ja/questions/1018686

かいつまんで言うと、

  1. 言語パックをインストールして
  2. about:configで設定を開き
  3. "I'll be careful, I promise!".というボタンを押し
  4. intl.locale.matchOStrueにし
  5. general.useragent.localeを jpにして
  6. firefoxをリスタートする

4の手順が書いてないサイトが多いです。これをしないとダメな模様

rubyの class_eval とスコープのメモ

rubyのclass_evalは「ブロックをクラス定義やモジュール定義の中のコードであるように実行します。ブロックの戻り値がメソッドの戻り値になります。」と書いてますが、次の例は以下のような警告がでるようです。

warning: class variable access from toplevel

class A
  def self.a
    p @@a
  end
end

A.class_eval{
  @@a = 1
}

A.a

どうも class_evalのブロック中で @@aはクラスAの@@aを見ているのではなくトップレベルに @@aという変数を定義してしまっているようです。

class A
  def self.a
    p @@a
  end
end

A.class_eval{
  @@a = 1
}

p @@a #=>1

これを期待したように実行するには

class_variable_set

を使うとよいようです。

class A
  def self.a
    p @@a
  end
end

A.class_eval{
  class_variable_set :@@a, 1
}

A.a

あるいは class_evalの中身を文字列で渡してしまえばOK

class A
  def self.a
    p @@a
  end
end

A.class_eval <<-EOS
  @@a = 1
EOS

A.a

 

 

RailsでTimeWithZoneを使う

真面目にプログラムをしはじめるとタイムゾーンは非常に面倒です。まず、rubyのTimeオブジェクトはUNIXのシステムをそのまま使っているようなので時刻として

UTC

または

現在のOSのlocaltime

の2つしかとりえません。なのでユーザ毎に異なるタイムゾーンをもつシステムとかを作るときは非常に面倒です。localtimeは/etc/localtimeや 環境変数TZで決まるので例えば現在台北で今何時よ?というときは

ENV['TZ'] = "Asia/Taipei
Time.now

とかやればいいわけですが、ENVはプロセス全体に影響を及ぼしうるので、あまり推奨されません。こういったことを何とかしてくれるライブラリとしてTZinfoというのがあるのですが、 Railsの4あたりからTimeWithZoneとして標準で入っているようです。 これを使うのが簡単でしょう。

Timeを TimeWithZoneに変換するには、次のようにします。

Time.utc(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00
Time.local(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 06:00:00 AKST -09:00

逆ににアラスカの2000年1月1日の0時を求めたいときは、次のようにします。

Time.zone = 'Alaska'
Time.zone.local(2000,1, 1) #=> Sat, 01 Jan 2000 00:00:00 AKST -09:00

Time.zoneに代入していると、クラス変数に代入しているような気がしますが、これはスレッドセーフに作られているようなのでとりあえず代入してしまって問題ないようです。

Time.zoneを設定すると、ActiveRecord等の時間のフィールドはそのtimezoneになるようなのでControllerのフィルタあたりでユーザ毎にTime.zoneを設定してやれば一発で済みそうです。個人的には内部的に時間を格納するときはすべてUTCにしておいて、表示や検索するときに適宜変換するのが混乱がないと思います。Railsの標準設計もそうなっているでしょう。

現在時刻を持ったTimeWithZoneオブジェクトを作るには

Time.zone.now

とすればOKです。TimeWithZoneオブジェクトはTimeオブジェクトとメソッドで互換があるのでActiveSupportのの便利なメソッドが使えます。

夏時間等あるエリアでは、24時間前などを取得しても1日前になる保証はないので、日付の差分を取得したいときは、yesterdayやbeginning_of_yearなどを活用しましょう。

例えばハワイの今年の正月は以下のようにすればUTCで求まります。

Time.zone.now.beginning_of_year.utc

2015年3月29日の2時の一日前の同時刻との差はどうなるでしょうか?

Time.zone="London"
a=Time.zone.local(2015,3,29,2,0,0) # => Sun, 29 Mar 2015 02:00:00 BST +01:00
b=a.yesterday #=> Sat, 28 Mar 2015 02:00:00 GMT +00:00
(a-b)/3600 => 23.0

ロンドンでは2015年3月29日の2時に1時間時間が進みますので前日の同じ時間との差は23時間ということがわかります。

その他、詳しい使い方は

に例があるのでこちらを参考にしてください。

注記)

ruby-2.2からはlocaltimeでもないUTCでもないオフセットを持った時刻を保持できるようです

Time.parse("2015-02-24 16:32:20 +1200") #=> 2015-02-24 16:32:20 +1200

Rails4.2 + Mongoにしました

Railsを4.2にした序でにMySQLを捨ててMongoにしてみました。

一応動いている模様。

chromebook ASUS C300でdeveloper modeに入るメモ

リカバリーメディアを作成してから

esc + F3 + 電源

同時押し

サーバが逝く

AJPG-2fjq02j2dkc8.jpg

HPのProliant ML115が死にました。

暫く電源を切って床の上におきっぱで先日ルータとして復活したんですが早くも死亡。電源を交換してみたら動いたのでどうも電源が逝ったようです。ここ数日暑かったですからね。CPUの温度はチェックしていたのにまさか電源とか電源にはセンサーないもんなぁ・・・

そういや青森でもHPのサーバが先日逝ったんですよね。あれも電源だったのかな?(調査する時間がないので、そのまま廃棄)

で、電源を交換しようと螺旋を星型ドライバーで外そうとしたんですが電源の螺旋がバカになってるのかドライバーがちょっと小さいのか一ヶ所しか回らないんですよね。しかも別の電源(いわゆる普通にショップで売ってる電源)はネジ穴の位置が合わなくて結局写真のように応急処置。

当面これとエアコン強めで凌ごう


 

RailsのAction Cache

RailsでAction cacheでlayoutの中身だけをchaceする Action cacheはactionを丸々キャッシュするのですが、 フィルターは実行してくれるのでそこに「キャッシュを何時どうやって消すか?」という ロジックを書くことが出来るという利点があります。

また、Layoutの中身だけキャッシュするという機構があるので、レイアウトの外側に ログインしているユーザ名を書いたりする動的なページも作ることができます。

これらどちらも Page cacheでは難しい問題なんですよね。 さて、このAction cacheですが 3.Xまでは標準パッケージに含まれていましたが、 4.xからは標準パッケージに含まれなくなったので、gemで追加してやる必要があります。 やり方は他と同様 Gemfileに次の一行を書いてbundleをしなおすことでOKです。

gem 'actionpack-action_caching'

使い方ですが、controllerにキャッシュしたい actionを以下のように書けばOK

  caches_action :show

これで 初回アクセス時のみshow アクションが実行され、2回目からは 初回アクセス時に renderされたHTMLが帰ってきます。 内容が更新されない場合は、これだけでいいのですが更新もある場合は 以下のように chaceのパラメータに何か更新する情報を渡してやるのがよいでせう。

caches_action :show, cache_path: Proc.new{ params.merge(:t => @blog.updated_at.to_f) } 

@blogが更新される度に updated_atが更新されれば、 cache_pathパラメータが 毎回変わるので古いキャッシュが使用されることなく新しいキャッシュファイルが 作られるというわけです。 ただしこれは tmp/cachesの下にどんどんファイルが溜っていくので、 定期的に日付を見てファイルを削除してやるロジックが必要になります。 Layoutの中身だけCacheしたい場合はさらに layoutパラメータを追加し

  caches_action :show, layout: false, cache_path: Proc.new{
   params.merge(:t => @blog.updated_at.to_f)
  }

とします。但しこの場合

  • Controllerはデフォルトのレイアウトを持っていなければならない
  • render時に layoutのパラメータを指定してはならない

という条件がつきます。Filterの評価が全て終ったあとに、どのlayoutが 使われるのあ分からないとキャッシュできないので、これは致し方のないところで ありましょう。 通常はデフォルトのLayoutは applicationになっていると思いますが、 例えばuser毎にlayoutを変える必要がある場合は

  layout :custom_layout
...
...
  private
  def custom_layout
    @user.laytout
  end

のように layoutにメソッド名をシンボルで指定してやればOKです。 さて、ここまで書いて、いろいろなところで @userやら @blogなどというインスタンス変数が登場してますが、 これらを Actionで取得することはできません。つまり、

  def show
    @blog = Blog.find(params[:id])
  end

とか書くのはNGです。何故なら cacheを使うかどうかは actionよりも先に実行されるので、 その前に@blogなどは取得できてないといけないわけです。 つまり、

  before_action :set_blog, if: [:show]

  private 
  def before_action
    @blog = Blog.find(parmas[:id])
  end

のようなFilterを書いておかないといけないと。 また、Layoutの外側に書く内容も当然filterで全て処理をしておかない いけなくなります。 結果 Action本体よりも Filterばっかり書くハメになり、コードの見通しが悪くなるという 問題があるんですよね。