Rails勉強会@関西6

投稿者 nanki 2007-01-22 05:51:00 GMT

土曜日は、Rails勉強会に行ってきました。

今回は、初心者レッスンの担当。

朝8時に起きて準備するはずが、前日5時くらいまで(というか、三時間前まで)いろいろやっていたので、目覚まし時計の思いも届かず、2時間寝坊。 ひげを剃るのも会場で。 11時到着に合わせて計算していたので、なんとか12時前にはたどりつけたけど、あせったなぁ。

発表は、なんとか終了。 途中で場内を回ってみると、思いの外、進み具合がバラバラだったので、最後の部分は演習時間を延長してカット。

なにから解放されたのか、昼御飯は食べる気も起こらなかったのに懇親会まではずっとお腹が鳴りっぱなしなのでした。

終わってから気がついたけど、初期のRails勉強会のように、教科書になるような本を写経とかでもいいんじゃないか、と思えてきた。
毎回、目的のテーマにたどり着くまでに、ActiveRecord, scaffold の道を進まねばならないので、なんとも大変。 三回目なので、シリーズ化はまだ止められそうだし。

「RailsでXML-DBにチャレンジ」by モバイル通信兵さん

おもしろそう。 DB2要求されるのが、ちょっとハードル高め。 使えそうな場所を探してみようっと。

「Rubyist SNS の実装について」by かずひこさん

最近コミットできてなくて申し訳ないです。 会場で、updateしていつものように一人で友達作って・・・
この作業がいつも寂しい。

「rails tips」by 氏久さん

<%=h %>は、エディタのショートカットで出せるように設定していて、<%= %> にするには、hを削らないといけない、という安全スイッチがあるので、少人数での開発の場合はまあいいかな。 jitor は楽しそう。

「やさしいRailsの育て方(仮題)」by 西和則さん

DBモデリング?のお話。 火星エステ理論なる判別法で、本質的な項目を洗い出せ!

火星の鈴木さん(だっけ?)で何故か火星年代記を思い出してしまった。

懇親会は、内装がゴージャスなお店。

二次会では、非カラオケチームに合流しようとして連絡をしたら、途中で携帯の電池が切れてしまって、結局合流できなかった・・・。 今朝、僕の目を覚まそうとして、一時間に渡ってブルブルしてたはずだから、当然なのかも。

なので、はぐれ組三人で、駅前のサンマルクカフェで、お話しました。


Operaのバグ?

投稿者 nanki 2007-01-17 14:39:00 GMT

最近、Javascript付いている。

Ajaxのレスポンス中に<script>タグを埋め込んでいたら、Operaで動いてない。
prototype 1.4.0のevalScriptsがOperaでは動かないらしい。

  evalScripts: function() {
    return this.extractScripts().map(eval);
  },

  evalScripts: function() {
    return this.extractScripts().map(function(a){return eval(a)});
  },

と変更することで直るのだとか。

1.5.0を使おう。

参考

Bug in Opera? Problems calling Prototype’s evalScripts()


W3C Range

投稿者 nanki 2007-01-15 21:35:00 GMT

W3C Range in Internet Explorer
選択したテキストをDOM上で操作するAPIが例によってIEでは変なので、これを使うと解決してくれそう。

参考

DOM Range


ActiveRecord - フォーマット

投稿者 nanki 2006-12-27 21:09:00 GMT

小分けにしないとサーバが止まる・・・

model_formatter
  • 特定のカラムを、フォーマット付きでアクセス。
  • formatted_weight で、フォーマット済みのweightにアクセス。
  • フォーマット済み属性の名前は、:formatted_attr, :prefixで変更。
  • class Widget < ActiveRecord::Base
    # FormatInteger という名前のFormatterでフォーマットを指定
    # :boolean, :currency, :decimal, :integer, :percent, :phone が定義済み
    # :as には、Formatterのインスタンスも指定できる
    format_column :weight, :as => :integer

# Procを使って format_column :weight,

<span class="symbol">:formatted_attr</span> =&gt; <span class="symbol">:formatted_weight</span>,
<span class="symbol">:options</span> =&gt; {<span class="symbol">:delimiter</span> =&gt; <span class="string"><span class="delimiter">'</span><span class="content">,</span><span class="delimiter">'</span></span>},
<span class="symbol">:from</span> =&gt; <span class="constant">Proc</span>.new{|attribute, options| ... },
<span class="symbol">:to</span>   =&gt; <span class="constant">Proc</span>.new{|str, options| ... }

# ブロックによる定義も format_column :weight do

<span class="keyword">def</span> <span class="function">from</span>(attribute, options)
  <span class="comment"># ...</span>
<span class="keyword">end</span>

<span class="keyword">def</span> <span class="function">to</span>(str, options)
  <span class="comment"># ...</span>
<span class="keyword">end</span>

end end

w = Widget.new(:weight => 12345) w.formattedweight # => 12,345 # 書き込みもできる! w.formattedweight = 54,321 w.weight # => 54321

auto_convert_fields
  • attribute=を定義。
  • class MyModel < ActiveRecord::Base
    # name=, :text= の前に、TextHelper#striptags をはさむ。
    autoconvert :name, :text, :with => :strip_tags

# 同じ auto_convert :name, :text do |value|

strip_tags(value)

end end


:yの悲劇

投稿者 nanki 2006-12-21 18:51:00 GMT

GPS情報を格納するのに、

class Entry < ActiveRecord::Base
  has_one :location
end
  
class Location < ActiveRecord::Base
  # 実際にはGeometry型で格納するので、アクセサを定義
  def x
    point.x
  end
  def y
    point.y
  end
end

こんなモデルを作ると・・・

$ script/console
>> entry = Entry.find(:first)
>> entry.location.x
=> 135.0
>> entry.location.y
=> 35.0
>> entry.location.send :x
=> 135.0
>> entry.location.send :y
ArgumentError: wrong number of arguments (0 for 1)
        from (irb):35:in `y'
        from (irb):35:in `send'
        from (irb):35

xは大丈夫なのにyはだめ?

yの正体は、pのようにyamlを吐くprivate method、Kernel#y in yaml.rb。 何故だ?

entry.location の中身は、実はAssociationProxyで、ActiveRecordのソースを見るとこんな風になっている。

# lib/active_record/associations/association_proxy.rb
module ActiveRecord
  module Associations
    class AssociationProxy #:nodoc:
      attr_reader :reflection
      alias_method :proxy_respond_to?, :respond_to?
      alias_method :proxy_extend, :extend
      instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?|^proxy_respond_to\?|^proxy_extend|^send)/ }

entry.location.send :x すると、AssocationProxy#xが無いのでtargetにsendされるが、entry.location.send :y だと、Kernel#yが見つかってしまうのか・・・

当然entry.location.target.send :y だとうまくいく。

Ruby1.9 だとsendの仕様が違ってうまくいきそう。


svn:externals のリビジョン固定

投稿者 nanki 2006-12-03 11:01:00 GMT

Railsで $ script/plugin install -x したプラグインのリビジョンを固定するには、

$ svn propedit svn:externals vendor/plugins/

として、

plugin_name  -r150  svn://example.com/path

とやればよいらしい。

参考

subversion - 外部定義


CGAL - Computational Geometry Algorithms Library

投稿者 nanki 2006-11-24 05:48:00 GMT

CGAL

すごいの一言。幾何計算に関するアルゴリズムライブラリ。

あこがれの、あんなアルゴリズム、こんなアルゴリズムがいっぱい。

Pythonバインディングしかないか・・・

demo


今日のPostScript

投稿者 nanki 2006-10-12 16:57:00 GMT

スタックマシン?なので、テトリスやってるみたい。

% a の文字コード
(a) 0 get

% 0x81
16#81

% 数字から文字列へ
100 20 string cvs

% SJISかどうかの判定(の一部)
char 0 get dup 16#81 ge exch 16#9f le and

% pathのbounding boxの高さ
path pathbbox exch pop exch sub exch pop

Rails Plugin - View系2

投稿者 nanki 2006-10-05 06:55:00 GMT
MenuEngine
  • DHTMLのメニューを作る。
  • # in config/environment.rb
    module ApplicationHelper
    include MenuHelper
    end

# in app/helpers/applicationhelper.rb module ApplicationHelper include MenuHelper end

*
module MenuEngine
  # UserEngineと連携
  # trueで許可されないcontroller/actionへのメニューが表示されなくなる
  config :accesscontrol, false
  # エフェクトの設定。element はメニューを指す。
  config :onshow, "new Effect.Appear(element);"
  config :onhide, "new Effect.Fade(element);"
end
*
module ApplicationHelper
  def my_menu

item0 = <span class="constant">MenuItem</span>.new(<span class="symbol">:text</span> =&gt;  <span class="string"><span class="delimiter">&quot;</span><span class="content">Users</span><span class="delimiter">&quot;</span></span>, <span class="symbol">:controller</span> =&gt; <span class="string"><span class="delimiter">&quot;</span><span class="content">user</span><span class="delimiter">&quot;</span></span>)
item1 = <span class="constant">MenuItem</span>.new(<span class="symbol">:text</span> =&gt;   <span class="string"><span class="delimiter">&quot;</span><span class="content">List</span><span class="delimiter">&quot;</span></span>, <span class="symbol">:controller</span> =&gt; <span class="string"><span class="delimiter">&quot;</span><span class="content">user</span><span class="delimiter">&quot;</span></span>, <span class="symbol">:action</span>=&gt;<span class="string"><span class="delimiter">&quot;</span><span class="content">list</span><span class="delimiter">&quot;</span></span>)
item2 = <span class="constant">MenuItem</span>.new(<span class="symbol">:text</span> =&gt; <span class="string"><span class="delimiter">&quot;</span><span class="content">Images</span><span class="delimiter">&quot;</span></span>, <span class="symbol">:controller</span> =&gt; <span class="string"><span class="delimiter">&quot;</span><span class="content">image</span><span class="delimiter">&quot;</span></span>)

item0.items &lt;&lt; item1
[item0, item2]

end end

*
<%= enginestylesheet "menuengine" %>
<%= enginejavascript "menuengine" %>
...
<%= menu :menu => my_menu, :layout => :vertical %>
* YAMLで設定する方法もある。


Rails Plugin - ActiveRecord拡張系2

投稿者 nanki 2006-08-29 16:24:00 GMT
acts_as_modified

# restore person.restore_attributes :only => :age person.age # 100

# clear person.clearoriginalattributes :only => :age

# dbと比較 person.modified?(:reload) # true

acts_as_bookmarkable

post.add_bookmark(Bookmark.new)

だけ。 * 構成はacts_as_commentableとほぼ同じ。

acts_as_commentable
acts_as_sluggable

urlfor :controller => "articles", :action => 'show', :id => @article # => "/articles/show/76-omg-my-cat-is-so-cute-lol" * toparam というメソッドを上書きしてるらしい。

acts_as_sequenced

class Customer < ActiveRecord::Base actsassequenced

<span class="comment"># 連番</span>
<span class="symbol">:column</span> =&gt; <span class="symbol">:customer_number</span>,
<span class="comment"># 有効範囲</span>
<span class="symbol">:scope</span> =&gt; <span class="symbol">:account</span>

end

class Job < ActiveRecord::Base actsassequenced :column => :job_number, :scope => :account endこれで、Account毎に連番が。 * プラグインの形では提供されてないので、コードをlib/以下にコピペして、environment.rbでrequireしてね。 * コードからは、削除して追加すると、過去の管理番号と重複する番号が割り当てられるように見える。(これはうれしくない) * acts_as_paranoid(削除フラグで削除したかの用に見せるプラグイン)と併用できるようになっていて、併用すればこの問題は起こらなさそう。

acts_as_most_popular

# すると、頻度の高い順に3個とってこられる。 Person.mostpopularnames # => ["Jajamaru", "Piccolo", "Porori"] * nameが複数形になるってどういうことよ。

acts_as_network

alice, bob = User.find([1,2])

# bobはaliceの友達です alice.connections << bob

# bobはaliceの2です alice.connections.pushwithattributes(bob, :role => 2) alice.connections.find(bob.id).role # => 2

# bobはaliceの友達ですか? alice.connections.include?(bob) # => true

# aliceは誰の友達ですか? alice.connections.all_in

acts_as_rateable

def self.down

drop_table <span class="symbol">:ratings</span>

end end *

class YourModel
  actsasrateable
end

# 5点をつける m.rate(5) m.rating = 5

# 5点 m.rating # => 5

# 最初に見つかった3点のもの YourModel.findbyrating(3) # 3点以上のもの全部 YourModel.findallbyrating(3..-1) # 1点または3-5点のもの全部 YourModel.findallbyrating([1,3..5])

acts_as_ratable

# currentuserが5点をつけました m.rateas(5, :by => current_user)

# currentuserによって付けられた点数 m.ratingby(current_user)

m.average_rating # => 平均点 m.raters # => 採点者 * 同じユーザが同じものに採点すると上書きされる。

acts_as_popular
acts_as_searchable
acts_as_rast_indexed
acts_as_ordered
acts_as_taggable
acts_as_versioned
acts_as_paranoid
acts_as_bitfield
acts_as_deque
acts_as_attachment
better_nested_set
acts_as_threaded
acts_as_ldapable
acts_as_habtm_list
acts_as_shellable
acts_as_enumerated