[Rails]Hash#from_xml

Rails使いがRailsをもっと好きになるHashメソッド集


from_xmlに感動したから紹介したいだけのお話


Hash.from_xml


RailsのHash拡張メソッド
XMLをHashにマッピングしてくれます


サンプルコード(rails cで実行します)
お天気Webサービス(Livedoor Weather Web Service / LWWS)のXMLをHashにマッピングします


require 'net/http'
response = Net::HTTP.start('weather.livedoor.com') do |http|
http.get('/forecast/webservice/rest/v1?city=113&day=tomorrow')
end
weather = Hash.from_xml(response.body)
weather['lwws']['location']
=> {"area"=>"九州", "pref"=>"福岡県", "city"=>"久留米"}

ちなみにActiveModel::Serializers::Xmlのfrom_xmlはこれを使っています


Hash#except, #extract, #slice


from_xmlと組み合わせると容易にXMLデータの解析ができてしまう


Hash.except


Hashから指定したキーを除外します
非破壊的メソッドのexcept, 破壊的メソッドのexcept!が存在します


data = {a: 1, b: 2, c: 3}
data.except(:a)
=> {:b => 2, :c => 3}

Railsだと外部指定できないパラメータは
attr_protected :id, :created_at, :status_code等で保護する場面が多いですが、
外部指定をしたいけど、あるコントローラーからは外部指定できないようにしたい等の場合に以下のようにします


User.update_attributes(params[:user].except(:status_code)

これで外部からstatus_codeが送信されてきても保護することができます


Hash#extract!


必要な項目だけ抜き出すときに使います
こちらは実装の関係上破壊的なメソッドのみになります


x = { a: 1, b: 2, c: 3 }
=> {:a => 1, :b => 2, :c => 3}
x.extract!(:a, :b)
=> {:a => 1, :b=> 2}
p x
=> {:c => 3}

破壊的メソッドのため、extract!した残りはそのフィールドが取り除かれたデータ(except実行後)になります


from_xmlと組み合わせて以下のように使ってます


data = Hash.from_xml(xml_data)["namespace"].extract!(:foo, :bar)

Hash#with_indifferent_access


シンボルでもストリングでもどっちでもアクセスできるようにします


x = { a: 1, b: 2, c: 3 }
x["a"]
=> nil
x.with_indifferent_access["a"]
=> 1
x.with_indifferent_access[:a]
=> 1

これはまぁ"a".to_symしたのを渡してあげればいいんだけどね


File.atomic_write


Hash拡張の紹介のみの予定だったけど、Tempfileを使ってmvしている人を見かけたので、これも紹介


生成途中のデータを他のプロセス等に読み込まれたりしないようにするための仕組み
内部的にはTempfileを使っていて、Tempfileへの書き込みが完了した段階で、実ファイルを作成します


実装は以下の部分
https://github.com/rails/rails/blob/dd6c3676af3fa6019c53a59f62c4fd14966be728/activesupport/lib/active_support/core_ext/file/atomic.rb#L15
バッチ処理をRailsで書いているような場合はこれを使っておくと色々安全


File.atomic_write("my_batch_result.txt") do |file|
MyModel.find_each do |my_model|
file.puts my_model.to_a.join(",")
end
end
スポンサーサイト

[Rails]memoizeでクラスメソッドのメモ化のdeprecatedの対処方法

[Rails3]Memoizeでクラスメソッドをメモ化する方法


class MyModel < ActiveRecord::Base
after_save :unmemoize

def unmemoize
self.class.unmemoize
end

class << self
extend ActiveSupport::Memoizable
def my_method
# too slow
end
memoize :my_method

def unmemoize
unmemoize_all
end
end

end

MyModelがsaveされると、unmemoize_allが実行されるようになっているため、
ある程度安全に使えるはず。。。


Rails3.1以降はdeprecatedなので以下のようにする


class MyModel < ActiveRecord::Base
after_save :unmemoize

def unmemoize
self.class.unmemoize
end

class << self
def my_method
@@my_method ||= get_my_method_value
end

def get_my_method_value
# too slow
end

def unmemoize
@@my_method = nil
end
end
end
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。