Named Results

メソッドの引数、複数宣言するときは型をまとめられる。 あと戻り値の型宣言も複数できる。複数返ることがわかりやすくていいね。 そして戻り値の宣言時に名前をつけられる。名前をつけた場合は、そのメソッドの同名ローカル変数がそのままreturnで戻る。

package main

import "fmt"

func hoge(x, y int) (sum, diff int) {
  sum = x + y
  diff = x - y
  return
}

func main() {
  fmt.Println(hoge(10, 6))
}
% go run hoge.go
16 4

最初メソッド大文字始まりちょっと違和感あったけど、メソッドの大文字はパッケージ外に対してpublic, 小文字はprivateみたいな扱いらしい。 まだスコープがよくわかっていない。

[rspec] raise_error matcher

rspecのraise_error matcherは引数に例外クラスを渡すことで検証ができる。

expect { subject }.to raise_error(FooError)
Failure/Error: expect { subject }.to raise_error(FooError)
  expected FooError, got #<BarError: BarError> with backtrace:

ただしrspec3からto_notで引数渡すのはdeprecatedになっている。 https://www.relishapp.com/rspec/rspec-expectations/docs/changelog

expect { subject }.to_not raise_error(FooError)
DEPRECATION: `expect { }.not_to raise_error(SpecificErrorClass)` is deprecated. Use `expect { }.not_to raise_error` (with no args) instead.

AR#find_eachのlimit/offset

ARのfind_each/find_in_batchesはlimit/offsetをオプションで指定できる。

User.find_each(start: 1000, batch_size: 100) do |user|
  user.touch
end

batch_sizeは単純にrelationのlimitにわたされるだけ。 startは>=でprimary keyに対してセットされる。

relation.where(table[primary_key].gteq(start)).to_a

deviseでさくっと認証作る

有名なやつ。 結論、ちょう簡単にできる。

https://github.com/plataformatec/devise ドキュメントが親切。

Install

Gemfileに追記。

gem 'devise'
bundle install
rails g devise:install

初期設定

devise:installしたら設定項目が表示されるので迷うことはないのだが。

  • config/environments/development.rb
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
  • config/environments/production.rb developmentと同じ物を、本番のドメインで。

  • config/routes.rb

root :to => "top#index"

これは認証後の画面なので好きなとこで。 - app/views/layouts/application.html.erb

<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>

モデルを作る

rails g devise User

モデルは好きなかんじで。まあだいたいUserだろうけど。

これでもう、localhost:3000いくとできてる!!!! アホか!!!!

メール確認する場合

Confirmableというオプションを使う。 - migration file(たぶんdb/migrate/20121215012513_devise_create_users.rbみたいなの) カラムとINDEXを追加(コメントアウトするだけ)

      ## Confirmable
      t.string   :confirmation_token
      t.datetime :confirmed_at
      t.datetime :confirmation_sent_at
      t.string   :unconfirmed_email # Only if using reconfirmable
...

      add_index :users, :confirmation_token,   :unique => true
  • Userモデル deviseメソッドに:confirmable を追加(コメント書いてあるし迷わないとおもわれる)

あとメールの設定必要。

Viewのカスタム

rails g devise:views

ってやると、各種画面のViewが生成されるので、好きにいじることができる。

devise:viewsのhaml

でも生成されるのはerb...しかも昔はhamlで生成ができたらしいが今はできない。。 そこでhtml2hamlを使う。 https://github.com/plataformatec/devise/wiki/How-To:-Create-Haml-and-Slim-Views

基本的には、

gem install haml hpricot ruby_parser slim haml2slim
for i in `find app/views/devise -name '*.erb'` ; do html2haml -e $i ${i%erb}haml ; rm $i ; done

でいけるのだが、html2hamlがhaml', '>= 3.2.0.beta.1'なので注意。

Homesickべんり!!

はてなブログに変えてみた。

Homesickとは

dotfilesを管理するgemだよ

それgithubで

dotfiles自体はgitで管理すりゃいいんだけど、シンボリックリンクやらなんやらめんどくて、スクリプト書いたりするところを大体やってくれる

とりあえずインストール

gem install homesick

リポジトリの管理

homesick clone git@github.com:adorechic/dotfiles.git

コミットとかするならgit@で。 aliasで、

homesick clone adorechic/dotfiles

もいける。 管理下にあるやつらは

% homesick list
    dotfiles  git@github.com:adorechic/dotfiles.git

で見れる。 .homesick配下にいろいろ作られる。 基本的に、リポジトリ/home の下を自分のホームディレクトリと同期させる。 同期させるには

homesick symlink dotfiles

そこにあるファイルを、ホームディレクトリに対してシンボリックリンク貼ってくれる。 ファイル自体の変更はそのまま反映されるし、ファイルを追加したりしたらまたsymlink実行すれば差分を反映してくれる。

homesick push dotfiles

pushできる!! 嘘。できない。なんでこう書いたんだろう。

accepts_nested_attributes_for でupdateされないパターン

ちょっとハマったのでメモ。

class User < ActiveRecord::Base
  attr_accessible :name, :profile_attributes
  has_one :profile
  accepts_nested_attributes_for :profile
end

class Profile < ActiveRecord::Base
  attr_accessible :name, :user_id
  belongs_to :user
end

こんなモデルがあったとき、Userを更新したりするとProfileも一緒に更新してくれる。
が、更新しないときもある。

Userのみロードしてたとき

user = User.where(:id => 123).first
user.name = 'hoge'
user.save! #=> Profileのsaveは走らない

UserからProfileを参照した後

user = User.find(123)
name = user.profile.name
user.name = name
user.save! #=> Profileのsaveが走る

ProfileからUserをとって更新したとき

profile = Profile.find_by_user_id(123)
user = profile.user
user.name = 'aaa'
user.save! #=> Profileのsaveは走らない

つまり、accepts_nested_attributes_for宣言しているモデルが対象のモデルへの参照を握っている場合は一緒にsaveが走るっぽくて、逆の参照持ってても走らないっぽい。まあsaveの主体がどっちかってのを考えれば自然か。
たぶんacriverecordのattribute_will_changeに追加されるとこのコードをもっと読めばはっきりしそう。
うっかりすると、accepts_nested_attributes_for対象のvalidationに引っかかったりするトラップが待っている。