<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-630587874177549254</id><updated>2011-11-28T07:46:13.869+08:00</updated><category term='flash'/><category term='subquery'/><category term='escapeHTML'/><category term='big5'/><category term='back'/><category term='decode'/><category term='ar_mailer'/><category term='do_mysql'/><category term='bug'/><category term='redo'/><category term='progressbar'/><category term='watch'/><category term='self'/><category term='a'/><category term='regexp'/><category term='require'/><category term='api'/><category term='include'/><category term='cookie'/><category term='association'/><category term='ip'/><category term='multipart'/><category term='module'/><category term='passenger'/><category term='has_many'/><category term='attr_writer'/><category term='copy'/><category term='message'/><category term='gem'/><category term='hostname'/><category term='not'/><category term='extension'/><category term='rails'/><category term='lightbox'/><category term='rss'/><category term='Gem dependencies'/><category term='resource'/><category term='unescape'/><category term='multi'/><category term='like'/><category term='redirect'/><category term='swfobject'/><category term='marshal'/><category term='Graceful Degradation'/><category term='uninstall'/><category term='compress'/><category term='='/><category term='tab'/><category term='system'/><category term='i18n'/><category term='checkbox'/><category term='fn'/><category term='type'/><category term='host'/><category term='wbr'/><category term='webrat'/><category term='absolute'/><category term='dir'/><category term='in'/><category term='through'/><category term='effect'/><category term='order'/><category term='padding'/><category term='trim'/><category term='format'/><category term='respond_to'/><category term='Block in views'/><category term='method_missing'/><category term='page'/><category term='select_layout'/><category term='rails set mode'/><category term='class_eval'/><category term='rest'/><category term='will_paginate'/><category term='ui'/><category term='render js'/><category term='controller'/><category term='substring'/><category term='z-index'/><category term='update_attributes'/><category term='ie6'/><category term='fields_for'/><category term='content_tag'/><category term='habtm'/><category term='asset_host'/><category term='rail'/><category term='ubuntu'/><category term='overwrite'/><category term='step'/><category term='distinct'/><category term='facebox'/><category term='error'/><category term='json'/><category term='svn'/><category term='google'/><category term='ruby'/><category term='this'/><category term='activerecord'/><category term='delete_all'/><category term='polymorphic_path'/><category term='concat'/><category term='iframe'/><category term='debugger'/><category term='mailer'/><category term='option'/><category term='event'/><category term='auth'/><category term='merb'/><category term='detect'/><category term='command'/><category term='redirect_to'/><category term='length'/><category term='attr_accessor'/><category term='bundle-fu'/><category term='glob'/><category term='routes'/><category term='track'/><category term='class_name'/><category term='response'/><category term='source_type'/><category term='plugin'/><category term='railscast'/><category term='iconv'/><category term='mod_rails'/><category term='textarea'/><category term='image'/><category term='code'/><category term='rails2.2'/><category term='update'/><category term='group_by'/><category term='memoizable'/><category term='anchor'/><category term='alias'/><category term='polymphic'/><category term='speed'/><category term='localtime'/><category term='basic'/><category term='cycle'/><category term='thickbox'/><category term='header'/><category term='parse'/><category term='has_image'/><category term='squish'/><category term='validate'/><category term='migration'/><category term='version'/><category term='post'/><category term='keypress'/><category term='join'/><category term='thread'/><category term='早鳥'/><category term='ie'/><category term='create'/><category term='tip'/><category term='jquery'/><category term='recipe'/><category term='etag'/><category term='clone'/><category term='cgi'/><category term='sql'/><category term='div'/><category term='index'/><category term='rescue'/><category term='rjs'/><category term='update_attribute'/><category term='timeout'/><category term='jrails'/><category term='yield'/><category term='before'/><category term='observe_field'/><category term='replace_html'/><category term='path'/><category term='relative'/><category term='web'/><category term='singleton'/><category term='define_method'/><category term='conditions'/><category term='corner'/><category term='separate'/><category term='date'/><category term='load_file'/><category term='require_dependency'/><category term='firefox'/><category term='test'/><category term='form_for'/><category term='submit'/><category term='to_time'/><category term='tls'/><category term='retry'/><category term='css'/><category term='js'/><category term='render'/><category term='Net'/><category term='dynamic content'/><category term='window'/><category term='utf8'/><category term='function'/><category term='entries'/><category term='lightted'/><category term='href'/><category term='referer'/><category term='form_tag'/><category term='link'/><category term='each_with_object'/><category term='has_one'/><category term='performance'/><category term='group'/><category term='vim'/><category term='cron'/><category term='get'/><category term='reverse'/><category term='xml'/><category term='alias_method_chain'/><category term='select'/><category term='src'/><category term='mysql'/><category term='attribute'/><category term='local'/><category term='from'/><category term='scope'/><category term='link_to anchor name'/><category term='save'/><category term='alter'/><category term='script defer'/><category term='strain'/><category term='extend'/><category term='alias_method'/><category term='clone.timeout'/><category term='scan'/><category term='filter'/><category term='blockui'/><category term='th'/><category term='yaml'/><category term='split'/><category term='image_tag'/><category term='hidden'/><category term='construction'/><category term='last_modified'/><category term='substr'/><category term='destroy'/><category term='escape'/><category term='with_options'/><category term='html'/><category term='update_all'/><category term='ActiveResource'/><category term='session'/><category term='ssl'/><category term='atom'/><category term='memcached'/><category term='swf'/><category term='partition'/><category term='selector'/><category term='foregin_key'/><category term='text_field'/><category term='encode'/><category term='verify'/><category term='serialize'/><category term='capture'/><category term='widget'/><category term='request'/><category term='uri'/><category term='exists?'/><category term='delegate'/><category term='modal'/><category term='enter'/><category term='data object'/><category term='url'/><category term='content_for'/><category term='attachment_fu'/><category term='bgiframe'/><category term='javascript'/><category term='send_file'/><category term='cache'/><category term='connection'/><category term='strip'/><category term='prefix'/><category term='map'/><category term='load'/><category term='module_eval'/><category term='benchmark'/><category term='gzip'/><category term='中文化'/><category term='export'/><category term='http'/><category term='form'/><category term='string'/><category term='each'/><category term='console'/><category term='find'/><category term='delete'/><category term='helper'/><category term='polymorphic'/><category term='liquid'/><category term='class'/><category term='range'/><category term='domain'/><category term='layout'/><category term='valid'/><category term='gcin'/><category term='csv'/><category term='count'/><category term='file'/><category term='default'/><category term='database'/><category term='deploy'/><category term='linux'/><category term='apache'/><category term='setTimeout'/><category term='feed'/><category term='dispatching'/><category term='empty'/><category term='ajax'/><category term='logger'/><category term='views'/><category term='random'/><category term='reset'/><category term='execute'/><category term='name'/><category term='destroy_all'/><category term='simple'/><category term='website'/><category term='route'/><category term='http status'/><category term='blog'/><category term='time'/><category term='source'/><category term='named_scope'/><category term='with_scope'/><category term='themeroller'/><category term='inject'/><category term='upload'/><category term='history'/><category term='composed_of'/><category term='search'/><category term='paging_enumerator'/><category term='parser'/><category term='model'/><category term='instance_variable_get'/><category term='rel'/><category term='password'/><category term='db'/><category term='keycode'/><category term='binding'/><title type='text'>ubuntu, ror, jQuery, css, website memo</title><subtitle type='html'>太嫩, 沒啥心得, 用來紀錄每天學的</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default?start-index=101&amp;max-results=100'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>621</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-780846421004086618</id><published>2011-04-25T11:09:00.001+08:00</published><updated>2011-04-25T11:10:46.775+08:00</updated><title type='text'>RuntimeError: !!! Missing the mysql2 gem</title><content type='html'>Rails 3 install mysql2 gem fail&lt;br /&gt;&lt;br /&gt;production:&lt;br /&gt;  adapter: mysql2      &lt;br /&gt;  encoding: utf8&lt;br /&gt;  reconnect: false&lt;br /&gt;  database: blog&lt;br /&gt;  pool: 5&lt;br /&gt;  username: root&lt;br /&gt;  password: &lt;br /&gt;  socket: /var/run/mysqld/mysqld.sock&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Change the adapter, and find your socket file&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-780846421004086618?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/780846421004086618/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=780846421004086618' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/780846421004086618'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/780846421004086618'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2011/04/runtimeerror-missing-mysql2-gem.html' title='RuntimeError: !!! Missing the mysql2 gem'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-7252902680635608916</id><published>2011-04-20T15:45:00.017+08:00</published><updated>2011-04-21T00:35:20.853+08:00</updated><title type='text'>rails + rubber + github + amazon ec2 free tier step by step</title><content type='html'>Reference:&lt;br /&gt;Rubber wiki : https://github.com/wr0ngway/rubber/wiki/&lt;div&gt;&lt;br /&gt;&lt;div&gt;How to deploy a Rails app to EC2 in less than an hour using Rubber&lt;/div&gt;&lt;div&gt;http://ginzametrics.com/deploy-rails-app-to-ec2-with-rubber.html&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span"&gt;Step 1:  Amazon Registration&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;http://www.amazon.com/gp/aws/registration/registration-form.html&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;reference: http://www.inside.com.tw/2010/11/02/amazon-aws-1&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span"&gt;Step 2: Check&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;You could check your amazon account status here, your billing&lt;br /&gt;https://aws-portal.amazon.com/gp/aws/developer/account/index.html&lt;br /&gt;&lt;br /&gt;Amazon service console&lt;br /&gt;https://console.aws.amazon.com/ec2/home&lt;br /&gt;&lt;br /&gt;Amazon Security Credentials, you could get your keys here&lt;br /&gt;https://aws-portal.amazon.com/gp/aws/developer/account/index.html?ie=UTF8&amp;amp;action=access-key&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span"&gt;Step 3: Get your key pair&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;https://console.aws.amazon.com/ec2/home?region=us-east-1#s=KeyPairs&lt;br /&gt;You will download a private key here like  :   keyname.pem&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span"&gt;Step 4: Install rubber in your project&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;sudo gem install rubber&lt;br /&gt;rails generate vulcanize complete_passenger_mysql&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span"&gt;Step 5: Generate your public key in ~/.ec2&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;Change keyname.pem to keyname&lt;br /&gt;chmod 400 keyname&lt;br /&gt;ssh-keygen -y -f keyname &amp;gt; exviewkey.pub&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span"&gt;Step 6: Edit your config/rubber/rubber.yml&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;1)&lt;br /&gt;cloud_providers → aws → access_key&lt;br /&gt;cloud_providers → aws → secret_access_key&lt;br /&gt;cloud_providers → aws → account&lt;br /&gt;cloud_providers → aws → keyname&lt;br /&gt;cloud_providers → aws → keyname_file_location&lt;br /&gt;&lt;br /&gt;access_key: ABCDEFGHIJKLMNOPQRST&lt;br /&gt;secret_access_key: ABCDEFGHIJKLMNOPQRSTUVWXY1234567890+zabc&lt;br /&gt;account: 123456789012 #account original would show like 1234-5678-9012&lt;br /&gt;key_name: exviewkey #the name of private key you download&lt;br /&gt;key_file: "#{Dir[(File.expand_path('~') rescue '/root') + '/.ec2/*' + cloud_providers.aws.key_name].first}"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2) Change the server timezone, and domain&lt;br /&gt;timezone: US/Pacific&lt;br /&gt;domain: webiste.com&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3) Change your image type&lt;br /&gt;image_type: t1.micro&lt;br /&gt;image_id: 'ami-3e02f257'&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It is my image type, you could find more in&lt;br /&gt;&lt;ul&gt;&lt;li&gt;http://uec-images.ubuntu.com/releases/10.10/release/&lt;/li&gt;&lt;li&gt;http://uec-images.ubuntu.com/releases/10.04/release/&lt;/li&gt;&lt;li&gt;http://aws.amazon.com/amis/Linux?browse=1&lt;/li&gt;&lt;li&gt;http://cloud.ubuntu.com/ami/&lt;/li&gt;&lt;/ul&gt;&lt;i&gt;Reference:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: normal; "&gt;&lt;i&gt;http://groups.google.com/group/rubber-ec2/browse_thread/thread/dfff07e016a28896&lt;/i&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/i&gt;&lt;br /&gt;4) Change the app_user, app_name&lt;br /&gt;app_user: www-data&lt;br /&gt;app_name: websitename&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span"&gt;Step 7: Edit deploy.rb&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;ssh_options[:forward_agent] = true  &lt;span class="Apple-style-span"&gt;#optional : for deploy from github&lt;/span&gt;&lt;br /&gt;set :repository, "git@github.com:yourname/projectname.git"&lt;br /&gt;set :scm, "git"&lt;br /&gt;set :deploy_via, :remote_cache&lt;br /&gt;set :branch, 'master'&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Reference:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: normal; "&gt;&lt;i&gt;http://groups.google.com/group/rubber-ec2/browse_thread/thread/bdf75bebb38eec2a/23fac77708767390?lnk=gst&amp;amp;q=github#23fac77708767390&lt;/i&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Step 8: set ssh-agent (optional : for deploy from github)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;eval `ssh-agent -s`&lt;br /&gt;ssh-add&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;i&gt;Reference:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: normal; "&gt;&lt;i&gt;http://groups.google.com/group/rubber-ec2/browse_thread/thread/73e50e32264768f6/ee1b4f497d621797?lnk=gst&amp;amp;q=github#ee1b4f497d621797&lt;/i&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: normal; "&gt;&lt;i&gt;http://www.josephj.com/article/understand-ssh-key/&lt;/i&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span"&gt;Step 9: deploy (Finally Gook Luck :p )&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;cap rubber:create_staging&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-7252902680635608916?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/7252902680635608916/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=7252902680635608916' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/7252902680635608916'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/7252902680635608916'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2011/04/rails-rubber-github-amazon-free-tier.html' title='rails + rubber + github + amazon ec2 free tier step by step'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-416360671559302426</id><published>2010-12-13T12:32:00.002+08:00</published><updated>2010-12-13T12:34:43.525+08:00</updated><title type='text'>fb comment</title><content type='html'>http://developers.facebook.com/docs/reference/plugins/comments&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Unique ID 填了反而不行用 是怎樣 = =&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-416360671559302426?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/416360671559302426/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=416360671559302426' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/416360671559302426'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/416360671559302426'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/12/fb-comment.html' title='fb comment'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-5456093035746143257</id><published>2010-06-30T17:38:00.002+08:00</published><updated>2010-06-30T17:44:24.669+08:00</updated><title type='text'>rails 設定多個 smtp account 寄信</title><content type='html'>&lt;a href="http://broadcast.oreilly.com/2009/03/using-multiple-smtp-accounts-w.html"&gt;Using multiple SMTP accounts with Rails &amp; ActionMailer&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;可利用此技巧, 達到多SMTP 寄信的目的&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;#action_mailer.yml&lt;br /&gt;production:&lt;br /&gt;  website1:&lt;br /&gt;    domain: "gary@superfriends.com"&lt;br /&gt;    user_name: gary&lt;br /&gt;    password: superduper&lt;br /&gt;    address: smtp.gmail.com&lt;br /&gt;    port: 587&lt;br /&gt;    authentication: :plain&lt;br /&gt;&lt;br /&gt;  website2:&lt;br /&gt;    domain: mysupercooldomain.com&lt;br /&gt;    user_name: ABCDEF&lt;br /&gt;    password: blahblah&lt;br /&gt;    address: mail.authsmtp.com&lt;br /&gt;    port: 25&lt;br /&gt;    authentication: :plain&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#app/models/mailer1.rb&lt;br /&gt;class Website1 &lt; ActionMailer::Base&lt;br /&gt;  def load_settings&lt;br /&gt;    options = YAML.load_file("#{RAILS_ROOT}/config/action_mailer.yml")[RAILS_ENV]["website1"]&lt;br /&gt;    @@smtp_settings = {&lt;br /&gt;      :address =&gt; options["address"],&lt;br /&gt;      :port =&gt; options["port"],&lt;br /&gt;      :domain =&gt; options["domain"],&lt;br /&gt;      :authentication =&gt; options["authentication"],&lt;br /&gt;      :user_name =&gt; options["user_name"],&lt;br /&gt;      :password =&gt; options["password"]&lt;br /&gt;    }&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def welcome_email(recipient, sent_at = Time.now)&lt;br /&gt;    load_settings&lt;br /&gt;    @subject = 'Thank you for visiting website 1'&lt;br /&gt;    @recipients = RAILS_ENV == "production" ? recipient : "cavneb@gmail.com"&lt;br /&gt;    @from = 'gary@superfriends.com'&lt;br /&gt;    @sent_on = sent_at&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-5456093035746143257?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/5456093035746143257/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=5456093035746143257' title='21 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/5456093035746143257'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/5456093035746143257'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/06/rails-smtp-account.html' title='rails 設定多個 smtp account 寄信'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>21</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-632842257861589294</id><published>2010-06-24T17:37:00.007+08:00</published><updated>2011-05-15T14:04:10.009+08:00</updated><title type='text'>haproxy nginx passenger munin</title><content type='html'>step1:  nginx need stub_status_module&lt;br /&gt;compile with   [--with-http_stub_status_module]&lt;br /&gt;&lt;br /&gt;step2: install munin&lt;br /&gt;sudo apt-get install munin munin-node&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: ruby"&gt; &lt;br /&gt;#/etc/munin/munin.conf&lt;br /&gt;#This will tell munin to connect to munin-node at 127.0.0.1 on the same machine.&lt;br /&gt;[foo.net]&lt;br /&gt;    address 127.0.0.1&lt;br /&gt;    use_node_name yes&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#Edit the file /etc/munin/munin-node.conf and change # Which port to bind to set&lt;br /&gt;host 127.0.0.1&lt;br /&gt;&lt;br /&gt;#Make sure that this is present in the file&lt;br /&gt;&lt;br /&gt;allow ^127\.0\.0\.1$&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;http://github.com/barttenbrinke/munin-plugins-rails&lt;br /&gt;http://www.alfajango.com/blog/how-to-monitor-your-railspassenger-app-with-munin/&lt;br /&gt;http://github.com/jnstq/munin-nginx-ubuntu&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: ruby"&gt; &lt;br /&gt;#haproxy setting&lt;br /&gt;reqisetbe       ^Host:\ munin.foo.net        foomunin&lt;br /&gt;&lt;br /&gt;#nginx config&lt;br /&gt;server {&lt;br /&gt;   listen 6166; &lt;br /&gt;   server_name munin.foo.net;&lt;br /&gt;   root /home/foo/deploy/shared/directory/munin;   &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#/etc/munin/plugin-conf.d/munin-node&lt;br /&gt;[foo_*]&lt;br /&gt;env.log_file '/home/foo/app/production.log'&lt;br /&gt;user foo&lt;br /&gt;command /opt/ruby-enterprise-1.8.7-2010.02/bin/ruby %c&lt;br /&gt;env.graph_category Foo&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-632842257861589294?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/632842257861589294/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=632842257861589294' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/632842257861589294'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/632842257861589294'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/06/haproxy-nginx-passenger-munin.html' title='haproxy nginx passenger munin'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-4647557951376218898</id><published>2010-06-22T17:09:00.004+08:00</published><updated>2010-06-22T17:24:45.279+08:00</updated><title type='text'>rails ip 辨識國家</title><content type='html'>&lt;a href="http://mea-docta-ignorantia.blogspot.com/2009/03/how-to-know-user-location-with-rails.html"&gt;how-to-know-user-location-with-rails&lt;/a&gt;&lt;br /&gt;&lt;a href="http://github.com/cjheath/geoip"&gt;github geoip&lt;/a&gt;&lt;br /&gt;&lt;a href="http://blog.hungrymachine.com/2007/10/31/super-fast-ip-to-lat-lng-in-rails-part-2/"&gt;Super fast IP to lat/lng in Rails&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;下載點 http://geolite.maxmind.com/download/geoip/database/&lt;br /&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;IP_COUNTRY = GeoIP.new("#{Rails.root}/public/GeoIP.dat")&lt;br /&gt;&lt;br /&gt;IP_COUNTRY.country(request.remote_ip)&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-4647557951376218898?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/4647557951376218898/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=4647557951376218898' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4647557951376218898'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4647557951376218898'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/06/rails-ip.html' title='rails ip 辨識國家'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-7077729712797030076</id><published>2010-06-22T14:49:00.003+08:00</published><updated>2010-06-22T14:54:28.155+08:00</updated><title type='text'>haproxy rails ip</title><content type='html'>&lt;a href="http://frozentree.javaeye.com/blog/297393"&gt;haproxy不能正確記錄客戶端的IP&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.javaeye.com/topic/251180"&gt;關於 rails 的扔remote_ip&lt;/a&gt;&lt;br /&gt;http://kkito.cn/index.php/blog/getArticle/102/rails%E4%B8%AD%E5%BA%94%E6%B3%A8%E6%84%8F%E5%8F%AF%E8%83%BD%E5%AE%A2%E6%88%B7%E7%AB%AFip%E5%9C%B0%E5%9D%80%E6%98%AF%E4%BC%AA%E8%A3%85%E7%9A%84&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-7077729712797030076?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/7077729712797030076/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=7077729712797030076' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/7077729712797030076'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/7077729712797030076'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/06/haproxy-rails-ip.html' title='haproxy rails ip'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-6194489494240551360</id><published>2010-06-21T15:35:00.006+08:00</published><updated>2010-06-23T18:05:05.737+08:00</updated><title type='text'>capistrano path rake fail</title><content type='html'>http://blog.zerobearing.com/2009/04/27/capistrano-rake-command-not-found/&lt;br /&gt;http://stackoverflow.com/questions/588934/using-ruby-enterprise-edition-gems-are-not-installed-where-i-would-expect&lt;br /&gt;http://forum.slicehost.com/comments.php?DiscussionID=3657&lt;br /&gt;http://stackoverflow.com/questions/257616/sudo-changes-path-why&lt;br /&gt;http://groups.google.com/group/emm-ruby/browse_thread/thread/d0c685bbd096823a#msg_effa7d6ad42c541c&lt;br /&gt;http://www.f15ijp.com/2009/11/30/sudo-no-tty-present-and-no-askpass-program-specified/&lt;br /&gt;&lt;br /&gt;/etc/ssh/sshd_config:&lt;br /&gt;&lt;br /&gt;PermitUserEnvironment yes&lt;br /&gt;/etc/init.d/sshd restart&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;~/.ssh/environment&lt;br /&gt;PATH=/opt/ruby-enterprise-1.8.7-2010.02/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;http://formatinternet.wordpress.com/2009/07/06/sudo-rake-command-not-found/&lt;br /&gt;~/.bashrc&lt;br /&gt;alias sudo='sudo env PATH=$PATH'&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;sudo ln -s `which rake` /usr/local/bin/&lt;br /&gt;&lt;br /&gt;#sudo: no tty present and no askpass program specified     error&lt;br /&gt;the /etc/sudoers file.&lt;br /&gt;#commend sudo visudo&lt;br /&gt;Defaults visiblepw&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-6194489494240551360?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/6194489494240551360/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=6194489494240551360' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/6194489494240551360'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/6194489494240551360'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/06/capistrano-path-rake-fail.html' title='capistrano path rake fail'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-8507294234632172173</id><published>2010-06-13T17:12:00.002+08:00</published><updated>2010-06-13T17:18:25.828+08:00</updated><title type='text'>delayed_job capistrano production fail</title><content type='html'>主要參考 &lt;br /&gt;http://railscasts.com/episodes/171-delayed-job&lt;br /&gt;http://www.magnionlabs.com/2009/2/28/background-job-processing-in-rails-with-delayed_job&lt;br /&gt;&lt;br /&gt;不知道哪邊弄錯了用capistrano deploy 想啟動delayed_job 卻好像都沒反應&lt;br /&gt;後來終於看到 有script/delayed_job run的指令 這個動作才可以讓你看到你錯在哪, start 只會無聲無息&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;set :env, 'production' #不知道為範例的rails_env 都抓不到值&lt;br /&gt;&lt;br /&gt;namespace :delayed_job do&lt;br /&gt;  desc "Start delayed_job process" &lt;br /&gt;  task :start, :roles =&gt; :app do&lt;br /&gt;    run "cd #{current_path}; ruby script/delayed_job start -- #{env}" &lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  desc "Stop delayed_job process" &lt;br /&gt;  task :stop, :roles =&gt; :app do&lt;br /&gt;    run "cd #{current_path}; script/delayed_job stop -- #{env}" &lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  desc "Restart delayed_job process"&lt;br /&gt;  task :restart, :roles =&gt; :app do&lt;br /&gt;    run "cd #{current_path}; script/delayed_job restart -- #{env}" &lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-8507294234632172173?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/8507294234632172173/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=8507294234632172173' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8507294234632172173'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8507294234632172173'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/06/delayedjob-capistrano-production-fail.html' title='delayed_job capistrano production fail'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-1376512379260644131</id><published>2010-06-10T18:30:00.003+08:00</published><updated>2010-06-13T17:11:53.409+08:00</updated><title type='text'>rmagic cannot open shared object file: No such file or directory</title><content type='html'>&lt;a href="http://www.semanticpool.de/cannot-open-shared-object-file-no-such-file-or-directory/"&gt;libMagickCore.so.* cannot open shared object file: No such file or directory&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://github.com/jnstq/rails-nginx-passenger-ubuntu"&gt;http://github.com/jnstq/rails-nginx-passenger-ubuntu&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;To get rid of this error i executed&lt;br /&gt;&lt;br /&gt;ldconfig /usr/local/lib&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-1376512379260644131?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/1376512379260644131/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=1376512379260644131' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1376512379260644131'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1376512379260644131'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/06/rmagic-cannot-open-shared-object-file.html' title='rmagic cannot open shared object file: No such file or directory'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-6900881524730078168</id><published>2010-06-03T14:04:00.006+08:00</published><updated>2011-05-16T11:13:16.773+08:00</updated><title type='text'>nginx passenger config</title><content type='html'>&lt;a href="http://groups.google.com/group/phusion-passenger/browse_thread/thread/c004030ab1471e01"&gt;nginx, worker_processes, and passenger_max_pool_size&lt;/a&gt;&lt;br /&gt;&lt;a href="http://blog.scoutapp.com/articles/2009/12/08/production-rails-tuning-with-passenger-passengermaxprocesses"&gt;Production Rails Tuning with Passenger: PassengerMaxProcesses&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: ruby"&gt; &lt;br /&gt;worker_processes 4;    &lt;= Setting the number of Nginx workers to the number of CPU cores should be sufficient. &lt;br /&gt;&lt;br /&gt;http { &lt;br /&gt;passenger_max_pool_size 20; # memory 256M should be 2,  2G should be 30, max_pool 不要設太大, 不要讓它吃到swap,  free -ml ;  vmstat 2  都可以看到現在memory 的情況&lt;br /&gt;passenger_max_instances_per_app 15; #每種ap 能用到最多的instance, 所以如果跑兩個app 就會再少一點&lt;br /&gt;&lt;br /&gt;# PassengerPoolIdleTime&lt;br /&gt;# Recommended to be avg time per page * 2&lt;br /&gt;# In Google Analytics... (Avg time on site / Avg page views) * 2&lt;br /&gt;# Default: 300&lt;br /&gt;passenger_pool_idle_time 144&lt;br /&gt;&lt;br /&gt; } &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;超小型web server 設定&lt;br /&gt;&lt;a href="http://programming-gone-awry.blogspot.com/2009/06/how-to-save-much-ram-when-running-rails.html"&gt;How to save MUCH RAM when running rails (linode/slicehost) and mod_rails passenger&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-6900881524730078168?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/6900881524730078168/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=6900881524730078168' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/6900881524730078168'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/6900881524730078168'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/06/nginx-passenger-config.html' title='nginx passenger config'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-3973737463181597533</id><published>2010-05-07T14:40:00.004+08:00</published><updated>2010-05-07T14:42:43.648+08:00</updated><title type='text'>改變預設的cache 目錄</title><content type='html'>http://railsforum.com/viewtopic.php?id=11033&lt;br /&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;#光只是改變Rails 設定是不夠的&lt;br /&gt;config.action_controller.page_cache_directory = RAILS_ROOT + '/public/cache/'&lt;br /&gt;&lt;br /&gt;#還需要更改web server 的設定, 以下是apache 的設定&lt;br /&gt;RewriteEngine On&lt;br /&gt;RewriteCond %{THE_REQUEST} ^(GET|HEAD)&lt;br /&gt;RewriteCond %{REQUEST_URI} ^([^.]+)/?$&lt;br /&gt;RewriteCond %{DOCUMENT_ROOT}/cache/%1.html -f&lt;br /&gt;RewriteRule ^[^.]+/?$ /cache/%1.html [QSA,L]&lt;br /&gt;&lt;br /&gt;RewriteCond %{THE_REQUEST} ^(GET|HEAD)&lt;br /&gt;RewriteCond %{DOCUMENT_ROOT}/cache/index.html -f&lt;br /&gt;RewriteRule ^$ /cache/index.html [QSA,L]&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-3973737463181597533?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/3973737463181597533/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=3973737463181597533' title='2 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/3973737463181597533'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/3973737463181597533'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/05/cache.html' title='改變預設的cache 目錄'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-2598075944763639145</id><published>2010-04-20T17:49:00.000+08:00</published><updated>2010-04-20T17:50:25.150+08:00</updated><title type='text'>[Ptt][心得] Restful下遇到params[:id]含有.的解法</title><content type='html'>在restful的前提下, 遇到class的to_param是字串, 而剛好某筆&lt;br /&gt;        紀錄的to_param欄位含有.&lt;br /&gt;&lt;br /&gt;        一般情形下會發生錯誤, 因為restful會把.後的東西當成format&lt;br /&gt;        這時的解法, 變成要在routes.rb中的xxx.resources加上參數&lt;br /&gt;&lt;br /&gt;        ex:&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;     map.resources :categories, :requirements =&gt; {:id =&gt; /.*/}&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-2598075944763639145?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/2598075944763639145/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=2598075944763639145' title='3 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2598075944763639145'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2598075944763639145'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/04/ptt-restfulparamsid.html' title='[Ptt][心得] Restful下遇到params[:id]含有.的解法'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-1227558343371063425</id><published>2010-04-20T16:39:00.003+08:00</published><updated>2010-04-20T16:41:23.991+08:00</updated><title type='text'>paramter change permanently, header status</title><content type='html'>&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;    if params[:id] != @episode.to_param&lt;br /&gt;      headers["Status"] = "301 Moved Permanently"&lt;br /&gt;      redirect_to episode_url(@episode)&lt;br /&gt;    else&lt;br /&gt;      @comment = Comment.new(:episode =&gt; @episode)&lt;br /&gt;      respond_to do |format|&lt;br /&gt;        format.html&lt;br /&gt;        format.rss&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-1227558343371063425?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/1227558343371063425/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=1227558343371063425' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1227558343371063425'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1227558343371063425'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/04/paramter-change-permanently-header.html' title='paramter change permanently, header status'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-8332063815938971072</id><published>2010-04-16T01:59:00.002+08:00</published><updated>2010-04-16T02:34:13.778+08:00</updated><title type='text'>Practical Rails Social Networking Site memo (2)</title><content type='html'>&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;#Ch10&lt;br /&gt;module ApplicationHelper&lt;br /&gt;  def yes_no(bool)&lt;br /&gt;    ...&lt;br /&gt;  end&lt;br /&gt;  def tag_cloud(tags, classes)&lt;br /&gt;    max, min = 0, 0&lt;br /&gt;    tags.each do |tag|&lt;br /&gt;      max = tag.count if tag.count &gt; max&lt;br /&gt;      min = tag.count if tag.count &lt; min&lt;br /&gt;    end&lt;br /&gt;    divisor = ((max - min) / classes.size) + 1&lt;br /&gt;    tags.each do |tag|&lt;br /&gt;      yield tag.name, classes[(tag.count - min) / divisor]&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;% tag_cloud @tags, %w(tag1 tag2 tag3 tag4 tag5) do |name, css_class| %&gt;&lt;br /&gt;&lt;%= link_to name, tag_path(name), :class =&gt; css_class %&gt;&lt;br /&gt;&lt;% end %&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-8332063815938971072?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/8332063815938971072/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=8332063815938971072' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8332063815938971072'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8332063815938971072'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/04/practical-rails-social-networking-site_16.html' title='Practical Rails Social Networking Site memo (2)'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-7742367902730120574</id><published>2010-04-15T15:00:00.003+08:00</published><updated>2010-04-15T18:27:50.726+08:00</updated><title type='text'>Practical Rails Social Networking Site memo</title><content type='html'>&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;#Ch2&lt;br /&gt;def to_param&lt;br /&gt;"#{id}-#{permalink}"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def show&lt;br /&gt;@page = Page.find(params[:id].to_i)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#Some database servers (including MySQL) will automatically do this conversion for you. However,PostgreSQL and some others do not, so it is a good idea to add this to your controllers. You could also overridean ActiveRecord method&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#Ch3&lt;br /&gt;module LoginSystem&lt;br /&gt;  protected&lt;br /&gt;  def is_logged_in?&lt;br /&gt;    @logged_in_user = User.find(session[:user]) if session[:user]&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def logged_in_user&lt;br /&gt;    return @logged_in_user if is_logged_in?&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def logged_in_user=(user)&lt;br /&gt;    if !user.nil?&lt;br /&gt;      session[:user] = user.id&lt;br /&gt;      @logged_in_user = user&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def self.included(base)&lt;br /&gt;    base.send :helper_method, :is_logged_in?, :logged_in_user&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;map.show_user '/user/:username',:controller =&gt; 'users',:action =&gt; 'show_by_username'&lt;br /&gt;map.resources :users, :member =&gt; { :enable =&gt; :put }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;%= render :partial =&gt; 'role', :collection =&gt; @user.roles %&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h2&gt;Roles available:&lt;/h2&gt;&lt;br /&gt;&lt;ul&gt;&lt;%= render :partial =&gt; 'role', :collection =&gt; (@all_roles - @user.roles) %&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#Ch4&lt;br /&gt;def self.up&lt;br /&gt;  create_table :categories do |t|&lt;br /&gt;    t.column :name, :string&lt;br /&gt;  end&lt;br /&gt;  news_category = Category.create(:name =&gt; 'Site News')&lt;br /&gt;  change_column :articles, :category_id, :integer, :default =&gt; news_category&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def self.down&lt;br /&gt;  change_column :articles, :category_id, :integer, :default =&gt; 0&lt;br /&gt;  drop_table :categories&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def get_http_auth_data&lt;br /&gt;  username, password = nil, nil&lt;br /&gt;  auth_headers = ['X-HTTP_AUTHORIZATION', 'Authorization', 'HTTP_AUTHORIZATION',&lt;br /&gt;    'REDIRECT_REDIRECT_X_http_AUTHORIZATION']&lt;br /&gt;  auth_header = auth_headers.detect { |key| request.env[key] }&lt;br /&gt;  auth_data = request.env[auth_header].to_s.split&lt;br /&gt;&lt;br /&gt;  if auth_data &amp;&amp; auth_data[0] == 'Basic'&lt;br /&gt;    username, password = Base64.decode64(auth_data[1]).split(':')[0..1]&lt;br /&gt;  end&lt;br /&gt;  return [username, password]&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;@request.env['HTTP_ACCEPT'] = 'application/xml'&lt;br /&gt;@request.env['Authorization'] = 'Basic ' + Base64::b64encode('editor:12345')&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-7742367902730120574?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/7742367902730120574/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=7742367902730120574' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/7742367902730120574'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/7742367902730120574'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/04/practical-rails-social-networking-site.html' title='Practical Rails Social Networking Site memo'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-2110756155572504007</id><published>2010-04-06T10:51:00.001+08:00</published><updated>2010-04-06T10:53:24.855+08:00</updated><title type='text'>check timezone valid</title><content type='html'>&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;module TimeFunc&lt;br /&gt;  def self.included(base)&lt;br /&gt;    base.class_eval do&lt;br /&gt;      base.extend Methods&lt;br /&gt;    end &lt;br /&gt;  end &lt;br /&gt;    &lt;br /&gt;  module Methods&lt;br /&gt;    def check_timezone_legal(timezone)&lt;br /&gt;      raise IllegalTimeZone unless ActiveSupport::TimeZone::ZONES.map(&amp;:name).include?(timezone)&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-2110756155572504007?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/2110756155572504007/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=2110756155572504007' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2110756155572504007'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2110756155572504007'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/04/check-timezone-valid.html' title='check timezone valid'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-4538956129867287679</id><published>2010-03-21T22:43:00.003+08:00</published><updated>2010-03-21T22:45:05.158+08:00</updated><title type='text'>migration</title><content type='html'>&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;&lt;br /&gt;#add_OOXX_to_foos  可以直接指定foos table 作為操作的talbe&lt;br /&gt;ruby script/generate migration add_express_token_to_orders express_token:string express_payer_id:string&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-4538956129867287679?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/4538956129867287679/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=4538956129867287679' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4538956129867287679'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4538956129867287679'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/03/migration.html' title='migration'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-4793793581489133382</id><published>2010-03-10T10:33:00.001+08:00</published><updated>2010-03-10T10:33:53.383+08:00</updated><title type='text'>rjs page</title><content type='html'>page['foo']['style']&lt;br /&gt;# =&gt; $('foo').style;&lt;br /&gt;page['foo']['style']['color']&lt;br /&gt;# =&gt; $('blank_slate').style.color;&lt;br /&gt;page['foo']['style']['color'] = 'red'&lt;br /&gt;# =&gt; $('blank_slate').style.color = 'red';&lt;br /&gt;page['foo']['style'].color = 'red'&lt;br /&gt;# =&gt; $('blank_slate').style.color = 'red';&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-4793793581489133382?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/4793793581489133382/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=4793793581489133382' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4793793581489133382'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4793793581489133382'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/03/rjs-page.html' title='rjs page'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-7871661936921810662</id><published>2010-03-10T10:28:00.001+08:00</published><updated>2010-03-10T10:29:16.696+08:00</updated><title type='text'>respond_to jsonp</title><content type='html'>respond_to recognizes • JSON. &lt;br /&gt;render :json =&gt; @person.to_json automatically sets the content type and takes a :callback option to specify a client-side function to call using the rendered JSON as an argument. #4185 [Scott Raymond, eventualbuddha]&lt;br /&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;# application/json response&lt;br /&gt;# with body 'Element.show({:name: "David"})'&lt;br /&gt;respond_to do |format|&lt;br /&gt;  format.json {&lt;br /&gt;    render :json =&gt; { :name =&gt; "David" }.to_json,:callback =&gt; 'Element.show' &lt;br /&gt;  }&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-7871661936921810662?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/7871661936921810662/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=7871661936921810662' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/7871661936921810662'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/7871661936921810662'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/03/respondto-jsonp.html' title='respond_to jsonp'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-1537505840097037433</id><published>2010-03-10T10:08:00.001+08:00</published><updated>2010-03-10T10:08:57.798+08:00</updated><title type='text'>Bootstrap Initializer</title><content type='html'>Bootstrap Initializer&lt;br /&gt;The files in config/initializers are loaded after Rails' environment is loaded (including environment.rb). However, there's a pre-environment&lt;br /&gt;hook provided for you should you need to do things prior to Rails' environment getting in the mix: just create a &lt;span style="font-weight:bold;"&gt;config/preinitializer.rb&lt;/span&gt; file.&lt;br /&gt;&lt;br /&gt;This file is loaded after the Rails classes are loaded but before the environment file and the environment configuration.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-1537505840097037433?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/1537505840097037433/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=1537505840097037433' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1537505840097037433'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1537505840097037433'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/03/bootstrap-initializer.html' title='Bootstrap Initializer'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-2104467934952370086</id><published>2010-03-09T17:01:00.002+08:00</published><updated>2010-03-09T17:09:46.350+08:00</updated><title type='text'>rescue_from Exception Handlers</title><content type='html'>rescue_from Exception Handlers&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;  class PostsController &lt; ApplicationController&lt;br /&gt;    def rescue_action_in_public(exception)&lt;br /&gt;      case(exception)&lt;br /&gt;      when ActiveRecord::RecordNotFound&lt;br /&gt;        render :file =&gt; '/bad_record'&lt;br /&gt;      when NoMethodError&lt;br /&gt;        render :file =&gt; '/no_method'&lt;br /&gt;      else&lt;br /&gt;        render :file =&gt; '/error'&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#======================================&lt;br /&gt;  class PostsController &lt; ApplicationController&lt;br /&gt;    # Declare exception to handler methods&lt;br /&gt;    rescue_from ActiveRecord::RecordNotFound, :with =&gt; :bad_record&lt;br /&gt;    rescue_from NoMethodError, :with =&gt; :show_error&lt;br /&gt;&lt;br /&gt;    # Define handler methods&lt;br /&gt;    def bad_record&lt;br /&gt;      render :file =&gt; '/bad_record'&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def show_error(exception)&lt;br /&gt;      render :text =&gt; exception.message&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#======================================&lt;br /&gt;  class PostsController &lt; ApplicationController&lt;br /&gt;    rescue_from(ActiveRecord::RecordNotFound) do |exception|&lt;br /&gt;      render :file =&gt; '/bad_record'&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    rescue_from NoMethodError, :with =&gt; proc do |e|&lt;br /&gt;      render :text =&gt; e.message&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-2104467934952370086?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/2104467934952370086/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=2104467934952370086' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2104467934952370086'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2104467934952370086'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/03/rescuefrom-exception-handlers.html' title='rescue_from Exception Handlers'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-9148861858926780394</id><published>2010-03-05T16:53:00.002+08:00</published><updated>2010-03-05T17:49:46.599+08:00</updated><title type='text'>Top 8 SQL Best Practices</title><content type='html'>&lt;a href="http://www.sheeri.com/content/top-8-sql-best-practices"&gt;Top 8 SQL Best Practices&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;1) Always use explicit joins. If I mean INNER JOIN, then I use INNER JOIN. No use of just plain "JOIN". Never, ever, ever use a comma join -- I consider that a mistake. If I explicitly state "CROSS JOIN" then I know I have consciously made that decision. Also, keep join conditions in an ON or USING clause; they should not go in the WHERE clause. I also put my join conditions in parentheses; for whatever reason, I find:&lt;br /&gt;ON (foo=bar AND baz=bop) WHERE a=b&lt;br /&gt;is easier to see that the join condition contains 2 conditions than&lt;br /&gt;ON foo=bar AND baz=bop WHERE a=b&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-9148861858926780394?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/9148861858926780394/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=9148861858926780394' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/9148861858926780394'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/9148861858926780394'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/03/top-8-sql-best-practices.html' title='Top 8 SQL Best Practices'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-2083413230281990149</id><published>2010-03-05T16:14:00.002+08:00</published><updated>2010-03-05T16:34:47.982+08:00</updated><title type='text'>SQL Server TSQL Coding Conventions, Best Practices, and Programming Guidelines</title><content type='html'>&lt;a href="http://www.sql-server-performance.com/articles/dev/sql_best_practices_p1.aspx"&gt;SQL Server TSQL Coding Conventions, Best Practices, and Programming Guidelines&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Try to avoid wildcard characters at the beginning of a word while searching using the LIKE keyword, as that results in an index scan, which defeats the purpose of an index. The following statement results in an index scan, while the second statement results in an index seek:&lt;br /&gt;&lt;br /&gt;SELECT LocationID FROM Locations WHERE Specialities LIKE '%pples'&lt;br /&gt;SELECT LocationID FROM Locations WHERE Specialities LIKE 'A%s'&lt;br /&gt;&lt;br /&gt;Also avoid searching using not equals operators (&lt;&gt; and NOT) as they result in table and index scans.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;br /&gt;Use 'Derived tables' wherever possible, as they perform better. Consider the following query to find the second highest salary from the Employees table:&lt;br /&gt;&lt;br /&gt;SELECT MIN(Salary) &lt;br /&gt;FROM Employees &lt;br /&gt;WHERE EmpID IN&lt;br /&gt;(&lt;br /&gt;SELECT TOP 2 EmpID &lt;br /&gt;FROM Employees &lt;br /&gt;ORDER BY Salary Desc&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;The same query can be re-written using a derived table, as shown below, and it performs twice as fast as the above query:&lt;br /&gt;&lt;br /&gt;SELECT MIN(Salary) &lt;br /&gt;FROM &lt;br /&gt;(&lt;br /&gt;SELECT TOP 2 Salary &lt;br /&gt;FROM Employees &lt;br /&gt;ORDER BY Salary DESC&lt;br /&gt;) AS A&lt;br /&gt;&lt;br /&gt;This is just an example, and your results might differ in different scenarios depending on the database design, indexes, volume of data, etc. So, test all the possible ways a query could be written and go with the most efficient one.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;br /&gt;While designing your database, design it keeping "performance" in mind. You can't really tune performance later, when your database is in production, as it involves rebuilding tables andindexes, re-writing queries, etc. Use the graphical execution plan in Query Analyzer or SHOWPLAN_TEXT or SHOWPLAN_ALL commands to analyze your queries. Make sure your queries do an "Index seek" instead of an "Index scan" or a "Table scan." A table scan or an index scan is a very bad thing and should be avoided where possible. Choose the right indexes on the right columns.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;br /&gt;Use the more readable ANSI-Standard Join clauses instead of the old style joins. With ANSI joins, the WHERE clause is used only for filtering data. Where as with older style joins, the WHERE clause handles both the join condition and filtering data. The first of the following two queries shows the old style join, while the second one shows the new ANSI join syntax:&lt;br /&gt;&lt;br /&gt;SELECT a.au_id, t.title &lt;br /&gt;FROM titles t, authors a, titleauthor ta&lt;br /&gt;WHERE &lt;br /&gt;a.au_id = ta.au_id AND&lt;br /&gt;ta.title_id = t.title_id AND &lt;br /&gt;t.title LIKE '%Computer%'&lt;br /&gt;&lt;br /&gt;SELECT a.au_id, t.title&lt;br /&gt;FROM authors a &lt;br /&gt;INNER JOIN&lt;br /&gt;titleauthor ta &lt;br /&gt;ON &lt;br /&gt;a.au_id = ta.au_id&lt;br /&gt;INNER JOIN&lt;br /&gt;titles t&lt;br /&gt;ON&lt;br /&gt;ta.title_id = t.title_id&lt;br /&gt;WHERE t.title LIKE '%Computer%'&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-2083413230281990149?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/2083413230281990149/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=2083413230281990149' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2083413230281990149'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2083413230281990149'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/03/sql-server-tsql-coding-conventions-best.html' title='SQL Server TSQL Coding Conventions, Best Practices, and Programming Guidelines'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-1413727116714683067</id><published>2010-03-05T12:23:00.001+08:00</published><updated>2010-03-05T12:24:56.112+08:00</updated><title type='text'>rails performance memo</title><content type='html'>&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;#Use external programs&lt;br /&gt;&lt;br /&gt;def thumbnail(temp, target)&lt;br /&gt;    system("/usr/local/bin/convert #{escape(temp)} -resize&lt;br /&gt;48x48! #{escape(target}")&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#Write inline C/C++ code&lt;br /&gt;• RubyInline: Write foreign code within ruby code&lt;br /&gt;  http://rubyinline.rubyforge.org/RubyInline/&lt;br /&gt;&lt;br /&gt;• Rice: Ruby Interface for C++ Extensions&lt;br /&gt;  http://rice.rubyforge.org/&lt;br /&gt;&lt;br /&gt;• Ruby-FFI: a ruby extension for programmatically&lt;br /&gt;  loading dynamic libraries&lt;br /&gt;  http://github.com/ffi/ffi&lt;br /&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-1413727116714683067?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/1413727116714683067/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=1413727116714683067' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1413727116714683067'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1413727116714683067'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/03/rails-performance-memo.html' title='rails performance memo'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-4027529039342192794</id><published>2010-03-03T15:00:00.002+08:00</published><updated>2010-03-03T15:51:45.734+08:00</updated><title type='text'>That’s Not a Memory Leak, It’s Bloat;  refactor</title><content type='html'>&lt;a href="That’s Not a Memory Leak, It’s Bloat"&gt;That’s Not a Memory Leak, It’s Bloat&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;#:includes are Including Too Much&lt;br /&gt;Article.find(:all, :include =&gt; [:user =&gt; [:posts =&gt; :comments]])&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#:includes on a has_many&lt;br /&gt;@articles.users.find(:all, :include =&gt; [:posts =&gt; :comments]])&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#Use :select When You Must Instantiate Large Quantities of Records&lt;br /&gt;@comment_ids = Comment.find(:all, :select =&gt; 'comments.id').collect{|comment| comment.id }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#Overfed Feeds&lt;br /&gt;Check all the places you are making XML sandwiches. Often these controllers are written early on and don’t scale well. Maybe you have a sitemap XML feed that delivers every record under the sun to Google, or are rending some large amount of data for an API.&lt;br /&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-4027529039342192794?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/4027529039342192794/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=4027529039342192794' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4027529039342192794'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4027529039342192794'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/03/thats-not-memory-leak-its-bloat.html' title='That’s Not a Memory Leak, It’s Bloat;  refactor'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-1895927629233794390</id><published>2010-03-03T12:08:00.002+08:00</published><updated>2010-03-03T12:09:17.036+08:00</updated><title type='text'>respond_to</title><content type='html'>&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;&lt;br /&gt;#===============================================&lt;br /&gt;class ApplicationController &lt; ActionController::Base&lt;br /&gt;   before_filter :adjust_format_for_iphone&lt;br /&gt;   helper_method :iphone_user_agent?&lt;br /&gt;&lt;br /&gt;protected&lt;br /&gt;   def adjust_format_for_iphone&lt;br /&gt;     request.format = :iphone if iphone_user_agent? || iphone_subdomain?&lt;br /&gt;   end&lt;br /&gt;&lt;br /&gt;     # Request from an iPhone or iPod touch?&lt;br /&gt;     # (Mobile Safari user agent)&lt;br /&gt;   def iphone_user_agent?&lt;br /&gt;     request.env["HTTP_USER_AGENT" ] &amp;&amp;&lt;br /&gt;         request.env["HTTP_USER_AGENT" ][/(Mobile\/.+Safari)/]&lt;br /&gt;   end&lt;br /&gt;&lt;br /&gt;   def iphone_subdomain?&lt;br /&gt;     return request.subdomains.first == "iphone"&lt;br /&gt;   end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# =======================&lt;br /&gt;# custom format&lt;br /&gt;# config/initializers/mime_types.rb&lt;br /&gt;Mime::Type.register ‘audio/mpeg’, :mp3?Mime::Type.register ‘audio/mpegurl’, :m3u&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def show&lt;br /&gt;    @mp3 = Mp3.find(params[:id])&lt;br /&gt;    respond_to do |format|&lt;br /&gt;         format.html&lt;br /&gt;         format.mp3 { redirect_to @mp3.url }&lt;br /&gt;         format.m3u { render :text =&gt; @mp3.url }&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#========================&lt;br /&gt;def index&lt;br /&gt;    @users = User.find(:all)&lt;br /&gt;    respond_to do |format|&lt;br /&gt;        format.js {&lt;br /&gt;            render :update do |page|&lt;br /&gt;                page.replace_html ‘content’, ‘&lt;p&gt;blah&lt;/p&gt;’&lt;br /&gt;            end&lt;br /&gt;        }&lt;br /&gt;        format.html #index.html.erb&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-1895927629233794390?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/1895927629233794390/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=1895927629233794390' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1895927629233794390'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1895927629233794390'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/03/respondto.html' title='respond_to'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-4057566370080270509</id><published>2010-03-03T10:55:00.007+08:00</published><updated>2010-03-03T12:09:10.649+08:00</updated><title type='text'>Restful memo</title><content type='html'>&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;#RESTful controller 一定是複數結尾&lt;br /&gt;map.resources :events do |event|&lt;br /&gt;    event.resource :map, :controller =&gt; ‘event_maps’&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#=============================================&lt;br /&gt;# 之前用的笨方法&lt;br /&gt;map.resources :orders, :path_prefix =&gt; "/admin", :controller =&gt; "admin/orders"&lt;br /&gt;&lt;br /&gt;# 其實有namespace&lt;br /&gt;map.namespace :admin do |admin|&lt;br /&gt;  admin.resources :events&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# /app/controllers/admin/events_controller.rb&lt;br /&gt;class Admin::EventsController &lt; ApplicationController&lt;br /&gt;    before_filter :require_admin&lt;br /&gt;    def index&lt;br /&gt;        ....&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#============================================&lt;br /&gt;=begin &lt;br /&gt;Considerations(1)&lt;br /&gt;  a REST resource does not map directly to&lt;br /&gt;  model. It’s high-level abstractions of what’s&lt;br /&gt;  available through your web app.&lt;br /&gt;  (Not always 1-to-1, maybe 1-to-many or 1-to-zero)&lt;br /&gt;&lt;br /&gt;• You don’t need to use all 7 actions if you don’t need them.&lt;br /&gt;&lt;br /&gt;Considerations(2)&lt;br /&gt;&lt;br /&gt;a RESTful controller may represent the&lt;br /&gt;creation or delete of only a concept.&lt;br /&gt;For example, a SpamsController create spam by changing a comment’s status&lt;br /&gt;to spam without adding any records to the DB.&lt;br /&gt;&lt;br /&gt;Considerations(3)&lt;br /&gt;  one resources should be associated with one controller.&lt;br /&gt;  (well, you can use one controller handle more than one resources)&lt;br /&gt;• offload privileged views into either a different controller or action.&lt;br /&gt;&lt;br /&gt;=end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#==================================&lt;br /&gt;&lt;br /&gt;#for event manager                                     &lt;br /&gt;map.resources :attendees &lt;br /&gt;&lt;br /&gt;class AttendeeController &lt; ApplicationController&lt;br /&gt;  before_filter :manager_required&lt;br /&gt;  def show&lt;br /&gt;    @person = @event.attendees.find(params[:id])&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#for attendeeing user&lt;br /&gt;map.resources :registers&lt;br /&gt;class RegistersController &lt; ApplicationController&lt;br /&gt;  before_filter :login_required&lt;br /&gt;&lt;br /&gt;  def show&lt;br /&gt;    @person = current_user.registers.find(params[:id])&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;1 attendee Model   &lt;br /&gt;2 Resources related      &lt;br /&gt;(2 Controller)    &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#==============================================&lt;br /&gt;# http://ryandaigle.com/articles/2008/11/27/what-s-new-in-edge-rails-no-more-formatted-routes&lt;br /&gt;# Old =&gt; New&lt;br /&gt;formatted_article_path(article, :xml) =&gt; article_path(article, :format =&gt; :xml)&lt;br /&gt;formatted_new_article_path(:json) =&gt; new_article_path(:format =&gt; :json)&lt;br /&gt;# etc...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-4057566370080270509?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/4057566370080270509/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=4057566370080270509' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4057566370080270509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4057566370080270509'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/03/restful-memo.html' title='Restful memo'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-29311407028752607</id><published>2010-03-02T10:34:00.002+08:00</published><updated>2010-03-02T12:07:13.699+08:00</updated><title type='text'>Rails Best Practices</title><content type='html'>&lt;a href="http://ihower.tw/blog/archives/3075"&gt;Rails Best Practices&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;#Before&lt;br /&gt;&lt;% form_for @user do |f| %&gt;&lt;br /&gt;  &lt;%= f.text_field :email %&gt;&lt;br /&gt;  &lt;% for role in Role.all %&gt;&lt;br /&gt;    &lt;%= check_box_tag 'role_id[]', role.id, @user.roles.include?(role) %&gt;&lt;br /&gt;    &lt;%= role.name %&gt;&lt;br /&gt;  &lt;% end %&gt;&lt;br /&gt;&lt;% end %&gt;&lt;br /&gt;&lt;br /&gt;class User &lt; ApplicationController&lt;br /&gt;  def update&lt;br /&gt;    @user = User.find(params[:id])&lt;br /&gt;    if @user.update_attributes(params[:user])&lt;br /&gt;      @user.roles.delete_all&lt;br /&gt;      (params[:role_id] || []).each { |i| @user.roles &lt;&lt; Role.find(i) }&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#After&lt;br /&gt;&lt;% form_for @user do |f| %&gt;&lt;br /&gt; &lt;% for role in Role.all %&gt;&lt;br /&gt;  &lt;%= check_box_tag 'user[role_ids][]', role.id, @user.roles.include?(role)&lt;br /&gt;  &lt;%= role.name %&gt;&lt;br /&gt; &lt;% end %&gt;&lt;br /&gt; &lt;%= hidden_field_tag 'user[role_ids][]', '' %&gt;&lt;br /&gt;&lt;% end %&gt;&lt;br /&gt;&lt;br /&gt;class User &lt; ApplicationController&lt;br /&gt;  def update&lt;br /&gt;    @user = User.find(params[:id])&lt;br /&gt;    @user.update_attributes(params[:user])&lt;br /&gt;    #       @user.role_ids = params[:user][:role_ids]&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#==========================================&lt;br /&gt;&lt;br /&gt;#Nested Model Forms (one-to-one)  Before&lt;br /&gt;&lt;br /&gt;class Product &lt; ActiveRecord::Base&lt;br /&gt;  has_one :detail&lt;br /&gt;end&lt;br /&gt;class Detail &lt; ActiveRecord::Base&lt;br /&gt;  belongs_to :product&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;% form_for :product do |f| %&gt;&lt;br /&gt;  &lt;%= f.text_field :title %&gt;&lt;br /&gt;  &lt;% fields_for :detail do |detail| %&gt;&lt;br /&gt;    &lt;%= detail.text_field :manufacturer %&gt;&lt;br /&gt;  &lt;% end %&gt;&lt;br /&gt;&lt;% end %&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class Product &lt; ApplicationController&lt;br /&gt;  def create&lt;br /&gt;    @product = Product.new(params[:product])&lt;br /&gt;    @details = Detail.new(params[:detail])&lt;br /&gt;&lt;br /&gt;    Product.transaction do&lt;br /&gt;      @product.save!&lt;br /&gt;      @details.product = @product&lt;br /&gt;      @details.save!&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# ~~~~~~~~~~~~~~~~~~~~~~~~~&lt;br /&gt;# Nested Model Forms (one-to-one) After Rails 2.3 new feature&lt;br /&gt;&lt;br /&gt;class Product &lt; ActiveRecord::Base&lt;br /&gt;  has_one :detail&lt;br /&gt;  accepts_nested_attributes_for :detail&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;% form_for :product do |f| %&gt;&lt;br /&gt;  &lt;%= f.text_field :title %&gt;&lt;br /&gt;  &lt;% f.fields_for :detail do |detail| %&gt;&lt;br /&gt;    &lt;%= detail.text_field :manufacturer %&gt;&lt;br /&gt;  &lt;% end %&gt;&lt;br /&gt;&lt;% end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class Product &lt; ApplicationController&lt;br /&gt;  def create&lt;br /&gt;    @product = Product.new(params[:product])&lt;br /&gt;    @product.save&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#Nested Model Forms (one-to-many)&lt;br /&gt;&lt;br /&gt;class Project &lt; ActiveRecord::Base&lt;br /&gt;  has_many :tasks&lt;br /&gt;  accepts_nested_attributes_for :tasks&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class Task &lt; ActiveRecord::Base&lt;br /&gt;  belongs_to :project&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;% form_for @project do |f| %&gt;&lt;br /&gt;  &lt;%= f.text_field :name %&gt;&lt;br /&gt;  &lt;% f.fields_for :tasks do |tasks_form| %&gt;&lt;br /&gt;    &lt;%= tasks_form.text_field :name %&gt;&lt;br /&gt;  &lt;% end %&gt;&lt;br /&gt;&lt;% end %&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#===========================================&lt;br /&gt;#Extract into Module Before&lt;br /&gt;&lt;br /&gt;class User &lt; ActiveRecord::Base&lt;br /&gt;  validates_presence_of :cellphone&lt;br /&gt;  before_save :parse_cellphone&lt;br /&gt;&lt;br /&gt;  def parse_cellphone&lt;br /&gt;    # do something&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#&lt;br /&gt;/lib/has_cellphone.rb&lt;br /&gt;module HasCellphone&lt;br /&gt;&lt;br /&gt;  def self.included(base)&lt;br /&gt;    base.validates_presence_of :cellphone&lt;br /&gt;    base.before_save :parse_cellphone&lt;br /&gt;    base.send(:include,InstanceMethods)&lt;br /&gt;    base.send(:extend, ClassMethods)&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  module InstanceMethods&lt;br /&gt;    def parse_cellphone&lt;br /&gt;      # do something&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  module ClassMethods&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class User &lt; ActiveRecord::Base&lt;br /&gt;  include HasCellphone&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#=======================================&lt;br /&gt;# Extract to composed class  Before&lt;br /&gt;&lt;br /&gt;# == Schema Information&lt;br /&gt;# address_city          :string(255)&lt;br /&gt;# address_street        :string(255)&lt;br /&gt;class Customer &lt; ActiveRecord::Base&lt;br /&gt;  def adddress_close_to?(other_customer)&lt;br /&gt;    address_city == other_customer.address_city&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def address_equal(other_customer)&lt;br /&gt;    address_street == other_customer.address_street &amp;&amp;&lt;br /&gt;      address_city == other_customer.address_city&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#Extract to composed class (value object)  After&lt;br /&gt;class Customer &lt; ActiveRecord::Base&lt;br /&gt;  composed_of :address, :mapping =&gt; [ %w(address_street street),&lt;br /&gt;                                      %w(address_city city) ]&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class Address&lt;br /&gt;  attr_reader :street, :city&lt;br /&gt;  def initialize(street, city)&lt;br /&gt;    @street, @city = street, city&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def close_to?(other_address)&lt;br /&gt;    city == other_address.city&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def ==(other_address)&lt;br /&gt;    city == other_address.city &amp;&amp; street == other_address.street&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# Isolating Seed Data&lt;br /&gt;# Before&lt;br /&gt;&lt;br /&gt;class CreateRoles &lt; ActiveRecord::Migration&lt;br /&gt;  def self.up&lt;br /&gt;    create_table "roles", :force =&gt; true do |t|&lt;br /&gt;      t.string :name&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    #Move this to  db/seeds.rb&lt;br /&gt;    ["admin", "author", "editor","account"].each do |name|&lt;br /&gt;      Role.create!(:name =&gt; name)&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def self.down&lt;br /&gt;    drop_table "roles"&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# After&lt;br /&gt;# /db/seeds.rb (Rails 2.3.4)&lt;br /&gt;["admin", "author", "editor","account"].each do |name|&lt;br /&gt;  Role.create!(:name =&gt; name)&lt;br /&gt;end&lt;br /&gt;rake db:seed&lt;br /&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-29311407028752607?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/29311407028752607/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=29311407028752607' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/29311407028752607'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/29311407028752607'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/03/rails-best-practices.html' title='Rails Best Practices'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-2080699467778854935</id><published>2010-03-01T17:39:00.003+08:00</published><updated>2010-03-01T18:30:44.817+08:00</updated><title type='text'>Advanced Active Record Techniques: Best Practice Refactoring</title><content type='html'>&lt;a href="http://en.oreilly.com/rails2008/public/schedule/detail/2032"&gt;Advanced Active Record Techniques: Best Practice Refactoring&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;#p54&lt;br /&gt;&lt;br /&gt;class ArticleVersion &lt; ActiveRecord::Base&lt;br /&gt;  before_validation_on_create :set_version_number&lt;br /&gt;   &lt;br /&gt;  before_create :mark_related_links_not_current, :if =&gt; :current_version&lt;br /&gt;&lt;br /&gt;  private&lt;br /&gt;  &lt;br /&gt;  def current_version&lt;br /&gt;    article.current_version&lt;br /&gt;  end&lt;br /&gt;  &lt;br /&gt;  #下面兩個method 都會call 到 article.current_version &lt;br /&gt;  #這樣就可以抽出來&lt;br /&gt;  #然後mark_related_linkers_not_current 會需要判斷 article.current_version 的存在與否這也可以利用 Conditional Callback 來判斷&lt;br /&gt;&lt;br /&gt;  def set_version_number&lt;br /&gt;    self.version = (current_version ? current_version.version : 0) + 1&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def mark_related_links_not_current&lt;br /&gt;    current_version.relateds.each do |rel|&lt;br /&gt;      rel.update_attribute(:current, false)&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#================================================================&lt;br /&gt;#p74&lt;br /&gt;class ArticleVersion &lt; ActiveRecord::Base&lt;br /&gt;  STATES = { :edit =&gt; 'Edit',&lt;br /&gt;             :edit_check =&gt; 'Edit Check',&lt;br /&gt;             :sub_edit =&gt; 'Sub Edit',&lt;br /&gt;             :publish_ready =&gt; 'Publish Ready',&lt;br /&gt;             :published =&gt; 'Published' }&lt;br /&gt;&lt;br /&gt;  STATES.each do |key, value|&lt;br /&gt;    define_method "#{key}?", {&lt;br /&gt;      self.state == "#{value}"&lt;br /&gt;    }&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#=========================================================&lt;br /&gt;# p84&lt;br /&gt;&lt;br /&gt;class Role &lt; ActiveRecord::Base&lt;br /&gt;  has_and_belongs_to_many :users&lt;br /&gt;  validates_presence_of :name&lt;br /&gt;  validates_uniqueness_of :name&lt;br /&gt;&lt;br /&gt;  def name=(value)&lt;br /&gt;    write_attribute("name", value.downcase)&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  # 想用symbol 拿值&lt;br /&gt;  def self.[](name) # Get a role quickly by using: Role[:admin]&lt;br /&gt;    self.find(:first, :conditions =&gt; ["name = ?", name.id2name])&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def add_user(user)&lt;br /&gt;    self.users &lt;&lt; user&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def delete_user(user)&lt;br /&gt;    self.users.delete(user)&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#====================================================&lt;br /&gt;# p91&lt;br /&gt;&lt;br /&gt;class User &lt; ActiveRecord::Base&lt;br /&gt;  has_many :roles&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class Role &lt; ActiveRecord::Base&lt;br /&gt;  TYPES = %w(admin editor writer guest)&lt;br /&gt;  validates_inclusion_of :name, :in =&gt; TYPES&lt;br /&gt;&lt;br /&gt;  # 生成 class method&lt;br /&gt;  class &lt;&lt; self&lt;br /&gt;    TYPES.each do |role_type|&lt;br /&gt;      define_method "#{role_type}?" do&lt;br /&gt;        # Exists?  http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M002268&lt;br /&gt;        roles.exists?(:name =&gt; role_type)&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# =====================================================&lt;br /&gt;# p96&lt;br /&gt;&lt;br /&gt;# Step 1&lt;br /&gt;class User &lt; ActiveRecord::Base&lt;br /&gt;  include Addressable&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class Order &lt; ActiveRecord::Base&lt;br /&gt;  include Addressable&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;module Addressable&lt;br /&gt;  def self.included(base)&lt;br /&gt;    base.validates_presence_of :billing_address_one, :billing_city, :billing_state,&lt;br /&gt;                               :billing_zip, :billing_country&lt;br /&gt;    base.validates_presence_of :shipping_address_one, :shipping_city, :shipping_state,&lt;br /&gt;                               :shipping_zip, :shipping_country&lt;br /&gt;    base.validates_format_of :billing_zip,&lt;br /&gt;                             :with =&gt; /\d{5}(-\d{4})?/,&lt;br /&gt;                             :if =&gt; Proc.new { |klass| klass.billing_country == "US" }&lt;br /&gt;    base.validates_format_of :shipping_zip,&lt;br /&gt;                             :with =&gt; /\d{5}(-\d{4})?/,&lt;br /&gt;                             :if =&gt; Proc.new { |klass| klass.shipping_country == "US" }&lt;br /&gt;    base.validates_format_of :billing_zip,&lt;br /&gt;                             :with =&gt; /[a-zA-Z]\d[a-zA-Z] \d[a-zA-Z]\d/,&lt;br /&gt;                             :if =&gt; Proc.new { |klass| klass.billing_country == "CA" }&lt;br /&gt;    base.validates_format_of :shipping_zip,&lt;br /&gt;                             :with =&gt; /[a-zA-Z]\d[a-zA-Z] \d[a-zA-Z]\d/,&lt;br /&gt;                             :if =&gt; Proc.new { |klass| klass.shipping_country == "CA" }&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# Step 2&lt;br /&gt;&lt;br /&gt;class User &lt; ActiveRecord::Base&lt;br /&gt;  has_address :shipping&lt;br /&gt;  has_address :billing&lt;br /&gt;  has_many :orders&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;module Addressable&lt;br /&gt;  class &lt;&lt; self&lt;br /&gt;    def included(base)&lt;br /&gt;      base.extend ClassMethods&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  module ClassMethods&lt;br /&gt;    def has_address(name = "")&lt;br /&gt;      name = "#{name}_" unless name.blank?&lt;br /&gt;      validates_presence_of "#{name}address_one", "#{name}city",&lt;br /&gt;                            "#{name}state_province", "#{name}postal_code", "#{name}country"&lt;br /&gt;      validates_format_of "#{name}postal_code", :with =&gt; /\d{5}(-\d{4})?/,&lt;br /&gt;                          :if =&gt; Proc.new { |user| user["#{name}country"] == "US" }&lt;br /&gt;      validates_format_of "#{name}postal_code", :with =&gt; /[a-zA-Z]\d[a-zA-Z] \d[a-zA-Z]\d/,&lt;br /&gt;                          :if =&gt; Proc.new { |user| user["#{name}country"] == "CA" }&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;ActiveRecord::Base.send :include, Addressable&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# Step 3&lt;br /&gt;&lt;br /&gt;                                   &lt;br /&gt;class User &lt; ActiveRecord::Base&lt;br /&gt;  has_address :shipping&lt;br /&gt;  has_address :billing&lt;br /&gt;                                   &lt;br /&gt;  has_many :orders&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;module Addressable&lt;br /&gt;  class &lt;&lt; self&lt;br /&gt;    def included(base)&lt;br /&gt;      base.extend ClassMethods&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  module ClassMethods&lt;br /&gt;    def has_address(name)&lt;br /&gt;      name &lt;&lt; “_” unless name.blank?&lt;br /&gt;      validates_presence_of "#{name}address_one", "#{name}city",&lt;br /&gt;                             "#{name}state_province", "#{name}postal_code", "#{name}country"&lt;br /&gt;      validates_format_of "#{name}postal_code", :with =&gt; /\d{5}(-\d{4})?/,&lt;br /&gt;                           :if =&gt; Proc.new { |user| user["#{name}country"] == "US" }&lt;br /&gt;      validates_format_of "#{name}postal_code", :with =&gt; /[a-zA-Z]\d[a-zA-Z] \d[a-zA-Z]\d/,&lt;br /&gt;                           :if =&gt; Proc.new { |user| user["#{name}country"] == "CA" }&lt;br /&gt;      composed_of "#{name}address", :class_name =&gt; “Address”,&lt;br /&gt;                   :mapping =&gt; [ ["#{name}address_one", "address_one"],&lt;br /&gt;                                 ["#{name}address_two", "address_two"],&lt;br /&gt;                                 ["#{name}city", "city"],&lt;br /&gt;                                 ["#{name}state_province", "state_province"],&lt;br /&gt;                                 ["#{name}postal_code", "postal_code"]&lt;br /&gt;                                 ["#{name}country", "country"] ]&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;ActiveRecord::Base.send :include, Addressable&lt;br /&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-2080699467778854935?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/2080699467778854935/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=2080699467778854935' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2080699467778854935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2080699467778854935'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/03/advanced-active-record-techniques-best.html' title='Advanced Active Record Techniques: Best Practice Refactoring'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-2746106034374452295</id><published>2010-03-01T16:25:00.002+08:00</published><updated>2010-03-01T16:30:41.946+08:00</updated><title type='text'>Rails Code Review PDF</title><content type='html'>http://peepcode.com/products/rails-code-review-pdf&lt;br /&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;#:select and :include&lt;br /&gt;&lt;br /&gt;#If a query contains an :include directive, any :select&lt;br /&gt;options will be ignored. For example you might expect this&lt;br /&gt;to return an array of ids only. Not so!&lt;br /&gt;&lt;br /&gt;# This won't work as you expect&lt;br /&gt;Farm.find(:all, {&lt;br /&gt;   :select =&gt; "farms.id, chickens.id",&lt;br /&gt;   :include =&gt; :chickens&lt;br /&gt;})&lt;br /&gt;&lt;br /&gt;#use :join with :select&lt;br /&gt;The way around this is to code the :join explicitly.&lt;br /&gt;  Farm.find(:all, {&lt;br /&gt;     :select =&gt; "farms.id, chickens.id",&lt;br /&gt;     :join   =&gt; "LEFT JOIN ..."&lt;br /&gt;  })&lt;br /&gt;&lt;br /&gt;LEFT OUTER JOIN chickens ON chickens.farm_id =&lt;br /&gt;farms.id&lt;br /&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-2746106034374452295?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/2746106034374452295/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=2746106034374452295' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2746106034374452295'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2746106034374452295'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/03/rails-code-review-pdf.html' title='Rails Code Review PDF'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-2314069358027268008</id><published>2010-02-26T10:34:00.001+08:00</published><updated>2010-02-26T10:36:26.125+08:00</updated><title type='text'>Enable or fix logging for HAProxy load balancer</title><content type='html'>&lt;a href="http://linuxadminzone.com/enable-or-fix-logging-for-haproxy-load-balancer/"&gt;Enable or fix logging for HAProxy load balancer&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;On a RedHat/CentOS server, edit the value of SYSLOGD_OPTIONS in /etc/sysconfig/syslog:&lt;br /&gt;&lt;br /&gt;    SYSLOGD_OPTIONS=”-m 0 -r” &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;On a Debian/Ubuntu server, edit the value of SYSLOGD in /etc/default/syslogd:&lt;br /&gt;&lt;br /&gt;    SYSLOGD=”-r” &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; /etc/syslog.conf:&lt;br /&gt;&lt;br /&gt;    local0.* /var/log/haproxy.log &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;restart syslog service to apply changes:&lt;br /&gt;&lt;br /&gt;    service syslog restart&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-2314069358027268008?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/2314069358027268008/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=2314069358027268008' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2314069358027268008'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2314069358027268008'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/02/enable-or-fix-logging-for-haproxy-load.html' title='Enable or fix logging for HAProxy load balancer'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-4791015978603761422</id><published>2010-02-22T14:55:00.006+08:00</published><updated>2010-07-19T11:24:26.724+08:00</updated><title type='text'>request host, query paramters, header</title><content type='html'>&lt;a href="http://railsfun.tw/viewthread.php?tid=439"&gt;登入登出轉址設計&lt;/a&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;request.env['QUERY_STRING']&lt;br /&gt;"cat=futures&amp;sort=latest"&lt;br /&gt;&lt;br /&gt;#full url&lt;br /&gt;request.url&lt;br /&gt;#http://localhost:3000/home/&lt;br /&gt;&lt;br /&gt;#path&lt;br /&gt;request.request_uri&lt;br /&gt;"/home/"&lt;br /&gt;&lt;br /&gt;#host_and_port&lt;br /&gt;request.host_with_port&lt;br /&gt;&lt;br /&gt;#source code http://api.rubyonrails.org/classes/ActionController/Base.html&lt;br /&gt;           when :back&lt;br /&gt;             if referer = request.headers["Referer"]&lt;br /&gt;               redirect_to(referer, :status=&gt;status)&lt;br /&gt;             else&lt;br /&gt;               raise RedirectBackError&lt;br /&gt;             end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-4791015978603761422?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/4791015978603761422/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=4791015978603761422' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4791015978603761422'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4791015978603761422'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/02/query-paramters.html' title='request host, query paramters, header'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-4261677483739537472</id><published>2010-02-21T21:26:00.002+08:00</published><updated>2010-02-21T21:41:14.759+08:00</updated><title type='text'>multi-step</title><content type='html'>&lt;a href="http://ow.ly/18z1T"&gt;RoR Multi-step forms&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;private&lt;br /&gt;    def get_partial_user_from_session&lt;br /&gt;      unless @session['partial_user'].nil?&lt;br /&gt;        @user = @session['partial_user']&lt;br /&gt;      else&lt;br /&gt;        @user = User.new&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def save_partial_user_in_session&lt;br /&gt;      unless @user.nil?&lt;br /&gt;        @session['partial_user'] = @user&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;    &lt;br /&gt;    # Might be a good addition to AR::Base&lt;br /&gt;    def valid_for_attributes( model, attributes )&lt;br /&gt;      unless model.valid?&lt;br /&gt;        errors = model.errors&lt;br /&gt;        our_errors = Array.new&lt;br /&gt;        errors.each { |attr,error|&lt;br /&gt;          if attributes.include? attr&lt;br /&gt;            our_errors &lt;&lt; [attr,error]&lt;br /&gt;          end&lt;br /&gt;        }&lt;br /&gt;        errors.clear&lt;br /&gt;        our_errors.each { |attr,error| errors.add(attr,error) }&lt;br /&gt;        return false unless errors.empty?&lt;br /&gt;      end&lt;br /&gt;      return true&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#To ensure the errors are cleared out properly on each request add a before_filter with the following:&lt;br /&gt;    def clear_stage_errors&lt;br /&gt;      unless @session['partial_user'].nil?&lt;br /&gt;        @session['partial_user'].errors.clear&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;=begin&lt;br /&gt;You can use&lt;br /&gt;get_partial_user_from_session&lt;br /&gt;and&lt;br /&gt;save_partial_user_in_session&lt;br /&gt;as before and after filters, respectively, so you only have to reference @user in your multi-step controller.&lt;br /&gt;=end&lt;br /&gt;&lt;br /&gt;#A clean way to arrange the view is to have each step in its own partial, and set a variable such as&lt;br /&gt;@current_stage&lt;br /&gt;#in your controller, then in your view just do something like:&lt;br /&gt;&lt;%= start_form_tag({:action=&gt; "signup"} , { :name =&gt; 'signupform' }) %&gt;&lt;br /&gt;&lt;%= hidden_field_tag "changeCountry" %&gt;&lt;br /&gt;&lt;%= hidden_field_tag "current_stage", "#{@current_stage}"%&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Registration Process&lt;/h2&gt;&lt;br /&gt;&lt;%= @flash['notice'] %&gt;&lt;br /&gt;&lt;br /&gt;&lt;%= render_partial "#{@current_stage}" %&gt;&lt;br /&gt; &lt;br /&gt;&lt;%= end_form_tag %&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#Your signup controller action could something similar to this:&lt;br /&gt;  def signup&lt;br /&gt;    case @request.method&lt;br /&gt;      when :post&lt;br /&gt;        @current_stage = @params['current_stage']&lt;br /&gt;        if @current_stage == "stage1"&lt;br /&gt;          @user.attributes = @params['user']    &lt;br /&gt;            @current_stage = "stage2" if valid_for_attributes(@user,["login","attribute2"])&lt;br /&gt;          end&lt;br /&gt;        elsif @current_stage == "stage2"&lt;br /&gt;          @user.attributes = @params['user']    &lt;br /&gt;          @current_stage = "stage3" if valid_for_attributes(@user,["attribute3","attribute4"])&lt;br /&gt;        elsif @current_stage == "stage3"&lt;br /&gt;          @user.attributes = @params['user']&lt;br /&gt;          &lt;br /&gt;          if @user.save&lt;br /&gt;            @session[:user] = User.authenticate(@user.login, @params['user']['password'])&lt;br /&gt;            flash['notice']  = "Signup successful"&lt;br /&gt;            redirect_to :action =&gt; "home"&lt;br /&gt;          end&lt;br /&gt;        end&lt;br /&gt;      when :get&lt;br /&gt;        @current_stage = "stage1"&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#==========================================&lt;br /&gt;=begin&lt;br /&gt;Comments on this post&lt;br /&gt;bmarini posts on May 19, 2008 at 12:56&lt;br /&gt;I took your partial validation idea and included it in AR Base&lt;br /&gt;=end&lt;br /&gt;module ActiveRecord&lt;br /&gt;  module Validations&lt;br /&gt;    module Partial&lt;br /&gt;      def valid_for_attributes?( *attr_names )&lt;br /&gt;        return validate_for_attributes(attr_names)&lt;br /&gt;      end&lt;br /&gt;      &lt;br /&gt;      def validate_for_attributes( *attr_names )&lt;br /&gt;        attr_names.map! {|a| a.to_s }&lt;br /&gt;        &lt;br /&gt;        unless valid?&lt;br /&gt;          our_errors = Array.new&lt;br /&gt;          errors.each { |attr,error|&lt;br /&gt;            if attr_names.include? attr&lt;br /&gt;              our_errors &lt;&lt; [attr,error]&lt;br /&gt;            end&lt;br /&gt;          }&lt;br /&gt;          &lt;br /&gt;          errors.clear&lt;br /&gt;          our_errors.each { |attr,error| errors.add(attr,error) }&lt;br /&gt;          return false unless errors.empty?&lt;br /&gt;        end&lt;br /&gt;        return true&lt;br /&gt;      end&lt;br /&gt;        &lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;ActiveRecord::Base.class_eval do&lt;br /&gt;  include ActiveRecord::Validations::Partial&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;=begin&lt;br /&gt;cgunther posts on Jul 02, 2009 at 11:40&lt;br /&gt;bmarini, I think there is a bug in your code.&lt;br /&gt;&lt;br /&gt;When I called:&lt;br /&gt;=end&lt;br /&gt;@order.valid_for_attributes? 'first_name', 'last_name'&lt;br /&gt;&lt;br /&gt;=begin&lt;br /&gt;It always passed validation. The error was the asterisk in front of attr_names on validate_for_attributes. It was being passed an array as the first attribute and when you run map! on it, it was converting the entire array to a single string (first_namelast_name).&lt;br /&gt;&lt;br /&gt;Here's the code that works for me:&lt;br /&gt;=end&lt;br /&gt;module ActiveRecord&lt;br /&gt;  module Validations&lt;br /&gt;    module Partial&lt;br /&gt;      def valid_for_attributes?( *attr_names )&lt;br /&gt;        return validate_for_attributes(attr_names)&lt;br /&gt;      end&lt;br /&gt;      &lt;br /&gt;      def validate_for_attributes( attr_names )&lt;br /&gt;        attr_names.map! {|a| a.to_s }&lt;br /&gt;        &lt;br /&gt;        unless valid?&lt;br /&gt;          our_errors = Array.new&lt;br /&gt;          errors.each { |attr,error|&lt;br /&gt;            if attr_names.include? attr&lt;br /&gt;              our_errors &lt;&lt; [attr,error]&lt;br /&gt;            end&lt;br /&gt;          }&lt;br /&gt;          &lt;br /&gt;          errors.clear&lt;br /&gt;          our_errors.each { |attr,error| errors.add(attr,error) }&lt;br /&gt;          return false unless errors.empty?&lt;br /&gt;        end&lt;br /&gt;        return true&lt;br /&gt;      end&lt;br /&gt;        &lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;ActiveRecord::Base.class_eval do&lt;br /&gt;  include ActiveRecord::Validations::Partial&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#The main difference is that if you call validate_for_attributes directly, you have to pass it an array.&lt;br /&gt;&lt;br /&gt;#Chris Gunther&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-4261677483739537472?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/4261677483739537472/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=4261677483739537472' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4261677483739537472'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4261677483739537472'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/02/multi-step.html' title='multi-step'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-4045441077586007527</id><published>2010-02-08T12:01:00.002+08:00</published><updated>2010-02-08T12:06:45.744+08:00</updated><title type='text'>render outside your controller</title><content type='html'>&lt;a href="http://blog.choonkeat.com/weblog/2006/08/05/"&gt;Rails: Calling render() outside your Controllers&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.compulsivoco.com/2008/10/rendering-rails-partials-in-a-model-or-background-task/"&gt;Calling Rails Render Partial in a Model or Background Task&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;# lib/render_anywhere.rb&lt;br /&gt;# &lt;br /&gt;# Render templates outside of a controller or view.&lt;br /&gt;# &lt;br /&gt;# Simply mixin this module to your existing class, for example:&lt;br /&gt;# &lt;br /&gt;#   class MyTemplater &lt; ActiveRecord::Base&lt;br /&gt;#     include RenderAnywhere&lt;br /&gt;# &lt;br /&gt;# And you can use render() method that works the same as ActionView::Base#render&lt;br /&gt;# &lt;br /&gt;#   obj = MyTemplater.new&lt;br /&gt;#   obj.html = obj.render :file =&gt; '/shared/header'&lt;br /&gt;# &lt;br /&gt;# &lt;br /&gt;module RenderAnywhere&lt;br /&gt;    &lt;br /&gt;    class DummyController&lt;br /&gt;        def logger&lt;br /&gt;            RAILS_DEFAULT_LOGGER&lt;br /&gt;        end&lt;br /&gt;        def headers&lt;br /&gt;            {}&lt;br /&gt;        end&lt;br /&gt;    end&lt;br /&gt;    &lt;br /&gt;    def render(options, assigns = {})&lt;br /&gt;        viewer = ActionView::Base.new(Rails::Configuration.new.view_path, assigns, DummyController.new)&lt;br /&gt;        viewer.render options&lt;br /&gt;    end&lt;br /&gt;    &lt;br /&gt;    def template_exists?(path, assigns = {})&lt;br /&gt;        viewer = ActionView::Base.new(Rails::Configuration.new.view_path, assigns, DummyController.new)&lt;br /&gt;        viewer.pick_template_extension(path) rescue false&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;class Page &lt; ActiveRecord::Base&lt;br /&gt;&lt;br /&gt;  def write_cache&lt;br /&gt;    self.cached_content = ActionView::Base.new(Rails::Configuration.new.view_path).render(:partial =&gt; "pages/show", :locals =&gt; {:page =&gt; self})&lt;br /&gt;    self.save&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;end&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-4045441077586007527?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/4045441077586007527/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=4045441077586007527' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4045441077586007527'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4045441077586007527'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/02/render-outside-your-controller.html' title='render outside your controller'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-2119009488116432798</id><published>2010-02-07T14:02:00.005+08:00</published><updated>2011-05-16T11:19:36.515+08:00</updated><title type='text'>Turning web server configuration</title><content type='html'>&lt;a href="http://craigjolicoeur.com/blog/setting-static-asset-expires-headers-with-nginx-and-passenger"&gt;Setting Static Asset Expires Headers with nginx and Passenger&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Nginx &lt;pre class="brush: ruby"&gt;location ~* \.(ico|css|js|gif|jpe?g|png)(\?[0-9]+)?$ {&lt;br /&gt;    expires max;&lt;br /&gt;    break;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-2119009488116432798?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/2119009488116432798/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=2119009488116432798' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2119009488116432798'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2119009488116432798'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/02/cache-in-web-server.html' title='Turning web server configuration'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-3425896331609940963</id><published>2010-02-04T12:33:00.005+08:00</published><updated>2011-05-16T11:19:11.980+08:00</updated><title type='text'>redirect permanent</title><content type='html'>&lt;a href="http://www.somacon.com/p145.php"&gt;Permanent Redirect with HTTP 301&lt;/a&gt;&lt;br /&gt;&lt;pre class="brush: ruby"&gt;&lt;br /&gt;#Apache&lt;br /&gt;    RewriteCond %{HTTP_HOST}   17\.ooxx\.com [NC]&lt;br /&gt;    RewriteRule ^/(.*)         http://17.ooxx.com.tw/$1 [L,R=permanent]&lt;br /&gt;&lt;br /&gt;#Nginx&lt;br /&gt;    if ($host ~* ^17.ooxx\.com) {&lt;br /&gt;      rewrite ^/(.*) http://17.ooxx.com.tw/$1 permanent;&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-3425896331609940963?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/3425896331609940963/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=3425896331609940963' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/3425896331609940963'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/3425896331609940963'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/02/redirect-permanent.html' title='redirect permanent'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-8857079205067744765</id><published>2010-02-03T14:26:00.002+08:00</published><updated>2010-02-03T14:29:26.814+08:00</updated><title type='text'>META HTTP-EQUIV="refresh" 實現網頁自動跳轉</title><content type='html'>&lt;a href="http://www.haishui.net/view.php?tid=20&amp;id=739"&gt;META HTTP-EQUIV="refresh" 實現網頁自動跳轉&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;textarea name="code" class="html"&gt;&lt;br /&gt;&lt; meta http-equiv="Refresh" content="秒數; url=跳轉的文件或地址" &gt; &lt;br /&gt;&lt;br /&gt;&lt; head &gt; &lt;br /&gt;   &lt; meta http-equiv="Refresh" content="3;url=http://www.haishui.net"&gt;&lt;br /&gt;&lt; /head &gt; &lt;br /&gt;&lt;br /&gt;多個內容相似而背景不同的頁面，讓其每隔一定時間自動相互跳轉。 &lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-8857079205067744765?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/8857079205067744765/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=8857079205067744765' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8857079205067744765'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8857079205067744765'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/02/meta-http-equivrefresh.html' title='META HTTP-EQUIV=&quot;refresh&quot; 實現網頁自動跳轉'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-2777608611228608848</id><published>2010-02-02T17:09:00.001+08:00</published><updated>2010-02-02T17:09:59.674+08:00</updated><title type='text'>rails default environment</title><content type='html'>~/.bashrc&lt;br /&gt;&lt;br /&gt;export PATH=$PATH:/opt/ruby-enterprise/bin&lt;br /&gt;export RAILS_ENV=production&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-2777608611228608848?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/2777608611228608848/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=2777608611228608848' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2777608611228608848'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2777608611228608848'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/02/rails-default-environment.html' title='rails default environment'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-1170682400833492085</id><published>2010-02-02T07:26:00.007+08:00</published><updated>2011-05-16T11:18:21.538+08:00</updated><title type='text'>nginx memo</title><content type='html'>&lt;a href="http://www.v-ec.com/dh20156/article.asp?id=263"&gt;Nginx泛域名解析及Rewrite重定向普通頁面及帶參數的頁面 &lt;/a&gt;&lt;br /&gt;&lt;a href="https://calomel.org/nginx.html"&gt;Nginx "how to" - Fast and Secure Web Server&lt;/a&gt;&lt;br /&gt;&lt;a href="http://wiki.nginx.org/NginxHttpCoreModule#location"&gt;Nginx Location&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;靜態地址重定向到帶參數的動態地址&lt;pre class="brush: ruby"&gt;rewrite "^(.*)/service/(.*)\.html$" $1/service.php?sid=$2 permanent;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;帶參數的動態地址重定向到靜態地址&lt;pre class="brush: ruby"&gt;if ($query_string ~* id=(.*)) {&lt;br /&gt;    set $id $1;&lt;br /&gt;    rewrite "^(.*)/article.asp$" $1/article/$id.htm last;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;舉例:&lt;br /&gt;abc.domian.com/sort/2 =&gt; abc.domian.com/index.php?act=sort&amp;name=abc&amp;id=2&lt;br /&gt;&lt;pre class="brush: ruby"&gt;&lt;br /&gt;if ($host ~* (.*)\.domain\.com) {&lt;br /&gt;    set $sub_name $1;&lt;br /&gt;    rewrite ^/sort\/(\d+)\/?$ /index.php?act=sort&amp;cid=$sub_name&amp;id=$1 last;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Nginx Rewrite Flags&lt;br /&gt;* last 相當於Apache裡的[L]標記，表示完成rewrite&lt;br /&gt;* break 終止匹配, 不再匹配後面的規則&lt;br /&gt;* redirect 返回302臨時重定向&lt;br /&gt;* permanent 返回301永久重定向&lt;br /&gt;&lt;br /&gt;Nginx正則表達式匹配&lt;br /&gt;* ~ 為區分大小寫匹配&lt;br /&gt;* ~* 為不區分大小寫匹配&lt;br /&gt;* !~和!~*分別為區分大小寫不匹配及不區分大小寫不匹配&lt;br /&gt;&lt;br /&gt;Nginx文件及目錄匹配&lt;br /&gt;* -f和!-f用來判斷是否存在文件&lt;br /&gt;* -d和!-d用來判斷是否存在目錄&lt;br /&gt;* -e和!-e用來判斷是否存在文件或目錄&lt;br /&gt;* -x和!-x用來判斷文件是否可執行&lt;br /&gt;&lt;br /&gt;Nginx全局變量&lt;br /&gt;$args&lt;br /&gt;$content_length&lt;br /&gt;$content_type&lt;br /&gt;$document_root&lt;br /&gt;$document_uri&lt;br /&gt;$host&lt;br /&gt;$http_user_agent&lt;br /&gt;$http_cookie&lt;br /&gt;$limit_rate&lt;br /&gt;$request_body_file&lt;br /&gt;$request_method&lt;br /&gt;$remote_addr&lt;br /&gt;$remote_port&lt;br /&gt;$remote_user&lt;br /&gt;$request_filename&lt;br /&gt;$request_uri&lt;br /&gt;$query_string&lt;br /&gt;$scheme&lt;br /&gt;$server_protocol&lt;br /&gt;$server_addr&lt;br /&gt;$server_name&lt;br /&gt;$server_port&lt;br /&gt;$uri&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-1170682400833492085?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/1170682400833492085/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=1170682400833492085' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1170682400833492085'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1170682400833492085'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/02/nginx-memo.html' title='nginx memo'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-3692982311902663401</id><published>2010-02-01T14:15:00.002+08:00</published><updated>2011-05-16T11:15:20.704+08:00</updated><title type='text'>restart nginx</title><content type='html'>&lt;pre class="brush: ruby"&gt; &lt;br /&gt;alias startnginx='sudo /opt/nginx/sbin/nginx' &lt;br /&gt;alias stopnginx='sudo kill `cat /opt/nginx/logs/nginx.pid `' &lt;br /&gt;alias restartnginx='stopnginx; startnginx' &lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-3692982311902663401?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/3692982311902663401/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=3692982311902663401' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/3692982311902663401'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/3692982311902663401'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/02/restart-nginx.html' title='restart nginx'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-763553219444031775</id><published>2010-02-01T12:12:00.004+08:00</published><updated>2010-02-01T12:19:55.473+08:00</updated><title type='text'>transcation</title><content type='html'>&lt;a href="http://tempe.st/2007/05/transaction-in-rails/"&gt;Transaction in Rails&lt;/a&gt;&lt;br /&gt;&lt;a href="http://rpheath.com/posts/124-working-with-transactions-in-rails"&gt;Working with transactions in Rails&lt;/a&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;transaction do&lt;br /&gt;  first.save!&lt;br /&gt;  second.save!&lt;br /&gt;  third.save!&lt;br /&gt;  fourth.save!&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;  Course.transaction do&lt;br /&gt;    @course.save!&lt;br /&gt;    read_directory(@course.folder_title).each do |f|&lt;br /&gt;      lo = LearningObject.new&lt;br /&gt;      lo.course_id, lo.title = @course.id, f.gsub('_',' ')&lt;br /&gt;      lo.save!&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-763553219444031775?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/763553219444031775/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=763553219444031775' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/763553219444031775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/763553219444031775'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/02/transcation.html' title='transcation'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-1118150753032461510</id><published>2010-01-29T17:28:00.006+08:00</published><updated>2011-05-16T11:20:40.532+08:00</updated><title type='text'>ssl apache nginx configuration</title><content type='html'>http://articles.slicehost.com/2010/1/11/managing-ssl-certificates-1&lt;br /&gt;http://articles.slicehost.com/2010/1/11/managing-ssl-certificates-2&lt;br /&gt;&lt;a href="http://blog.mobile01.com/ryanlai/article/811"&gt;Nginx SSL 實務&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.digicert.com/ssl-certificate-installation-nginx.htm"&gt;SSL Certificate Installation in Nginx&lt;/a&gt;&lt;br /&gt;&lt;a href="http://nginx.org/en/docs/http/configuring_https_servers.html"&gt;Configuring HTTPS servers&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;ssl 設定的file 有三種  伺服器憑證, 中繼憑證, RSA key &lt;br /&gt;各種web server 吃的方式不同&lt;br /&gt;&lt;br /&gt;Nginx 設定&lt;br /&gt;&lt;pre class="brush: ruby"&gt;&lt;br /&gt;&lt;br /&gt;listen  ip.address:443; #監聽HTTPS, 通常是Port 443&lt;br /&gt;ssl  on;&lt;br /&gt;ssl_certificate  /path/to/server.crt; &lt;br /&gt;ssl_certificate_key  /path/to/private.key; #這是伺服器用的RSA Key&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#server.crt要用發下來的伺服器憑證與中繼憑證合併產生:&lt;br /&gt;cat domain_name.crt ca_bundle.crt  &gt; server.cr&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="brush: ruby"&gt;&lt;br /&gt;SSLCertificateFile /etc/ssl/apache_ca.crt      #這是伺服器憑證&lt;br /&gt;SSLCertificateKeyFile /etc/ssl/www.goyou.com.tw.key   &lt;br /&gt;SSLCertificateChainFile /etc/ssl/chain.crt    #中繼憑證&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-1118150753032461510?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/1118150753032461510/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=1118150753032461510' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1118150753032461510'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1118150753032461510'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/01/ssl.html' title='ssl apache nginx configuration'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-2050964123722208729</id><published>2010-01-28T11:24:00.007+08:00</published><updated>2011-05-16T11:21:10.331+08:00</updated><title type='text'>nginx , page cache, capistrano</title><content type='html'>&lt;a href="http://blog.hasmanythrough.com/2008/1/30/segregated-page-cache-storage"&gt;Segregated page cache storage&lt;/a&gt;&lt;br /&gt;&lt;a href="https://wincent.com/blog/rails-page-caching-vs-nginx"&gt;Rails page caching vs nginx Restful route 可能會造成有相同的html, like index and create, 所以利用nginx 做一些檢查來避免&lt;/a&gt; &lt;br /&gt;&lt;a href="http://stackoverflow.com/questions/1177979/nginx-rewrite-rules-with-passenger"&gt;nginx rewrite rules with Passenger&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: ruby"&gt;if (-f $request_filename) {&lt;br /&gt;  break;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;# cached pages&lt;br /&gt;#set $cache_extension '';&lt;br /&gt;#if ($request_method = GET) {&lt;br /&gt;#  set $cache_extension '.html';&lt;br /&gt;#}&lt;br /&gt;&lt;br /&gt;# the above is a hack because nginx doesn't allow nested or ANDed ifs&lt;br /&gt;#if (-f $request_filename$cache_extension) {&lt;br /&gt;#  rewrite (.*) $1.html break;&lt;br /&gt;#}&lt;br /&gt;&lt;br /&gt;# 這個才有用 上面那些都沒用 orz, 用$uri 才有用&lt;br /&gt;if (-f $document_root/cache/$uri/index.html) {&lt;br /&gt;  rewrite (.*) /cache/$1/index.html break;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;if (-f $document_root/cache/$uri.html) {&lt;br /&gt;  rewrite (.*) /cache/$1.html break;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# everything else goes to the mongrel cluster&lt;br /&gt;if (!-f $request_filename) {&lt;br /&gt;  proxy_pass http://mongrels;&lt;br /&gt;  break;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: ruby"&gt;#In config/environments/production.rb, tell Rails to put cached pages in the public/cache directory.&lt;br /&gt;&lt;br /&gt;config.action_controller.page_cache_directory = File.join(RAILS_ROOT, 'public', 'cache')&lt;br /&gt;&lt;br /&gt;#In nginx.conf, set up the precedence for locating static files. First look in public for regular static files. Next look in the cache directory for an exact match for the url. Lastly, look in the cache directory for the url with .html appended. That will let you cache pages for regular URLs with no .html extension as well as ones with extensions like .xml, .atom, .json, etc.&lt;br /&gt;&lt;br /&gt;  if (-f $request_filename) { &lt;br /&gt;    break; &lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;#  if (-f /cache$request_filename) { &lt;br /&gt;#    rewrite (.*) /cache$1 break;&lt;br /&gt;#    break; &lt;br /&gt;#  }&lt;br /&gt;&lt;br /&gt;#  if (-f /cache$request_filename.html) { &lt;br /&gt;#    rewrite (.*) /cache$1.html break;&lt;br /&gt;#    break; &lt;br /&gt;#  }&lt;br /&gt;&lt;br /&gt;#The capistrano recipes have to do a couple things. You need to create the shared/cache directory when setting up the deployment.&lt;br /&gt;&lt;br /&gt;after "deploy:setup", "create_page_cache"&lt;br /&gt;task :create_page_cache, :roles =&gt; :app do&lt;br /&gt;  run "umask 02 &amp;&amp; mkdir -p #{shared_path}/cache"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;after "deploy:update_code","symlink_shared_dirs"&lt;br /&gt;task :symlink_shared_dirs, :roles =&gt; :app, :except =&gt; {:no_release =&gt; true, :no_symlink =&gt; true} do&lt;br /&gt;    run &lt;&lt;-CMD&lt;br /&gt;      cd #{release_path} &amp;&amp;&lt;br /&gt;      ln -nfs #{shared_path}/cache #{release_path}/public/cache&lt;br /&gt;    CMD&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#When doing a deploy, the standard behavior is to flush the cache, just to be on the safe side. If you want to retain cached pages, as when making a change you know won't affect rendering, tell capistrano not to flush.&lt;br /&gt;&lt;br /&gt;# default behavior is to flush page cache on deploy&lt;br /&gt;set :flush_cache, true&lt;br /&gt;&lt;br /&gt;# page cache management&lt;br /&gt;task :keep_page_cache do&lt;br /&gt;  set :flush_cache, false&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;after "deploy:cleanup", "flush_page_cache"&lt;br /&gt;task :flush_page_cache, :roles =&gt; :app do&lt;br /&gt;  if flush_cache&lt;br /&gt;    run &lt;&lt;-CMD&lt;br /&gt;      rm -rf #{shared_path}/cache/*&lt;br /&gt;    CMD&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#With the above setup, you can deploy and retain the cache with the following capistrano command:&lt;br /&gt;$ cap keep_page_cache deploy&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-2050964123722208729?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/2050964123722208729/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=2050964123722208729' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2050964123722208729'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2050964123722208729'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/01/nginx-page-cache-capistrano.html' title='nginx , page cache, capistrano'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-3341570153792085270</id><published>2010-01-08T16:11:00.002+08:00</published><updated>2010-01-08T16:27:04.844+08:00</updated><title type='text'>Moneta, memcache</title><content type='html'>&lt;a href="http://ihower.tw/blog/archives/3420"&gt;Moneta: 提供 key/value stores 的統一介面&lt;/a&gt;&lt;br /&gt;&lt;a href="http://github.com/wycats/moneta/"&gt;moneta github&lt;/a&gt;&lt;br /&gt;&lt;a href="http://github.com/ihower/handcache"&gt;handcache github&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;#config/environment.rb&lt;br /&gt;begin&lt;br /&gt;  CacheStore = Moneta::Memcache.new(:server =&gt; "127.0.0.1")&lt;br /&gt;rescue&lt;br /&gt;  CacheStore = Moneta::BasicFile.new(:path =&gt; "tmp")&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#lib/handcache.rb&lt;br /&gt;#handcache lib&lt;br /&gt;&lt;br /&gt;#controller&lt;br /&gt;@user = Handcache.get_and_set("first-user", :expires_in =&gt; 30) do&lt;br /&gt;   User.first.inspect&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#view&lt;br /&gt;&lt;%= Handcache.get_and_set( dom_id(@post), :expires_in =&gt; 60 ) do&lt;br /&gt;               render :partial =&gt; "post"&lt;br /&gt;end %&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-3341570153792085270?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/3341570153792085270/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=3341570153792085270' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/3341570153792085270'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/3341570153792085270'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/01/moneta-memcache.html' title='Moneta, memcache'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-1929855736527159347</id><published>2010-01-05T00:14:00.003+08:00</published><updated>2010-01-05T00:15:52.150+08:00</updated><title type='text'>heroku 上 你要 它卻沒有的gem</title><content type='html'>&lt;a href="http://tammersaleh.com/posts/automatically-generate-heroku-gems-file"&gt;Automatically generate Heroku .gems file&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;用個rake 幫你生這個file&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;namespace :gems do&lt;br /&gt;  desc "Generate .gems file for Heroku"&lt;br /&gt;  task :heroku_spec =&gt; :environment do&lt;br /&gt;    require 'open-uri'&lt;br /&gt;    installed_gems = []&lt;br /&gt;    url = "http://installed-gems.heroku.com/"&lt;br /&gt;    open(url).read.scan(/&lt;li&gt;(\w+) [^&lt;]*&lt;\/li&gt;/) do |w| &lt;br /&gt;      installed_gems &lt;&lt; w.first&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    gems = Rails.configuration.gems&lt;br /&gt;    &lt;br /&gt;    # output .gems&lt;br /&gt;    dot_gems = File.join(RAILS_ROOT, ".gems")&lt;br /&gt;    File.open(dot_gems, "w") do |f|&lt;br /&gt;      output = []&lt;br /&gt;      gems.each do |gem|&lt;br /&gt;        next if installed_gems.include?(gem.name)&lt;br /&gt;        spec = "#{gem.name} --version '#{gem.version_requirements.to_s}'"&lt;br /&gt;        spec &lt;&lt; " --source #{gem.source}" if gem.source&lt;br /&gt;        output &lt;&lt; spec&lt;br /&gt;      end&lt;br /&gt;      f.write output.join("\n")&lt;br /&gt;      puts output.join("\n")&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-1929855736527159347?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/1929855736527159347/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=1929855736527159347' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1929855736527159347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1929855736527159347'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2010/01/heroku-gem.html' title='heroku 上 你要 它卻沒有的gem'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-8207952763290460532</id><published>2009-12-31T16:49:00.004+08:00</published><updated>2009-12-31T17:17:13.509+08:00</updated><title type='text'>Changing Your Origin</title><content type='html'>&lt;a href="http://github.com/guides/changing-your-origin"&gt;Changing Your Origin&lt;/a&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;# 增加遠端 Repository 的 branch(origin -&gt; project)&lt;br /&gt;git remote add new-branch http://git.example.com.tw/project.git &lt;/textarea&gt;&lt;textarea name="code" class="ruby"&gt;# 這個動作才是有把遠端的repository 跟 local 綁起來, 而且一定要利用 -b 來新建 branch&lt;br /&gt;# 抓取 new-branch, 並將此 branch 建立於 local 的 reps-branch&lt;br /&gt;git checkout --track -b reps-branch new-branch &lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;目前這樣只到可以pull的地步&lt;br /&gt;&lt;br /&gt;但是如果需要push 到不同的remote 端 還需要修改 .git/config&lt;br /&gt;需要補上push 的部份&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;#just sample &lt;br /&gt;[core]&lt;br /&gt;        repositoryformatversion = 0&lt;br /&gt;        filemode = true&lt;br /&gt;        bare = false&lt;br /&gt;        logallrefupdates = true&lt;br /&gt;[remote "public"]&lt;br /&gt;        url = git+ssh://repo.or.cz/srv/git/myproject.git&lt;br /&gt;        fetch = +refs/heads/*:refs/remotes/public/*&lt;br /&gt;        push = refs/heads/master:refs/heads/master&lt;br /&gt;[remote "github"]&lt;br /&gt;        url = git@github.com:username/myproject.git&lt;br /&gt;        fetch = +refs/heads/*:refs/remotes/github/*&lt;br /&gt;        push = refs/heads/*:refs/heads/*&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-8207952763290460532?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/8207952763290460532/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=8207952763290460532' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8207952763290460532'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8207952763290460532'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/12/changing-your-origin.html' title='Changing Your Origin'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-3950781025497101371</id><published>2009-12-16T17:40:00.002+08:00</published><updated>2009-12-16T17:41:11.584+08:00</updated><title type='text'>fb comment</title><content type='html'>FBML 和 XFBML 不同阿 小心 orz&lt;br /&gt;&lt;br /&gt;http://wiki.developers.facebook.com/index.php/Fb:comments&lt;br /&gt;http://wiki.developers.facebook.com/index.php/Fb:comments_(XFBML)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-3950781025497101371?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/3950781025497101371/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=3950781025497101371' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/3950781025497101371'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/3950781025497101371'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/12/fb-comment.html' title='fb comment'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-7561434443420331973</id><published>2009-12-08T10:59:00.002+08:00</published><updated>2009-12-08T11:30:55.619+08:00</updated><title type='text'>write rails plugin memo</title><content type='html'>&lt;a href="http://guides.rubyonrails.org/plugins.html"&gt;The Basic of Creating Rails Plugins&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;3 Extending Core Classes&lt;/span&gt;&lt;br /&gt;This section will explain how to add a method to String that will be available anywhere in your rails app.&lt;br /&gt;&lt;br /&gt;http://guides.rubyonrails.org/plugins.html#extending-core-classes&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-7561434443420331973?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/7561434443420331973/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=7561434443420331973' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/7561434443420331973'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/7561434443420331973'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/12/write-rails-plugin-memo.html' title='write rails plugin memo'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-319229120590247260</id><published>2009-12-03T15:04:00.003+08:00</published><updated>2009-12-03T15:38:11.964+08:00</updated><title type='text'>Paginating with the Fragment Cache</title><content type='html'>&lt;a href="http://railsenvy.com/2007/3/20/ruby-on-rails-caching-tutorial-part-2#fragmentpaginating,"&gt;Paginating with the Fragment Cache&lt;/a&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt; # Cache Controller&lt;br /&gt; def count&lt;br /&gt;   unless read_fragment({:page =&gt; params[:page] || 1})&lt;br /&gt;      @recommends = Recommend.paginate(:all , :group =&gt; 'stock' , :select =&gt; 'stock,count(id) as count' , :order =&gt; 'count(id) DESC' , :page =&gt; params[:page] ,  :per_page =&gt; 8)&lt;br /&gt;   end&lt;br /&gt; end&lt;br /&gt; &lt;br /&gt; def expire&lt;br /&gt;   expire_fragment(%r{cache/count.*})&lt;br /&gt; end &lt;br /&gt;&lt;br /&gt; # View count.html.erb&lt;br /&gt; &lt;% cache({:page =&gt; params[:page] || 1}) do %&gt;&lt;br /&gt;   //View HTML&lt;br /&gt; &lt;% end %&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;Another notable way we can clear out not only our Action Cache and Fragment cache is to run the following rake task:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;rake tmp:cache:clear&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-319229120590247260?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/319229120590247260/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=319229120590247260' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/319229120590247260'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/319229120590247260'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/12/paginating-with-fragment-cache.html' title='Paginating with the Fragment Cache'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-8988880017972584412</id><published>2009-12-03T14:15:00.003+08:00</published><updated>2009-12-03T14:20:37.357+08:00</updated><title type='text'>group count</title><content type='html'>&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;#Recommend(id: integer, stock: integer, be_recommend_user_facebook_id: string, message: string, recommend_us)&lt;br /&gt;&lt;br /&gt;#&lt;br /&gt;  @recommends = Recommend.paginate(:all , :group =&gt; 'stock' , :select =&gt; 'stock,count(id) as count' , :order =&gt; 'count(id) DESC' , :page =&gt; params[:page] ,  :per_page =&gt; 8)&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-8988880017972584412?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/8988880017972584412/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=8988880017972584412' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8988880017972584412'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8988880017972584412'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/12/group-count.html' title='group count'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-9120867564755887294</id><published>2009-11-29T11:30:00.001+08:00</published><updated>2009-11-29T11:32:21.689+08:00</updated><title type='text'>fbml in iframe canvas by serverfbml</title><content type='html'>&lt;a href="http://wiki.developers.facebook.com/index.php/Fb:serverfbml"&gt;Fb:serverfbml&lt;/a&gt;&lt;br /&gt;&lt;textarea name="code" class="javascript"&gt;&lt;br /&gt;&lt;fb:serverfbml style="width: 755px;"&gt;&lt;br /&gt;&lt;script type="text/fbml"&gt;&lt;br /&gt;  &lt;fb:fbml&gt;&lt;br /&gt;  &lt;fb:board xid="123"&gt;&lt;br /&gt;  &lt;/fb:board&gt;&lt;br /&gt;  &lt;/fb:fbml&gt;&lt;br /&gt;&lt;/script&gt;&lt;br /&gt;&lt;/fb:serverfbml&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-9120867564755887294?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/9120867564755887294/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=9120867564755887294' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/9120867564755887294'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/9120867564755887294'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/11/fbml-in-iframe-canvas-by-serverfbml.html' title='fbml in iframe canvas by serverfbml'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-7235223367466280451</id><published>2009-11-29T06:41:00.003+08:00</published><updated>2009-11-29T06:56:22.910+08:00</updated><title type='text'>Resizable IFrame</title><content type='html'>&lt;a href="http://wiki.developers.facebook.com/index.php/Resizable_IFrame"&gt;Resizable IFrame&lt;/a&gt;&lt;br /&gt;&lt;a href="http://wiki.developers.facebook.com/index.php/JavaScript_Client_Library"&gt;JavaScript Client Library&lt;/a&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Note&lt;/span&gt;: You must include the &lt;[script]&gt; tag that loads the FeatureLoader in the &lt;[body]&gt; element, not in the &lt;[head]&gt; element, because the FeatureLoader writes body elements directly to the document, and some browsers report an error if this happens when FeatureLoader is in the &lt;[head]&gt; tag.&lt;br /&gt;&lt;a href="http://wiki.developers.facebook.com/index.php/Cross_Domain_Communication_Channel"&gt;http://wiki.developers.facebook.com/index.php/Cross_Domain_Communication_Channel&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;textarea name="code" class="javascript"&gt;&lt;br /&gt;&lt;[body]&gt;&lt;br /&gt;&lt;!-- Note: Include this div markup as a workaround for a known bug in this release on IE where you may get a "operation aborted" error --&gt; &lt;br /&gt;&lt;[div id="FB_HiddenIFrameContainer" style="display:none; position:absolute; left:-100px; top:-100px; width:0px; height: 0px;"]&gt;&lt;[/div]&gt;&lt;br /&gt;&lt;br /&gt;  &lt;[script src="http://static.ak.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php" type="text/javascript"&gt;&lt;/script]&gt;&lt;br /&gt;  &lt;[script type="text/javascript"]&gt;&lt;br /&gt;    FB_RequireFeatures(["CanvasUtil"], function(){&lt;br /&gt;        FB.XdComm.Server.init("&lt;%= FACEBOOKER['callback_url']%&gt;/xd_receiver.htm");&lt;br /&gt;        FB.CanvasClient.startTimerToSizeToContent();&lt;br /&gt;  });&lt;br /&gt;&lt;[/script]&gt;&lt;br /&gt;&lt;[/body]&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-7235223367466280451?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/7235223367466280451/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=7235223367466280451' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/7235223367466280451'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/7235223367466280451'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/11/resizable-iframe.html' title='Resizable IFrame'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-637786403712644757</id><published>2009-11-22T21:01:00.009+08:00</published><updated>2011-05-15T14:02:43.266+08:00</updated><title type='text'>rjs page call</title><content type='html'>&lt;a href="http://railsforum.com/viewtopic.php?id=33181"&gt;RJS Page.call&lt;/a&gt;&lt;br /&gt;&lt;a href="http://stackoverflow.com/questions/1215797/passing-objects-from-rails-rjs-to-&lt;br /&gt;a-javascript-function-call-without-quoting-the"&gt;Passing objects from Rails RJS to a javascript function call without quoting the values?&lt;/a&gt;&lt;br /&gt;&lt;a href="http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper/JavaScriptGenerator/GeneratorMethods.html"&gt;http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper/JavaScriptGenerator/GeneratorMethods.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: ruby"&gt; &lt;br /&gt;#有些時候page.call paramter work 不是很正常&lt;br /&gt;page.call "get_details", "info-id", "message","{phone:5487895, mobile:9888565875}"&lt;br /&gt;page.call("buildYUITreeView", "project_tree", @current_project.get_directory_contents(@current_project.local_path, 0))&lt;br /&gt;#可以用這樣的方式去取代&lt;br /&gt;page &lt;&lt; "get_details('info-id','message','{phone:5487895, mobile:9888565875}')"&lt;br /&gt;page &lt;&lt; "buildUYITreeView('project_tree', #{@current_project.get_directory_contents(@current_project.local_path, 0))})"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;      respond_to do |format|&lt;br /&gt;        format.js {render(:update) { |page| page &lt;&lt; 'alert("Wrong Nick");'}}&lt;br /&gt;      end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  update_page do |page|&lt;br /&gt;    page.insert_html :bottom, 'list', "&lt;li&gt;#{@item.name}&lt;/li&gt;"&lt;br /&gt;    page.visual_effect :highlight, 'list'&lt;br /&gt;    page.hide 'status-indicator', 'cancel-link'&lt;br /&gt;  end&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-637786403712644757?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/637786403712644757/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=637786403712644757' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/637786403712644757'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/637786403712644757'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/11/rjs-page-call.html' title='rjs page call'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-8287405397844006143</id><published>2009-11-17T12:55:00.002+08:00</published><updated>2009-11-17T12:57:47.542+08:00</updated><title type='text'>Problem updating to Rubygems 1.3.5</title><content type='html'>更新又失敗了&lt;br /&gt;&lt;br /&gt;直接用source 裝吧&lt;br /&gt;&lt;br /&gt;http://railsforum.com/viewtopic.php?id=34044     &lt;= Problem&lt;br /&gt;http://docs.rubygems.org/read/chapter/3 &lt;= install rubygem&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-8287405397844006143?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/8287405397844006143/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=8287405397844006143' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8287405397844006143'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8287405397844006143'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/11/problem-updating-to-rubygems-135.html' title='Problem updating to Rubygems 1.3.5'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-4684574280808550192</id><published>2009-11-16T10:03:00.003+08:00</published><updated>2009-11-16T10:07:16.671+08:00</updated><title type='text'>facebook iframe use fbml</title><content type='html'>http://wiki.developers.facebook.com/index.php/Fb_force_mode&lt;br /&gt;&lt;br /&gt;除了用xfbml之外, 還有這招可以用&lt;br /&gt;&lt;br /&gt;For example, if you were using an iframe application, and wanted one page to be rendered as FBML, you could append ?fb_force_mode=fbml to the address, which will cause it to render as FBML. This can be particularly useful when using fb:request-form with iframe applications.&lt;br /&gt;&lt;br /&gt;If your application is an iframe application and you wish to use FBML, you will need to specify the full address, including http://apps.facebook.com.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-4684574280808550192?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/4684574280808550192/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=4684574280808550192' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4684574280808550192'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4684574280808550192'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/11/iframe-use-fbml.html' title='facebook iframe use fbml'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-5514077144564516299</id><published>2009-11-15T20:06:00.003+08:00</published><updated>2009-11-15T20:24:25.325+08:00</updated><title type='text'>include vs joins</title><content type='html'>http://railscasts.com/episodes/181-include-vs-joins&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;User.all(:joins =&gt; :comments, :select =&gt; "users.*, count(comments.id) as comments_count", :group =&gt; "users.id")&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;g = Group.first&lt;br /&gt;Comment.all(:joins =&gt; {:user =&gt; :memberships}, :conditions =&gt; { :memberships =&gt; { :group_id =&gt; g.id } })&lt;br /&gt;&lt;br /&gt;# models/comment.rb&lt;br /&gt;class Comment &lt; ActiveRecord::Base&lt;br /&gt;  belongs_to :user&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# models/user.rb&lt;br /&gt;class User &lt; ActiveRecord::Base&lt;br /&gt;  has_many :memberships&lt;br /&gt;  has_many :groups, :through =&gt; :memberships&lt;br /&gt;  has_many :comments&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# models/membership.rb&lt;br /&gt;class Membership &lt; ActiveRecord::Base&lt;br /&gt;  belongs_to :user&lt;br /&gt;  belongs_to :group&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# models/group.rb&lt;br /&gt;class Group &lt; ActiveRecord::Base&lt;br /&gt;  has_many :memberships&lt;br /&gt;  has_many :users, :through =&gt; :memberships&lt;br /&gt;  #rails does not support nested association&lt;br /&gt;&lt;br /&gt;  def comments&lt;br /&gt;    Comment.scoped(:joins =&gt; {:user =&gt; :memberships}, :conditions =&gt; { :memberships =&gt; { :group_id =&gt; id } })&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-5514077144564516299?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/5514077144564516299/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=5514077144564516299' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/5514077144564516299'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/5514077144564516299'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/11/include-vs-joins.html' title='include vs joins'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-1688549222979967627</id><published>2009-11-13T14:56:00.002+08:00</published><updated>2009-11-13T14:58:39.626+08:00</updated><title type='text'>dynamic asset_host</title><content type='html'>&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;       ActionController::Base.asset_host = Proc.new { |source|&lt;br /&gt;         "http://assets#{rand(2) + 1}.example.com"&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;        ActionController::Base.asset_host = Proc.new { |source|&lt;br /&gt;          if source.starts_with?('/images')&lt;br /&gt;            "http://images.example.com"&lt;br /&gt;          else&lt;br /&gt;            "http://assets.example.com"&lt;br /&gt;          end&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;       ActionController::Base.asset_host = Proc.new { |source, request|&lt;br /&gt;         if request.ssl?&lt;br /&gt;           "#{request.protocol}#{request.host_with_port}"&lt;br /&gt;         else&lt;br /&gt;           "#{request.protocol}assets.example.com"&lt;br /&gt;         end&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-1688549222979967627?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/1688549222979967627/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=1688549222979967627' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1688549222979967627'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1688549222979967627'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/11/dynamic-assethost.html' title='dynamic asset_host'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-8736937362016511766</id><published>2009-11-13T09:50:00.008+08:00</published><updated>2010-07-03T11:26:59.612+08:00</updated><title type='text'>google seo memo</title><content type='html'>&lt;a href="http://googlewebmastercentral.blogspot.com/2008/11/googles-seo-starter-guide.html"&gt;Google SEO Starter Guide&lt;/a&gt;&lt;br /&gt;&lt;a href="http://github.com/kpumuk/meta-tags"&gt;github meta tag plugin&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;1. title&lt;br /&gt;&lt;[title]&gt; 標記應該放在 HTML 文件的 &lt;[head]&gt; 標記區段中。&lt;br /&gt;理想情況下,您應該為網站的每一個網頁建立獨特的網頁標題&lt;br /&gt;&lt;br /&gt;您的文件出現在搜尋結果網頁中,標題標記的內容通常會出現在搜尋結果的第一行&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;2. meta desc&lt;br /&gt;Google 網站管理員工具」提供了好用的&lt;a href="http://googlewebmastercentral.blogspot.com/2007/12/new-content-analysis-and-sitemap.html"&gt;內容分析工具&lt;/a&gt;,可以指出太短、太長或過分重複的描述中繼標記使用簡短但描述明確的標題&lt;br /&gt;&lt;br /&gt;&lt;a href="http://googlewebmastercentral.blogspot.com/2007/09/improve-snippets-with-meta-description.html"&gt;improve-snippets-with-meta-description&lt;/a&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;3. 有意義的url&lt;br /&gt;http://www.google.com/support/webmasters/bin/answer.py?answer=76329&lt;br /&gt;  在網址中使用文字&lt;br /&gt;  建立簡單的目錄架構 &lt;br /&gt;  為同一文件提供同一版本的網址&lt;br /&gt;&lt;br /&gt;如果您確實發現有使用者透過不同的網址來瀏覽同樣的內容,您可以設定 301 重新導向,將不喜歡的網址重新導向到您所期望使用的網址&lt;br /&gt;&lt;br /&gt;請避免:&lt;br /&gt;     無論從子域還是根目錄 (例如「domain.com/page.htm」和「sub.domain.com/page.htm」) 都可以瀏覽到相同的內容&lt;br /&gt;     在您的內部連結架構中混合使用 www. 和非 www. 版本的網址&lt;br /&gt;     在網址中使用奇怪的大寫字母 (大部分使用者喜歡小寫的網址,並且小寫也便於使用者記憶)&lt;br /&gt;&lt;br /&gt;4. 讓您的網站更易於瀏覽&lt;br /&gt;&lt;br /&gt;您也可以使用 Google 的「&lt;a href="https://www.google.com/webmasters/tools/home?hl=zh-TW"&gt;網站管理員工具&lt;/a&gt;」提交 XML Sitemap (字母大寫),讓 Google 更容易發現您網站上的網頁。使用 Sitemap 還有一個好處 (雖然我們無法做出保證),就是您可以使用它來告知Google 哪個版本的網址是您偏好的標準網址 (例如:http://brandonsbaseballcards.com/ 或http://www.brandonsbaseballcards.com/;請瀏覽更多關於什麼是偏好網域的詳情)。Google 協助建立了開放原始碼的 Sitemap 產生器指令碼,以幫助您為自己的網站建立 Sitemap 檔案。如需有關Sitemap 的進一步資訊,請前往網站管理員說明中心,瀏覽實用的 Sitemap 檔案指南。&lt;br /&gt;&lt;br /&gt;5. 網站導覽實作典範&lt;br /&gt;&lt;br /&gt;建立自然流暢的層級架構&lt;br /&gt;請避免:&lt;br /&gt;     建立複雜的導覽連結網。例如,將網站上都每個網頁都連結至所有其他網頁&lt;br /&gt;     過度細分內容 (使用者必須要按二十次才能找到位於深層的內容)&lt;br /&gt;&lt;br /&gt;導覽中盡量使用文字連結&lt;br /&gt;請避免:&lt;br /&gt;     完全依靠下拉功能表、圖片或動畫來建立導覽 (雖然大多數搜尋引擎能夠發現&lt;br /&gt;     網站的此類連結,但如果讓使用者能透過正常文字連結到達網站上的所有網頁,&lt;br /&gt;     將可以提高網站的可用性;請瀏覽更多關於 Google 如何處理非文字檔案的&lt;br /&gt;     詳情)&lt;br /&gt;&lt;br /&gt;使用「麵包屑」導覽 — 麵包屑導覽是指在網頁頂端或底部放置一排內部連結,讓訪客可以&lt;br /&gt;  快速回到上一個網頁或根網頁。大多數的麵包屑導覽通常會將最具概括性的網頁 (通常是根網&lt;br /&gt;  頁) 放在最左邊的第一位,越靠近右邊,列出的網頁包含的內容更越具體。&lt;br /&gt;&lt;br /&gt;在您的網站上放置 HTML Sitemap 網頁,並使用 XML Sitemap 檔案 — 一個包含您網站&lt;br /&gt;  上所有網頁或最重要網頁 (如果您有成百上千個網頁) 的簡單 Sitemap 網頁,將會非常有用。&lt;br /&gt;&lt;br /&gt;  請避免:&lt;br /&gt;     在 HTML Sitemap 網頁中放置無效連結,使得網頁沒什麼用處&lt;br /&gt;     建立的 HTML Sitemap 僅簡單列出網頁,而沒有進行整理,例如依主題整理&lt;br /&gt;&lt;br /&gt;  請避免:&lt;br /&gt;     讓搜尋引擎建立 404 網頁的索引 (請務必將網站伺服器設定為當使用者要求的&lt;br /&gt;     網頁不存在時,能傳回 404 HTTP 狀態碼)&lt;br /&gt;     只提供類似於「Not found」、「404」等模糊的訊息,或者甚至連 404 網頁都沒有&lt;br /&gt;     404 網頁的設計與您網站的其他網頁不一致&lt;br /&gt;&lt;br /&gt;6. 撰寫更佳的錨定文字&lt;br /&gt;   這個錨定文字有時會告知使用者和 Google 有關您要連結之網頁的部分內容。您網頁上的連結可能是&lt;br /&gt;內部連結 (即指向您網站上其他網頁的連結),也可能是外部連結 (即指向其他網站之內容的連結)。&lt;br /&gt;無論是哪種情況,您的錨定文字寫得越詳細,使用者就越容易瀏覽,Google 也越容易瞭解您所連結的&lt;br /&gt;網頁內容。&lt;br /&gt;&lt;br /&gt;   請避免:&lt;br /&gt;     撰寫一般的錨定文字,比如「網頁」、「文章」或「按一下此處」&lt;br /&gt;     使用偏離主題或與要連結之網頁內容無關的文字&lt;br /&gt;     在多數情況下,使用網頁網址作為錨定文字 (即使某些情況可以這麼做,例如&lt;br /&gt;&lt;br /&gt;7. 適當使用標題標記&lt;br /&gt;標題標記 (請不要將其和 &lt;[head]&gt; HTML 標記或 HTTP 標頭混淆) 用於為使用者呈現網頁的結構。標&lt;br /&gt;題標記有六種不同大小,從 &lt;[h1]&gt; 到 &lt;[h6]&gt;,其重要性依次降低。&lt;br /&gt;&lt;br /&gt;   請避免:&lt;br /&gt;     在標題標記中放置對定義網頁結構沒有任何幫助的文字&lt;br /&gt;     在適合使用其他標記 (例如 &lt;[em]&gt; 和 &lt;[strong]&gt;) 的地方,不要使用標題標記&lt;br /&gt;     隨意調整標題標記的大小&lt;br /&gt;&lt;br /&gt;8. 最佳化圖片的使用&lt;br /&gt;圖片似乎是比較簡單的網站元件,但您可以對圖片的使用進行最佳化。所有圖片都有不同的檔案名稱和&lt;br /&gt;「alt」屬性,您可善加利用這兩個特點。&lt;br /&gt;&lt;br /&gt;   請避免:&lt;br /&gt;     儘可能使用像「image1.jpg」、「pic.gif」、「1.jpg」這樣的通用檔案名稱 (有&lt;br /&gt;     些網站的圖片超過數千張,因此可能會為圖片自動命名)&lt;br /&gt;     撰寫過長的檔案名稱&lt;br /&gt;     在替代文字中堆砌關鍵字,或者複製並貼上完整的句子&lt;br /&gt;&lt;br /&gt;  將圖片儲存在專用的目錄中 — 考慮將您的圖片合併到一個單獨的目錄中 (例如&lt;br /&gt;  brandonsbaseballcards.com/images/),而不是將圖片散佈在整個網域的很多目錄和子目錄下。&lt;br /&gt;  這樣可以簡化圖片的連結路徑。&lt;br /&gt;&lt;br /&gt;9. 利用 robots.txt&lt;br /&gt;「robots.txt」檔案可告知搜尋引擎是否可以存取您網站的某些部分,進而對這些部分進行檢索。此檔案&lt;br /&gt;必須要命名為「robots.txt」,並放置在您網站的根目錄中。&lt;br /&gt;&lt;br /&gt;http://baseball.com/robots.txt&lt;br /&gt;&lt;br /&gt;user-agent: *&lt;br /&gt;Disallow: /images/&lt;br /&gt;Disallow: /search&lt;br /&gt;所有符合條件的搜尋引擎漫遊器 (標有萬用字元符號 *) 都不會存取和檢索 /images/ 下的內容,&lt;br /&gt;或者任何以 /search 作為路徑開頭的網址&lt;br /&gt;&lt;br /&gt;「Google 網站管理員工具」中有一個很好用的&lt;br /&gt;&lt;a href="http://googlewebmastercentral.blogspot.com/2008/03/speaking-language-of-robots.html"&gt;robots.txt 產生器&lt;/a&gt;,可協助您建立此檔案。請注意,如果您的網站使用了子網域,且您不希望搜尋引擎檢索特定子網域中的某些網頁,則您必須為該子網域建立一個單獨的 robots.txt 檔案。如需更多有關&lt;br /&gt;robots.txt 詳情,我們建議您參閱有關&lt;a href="http://www.google.com/support/webmasters/bin/answer.py?hl=b5&amp;answer=156449"&gt;使用 robots.txt&lt;/a&gt; 檔案的網站管理員說明中心指南。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  對敏感的內容使用更為安全的方法 — 您或許對使用 robots.txt 來封鎖敏感或保密的材料感&lt;br /&gt;  覺不是特別放心。其中一個原因是,如果網際網路上碰巧存在連至您封鎖的網址的連結 (如參照記錄),則搜尋引擎仍然可以參照該網址 (只是顯示網址,而不顯示標題或片段內容)。此外,不遵守漫遊器排除標準的一些非符合條件的或惡意搜尋引擎可能會違背您的 robots.txt 指示。&lt;br /&gt;  最後,好奇的使用者可能會查看您 robots.txt 檔案中的目錄或子目錄,並猜中您不願被看到&lt;br /&gt;  的內容的網址。對內容加密或使用 .htaccess 對內容進行密碼保護是更安全的選擇。&lt;br /&gt;&lt;br /&gt;10. 瞭解連結的 rel="nofollow"&lt;br /&gt;&lt;br /&gt;將某個連結的「rel」屬性值設定為「nofollow」便會告知 Google 不應隨著您網站上的某些連結連至&lt;br /&gt;他處,也不應將您網頁的信譽情況傳給連至的網頁。不隨著某個連結連至他處的方法是,在連結的錨定&lt;br /&gt;標記中新增 rel="nofollow"。&lt;br /&gt;&lt;br /&gt;&lt;[a href='http://www.shadyseo.com/' rel='nofollow'&gt;Comment spammer&lt;[/a]&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;最後,如果您有意不隨著網頁中的任何連結連至他處,則可以在您的 robots 中繼標記中使用&lt;br /&gt;「nofollow」,將這個 robots 中繼標記放入該網頁 HTML 的 &lt;[head]&gt; 標記中。網站管理員中心網誌&lt;br /&gt;提供了一篇有關使用 &lt;a href="http://googlewebmastercentral.blogspot.com/2007/03/using-robots-meta-tag.html"&gt;robots 中繼標記&lt;/a&gt;的很有益的文章。這種方法的寫法是 &lt;[meta name="robots"&lt;br /&gt;content="nofollow"]&gt;。&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;a href="http://www.google.com/support/webmasters/bin/answer.py?hl=b5&amp;answer=156184"&gt;建立並提交 Sitemap&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-8736937362016511766?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/8736937362016511766/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=8736937362016511766' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8736937362016511766'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8736937362016511766'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/11/google-seo-memo.html' title='google seo memo'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-3921738155343802119</id><published>2009-10-28T07:23:00.001+08:00</published><updated>2009-10-28T07:26:09.496+08:00</updated><title type='text'>simple memo, initializer run</title><content type='html'>&lt;a href="http://api.rubyonrails.org/classes/Rails/Initializer.html"&gt;Class Rails::Initializer&lt;/a&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;#The Initializer is responsible for processing the Rails configuration, such as setting the $LOAD_PATH, requiring the right frameworks, initializing logging, and more. It can be run either as a single command that‘ll just use the default configuration, like this:&lt;br /&gt;&lt;br /&gt;  Rails::Initializer.run&lt;br /&gt;&lt;br /&gt;#But normally it‘s more interesting to pass in a custom configuration through the block running:&lt;br /&gt;&lt;br /&gt;  Rails::Initializer.run do |config|&lt;br /&gt;    config.frameworks -= [ :action_mailer ]&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-3921738155343802119?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/3921738155343802119/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=3921738155343802119' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/3921738155343802119'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/3921738155343802119'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/10/simple-memo-initializer-run.html' title='simple memo, initializer run'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-8574146512371318926</id><published>2009-10-26T22:16:00.001+08:00</published><updated>2009-10-26T22:19:21.716+08:00</updated><title type='text'>Symmetric Encryption vs  Asymmetric Encryption</title><content type='html'>http://support.oss.org.tw/wiki/index.php/&lt;br /&gt;&lt;br /&gt; Symmetric Encryption – 對稱式加密簡介 &lt;br /&gt;其特色在於加解密所使用的金鑰(key)是相同的! &lt;br /&gt;●兩方要進行秘密訊息的傳送之前，必須協議出一個共同的，用來加解密的金鑰(key)以及所使用的演算法；如此訊息一來一往之間，才可以被正確的加解密。 &lt;br /&gt;●當然這樣的方式會衍生出一些問題，因此才會有 Asymmetric Encryption(非對稱式加密) 的產生，來改善一些 Symmetric Encryption 的缺點；然而 Symmetric Encryption 在實際的應用上有其實用性，因此目前還是持續不斷的被使用當中&lt;br /&gt;&lt;br /&gt;在加解密運作的機制中，有兩大重要部分，除了金鑰(key)之外，另外一個即為加解密所使用的演算法(algorithm)。 &lt;br /&gt;在實際應用上，金鑰(key)是一個檔案，內容為一群無意義的英文與數字的集合，長度範圍有可能介於 64~1024 bits (甚至更大) 之間，妥善由通訊雙方秘密保管好。 &lt;br /&gt;而演算法(algorithm)則是透明公開的，隨時可以從網路或是其他地方取得演算法的相關使用方法與規則。&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;Asymmetric Encryption (非對稱式加密) 即是為了改良 Symmetric Encryption(對稱式加密) 的缺點而產生的。 &lt;br /&gt;在對稱式加密中，通訊雙方往來的訊息是由同一把金鑰進行加密；假設 A 與 B 通訊，兩個人必須有一把相同的金鑰；而若是 A 也要與 C 通訊，則 A 與 C 則必須擁有另外一把不同的金鑰；否則若是都使用相同金鑰，C 就可以解密出 A 要給 B 的訊息，相對的，B 也可以解密出 A 要給 C 的訊息，如此一來資訊在傳送就不再安全! &lt;br /&gt;除此之外，還要防範金鑰被竊取的問題，只要通訊雙方任一方把金鑰洩露出去，就破壞了原本建立的安全機制了。 &lt;br /&gt;因此，Asymmetric Encryption(非對稱式加密) 使用了一對金鑰(key pair)的方式解決了這個問題 &lt;br /&gt;&lt;br /&gt;在 Asymmetric Encryption 的架構中，要通訊的雙方都各持有一對金鑰，分別是私鑰(private key)以及公鑰(public key)。 &lt;br /&gt;private key 是要妥善且由自己秘密保管的，而 public key 則是可以公開出去。 &lt;br /&gt;假設使用者 A 有一對金鑰，若是 B 要與 A 進行通訊，則 B 必須使用 A 所提供的 public key 進行加密，再將加密的內容傳送給 A，接著 A 可以用自己的 private key 進行解密。同樣的，A 要是要傳訊息給 B，則是要使用 B 所提供的 public key 進行加密，而 B 則可以用自己的 private key 進行解密。 &lt;br /&gt;有趣的是，雖然訊息是由 public key 所加密，但是卻無法利用 public key 將原本的訊息還原回來，這就是非對稱式加密的精華所在，也是目前非常受到歡迎的原因。而這一來一往之間，所使用的演算法，即為 RSA 演算法。&lt;br /&gt;&lt;br /&gt;如此看來，其實 RSA 的加解密過程是很簡單的，因此重點就是在於金鑰的產生，目前已經被證明長度 1024 bits 不夠安全，因此建議使用長度為 2048 bits 的金鑰作為加解密之用，來提升重要資訊傳輸的安全性。 &lt;br /&gt;最後，雖然非對稱式加密解決了金鑰交換的問題，但是卻衍生出加解密效率不彰的問題，因為相較於 DES，RSA 的速度只有其百分之一不到&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;Asymmetric + Symmetric&lt;br /&gt;&lt;br /&gt;真的沒有更好的 solution 嗎? 當然是有的...只要巧妙的結合兩者的優點即可啦!! 其中的原理很簡單，假設 A 要傳訊息給 B，就會發生大概類似以下流程： &lt;br /&gt;    (1) A 透過對稱式演算法，產生出一把對稱式加密用的金鑰&lt;br /&gt;     (注意：這把金鑰只用在這一次的傳輸) &lt;br /&gt;    (2) 接著 A 使用 B 所提供的 public key，將這把金鑰加密，&lt;br /&gt;      並將加密後的內容傳給 B &lt;br /&gt;    (3) B 接收到後，使用自己的 private key 解密，取得這把&lt;br /&gt;      一次性金鑰 &lt;br /&gt;    (4) 之後雙方訊息的往來，都使用對稱式加密 &lt;br /&gt;如此一來，就不僅解決了金鑰交換的問題，也解決了非對稱式加解密效率不彰的問題。 &lt;br /&gt;當然，這樣的 solution 其實還不算最安全，因此才會有 Digital Signature(數位簽章) 的誕生&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-8574146512371318926?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/8574146512371318926/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=8574146512371318926' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8574146512371318926'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8574146512371318926'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/10/symmetric-encryption-vs-asymmetric.html' title='Symmetric Encryption vs  Asymmetric Encryption'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-8514456813025629060</id><published>2009-10-26T15:35:00.005+08:00</published><updated>2009-10-26T18:18:52.388+08:00</updated><title type='text'>facebook 發post ( story ) 到 wall</title><content type='html'>http://wiki.developers.facebook.com/index.php/Feed_forms&lt;br /&gt;http://wiki.developers.facebook.com/index.php/FB.Connect.streamPublish&lt;br /&gt;http://wiki.developers.facebook.com/index.php/Attachment_%28Streams%29&lt;br /&gt;http://wiki.developers.facebook.com/index.php/Stream.publish&lt;br /&gt;&lt;br /&gt;http://wiki.developers.facebook.com/index.php/XFBML&lt;br /&gt;http://blog.yangtheman.com/2009/08/23/how-to-integrate-facebook-connect-with-a-rails-app/&lt;br /&gt;&lt;br /&gt;這邊用的是iframe canvas下的 push 方式, 基本上是跟 facebook connect 相同的&lt;br /&gt;&lt;textarea name="code" class="javascript"&gt;&lt;br /&gt;  function trigger_publish(){&lt;br /&gt;    var attachment = {&lt;br /&gt;'media':[{'type':'image','src':'http://bit.ly/AJTnf','href':'http://bit.ly/hifZk'}],&lt;br /&gt;'description' : 'kerkerlala',&lt;br /&gt; 'caption' : 'caption kerker',&lt;br /&gt; 'properties' : {'category' : {'text' : 'pets', 'href' : 'http://www.youtube.com/browse?s=mp&amp;t=t&amp;c=15'}, 'ratings' : '5 stars' }};&lt;br /&gt;    var actionLinks = [{ "text": "Watch Video", "href": "http://www.myvideosite/videopage.html"}];&lt;br /&gt;    FB.Connect.streamPublish('lala', attachment, actionLinks, null, 'kerker');&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;a href='#' onclick='trigger_publish();' &gt;publish&lt;/a&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;需要include XFBML 和 facebook connect 的 js&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-8514456813025629060?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/8514456813025629060/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=8514456813025629060' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8514456813025629060'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8514456813025629060'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/10/facebook-post-story-wall.html' title='facebook 發post ( story ) 到 wall'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-3602417429332552300</id><published>2009-10-21T17:42:00.002+08:00</published><updated>2009-10-21T17:45:04.075+08:00</updated><title type='text'>Authorizing Applications, share button</title><content type='html'>&lt;a href="http://wiki.developers.facebook.com/index.php/Authorizing_Applications"&gt;Authorizing_Applications&lt;/a&gt;&lt;br /&gt;&lt;a href="http://wiki.developers.facebook.com/index.php/Fb:share-button"&gt;share button&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Once a user has authorized your application, you can utilize the following URLs, which you specify in your application's settings in the Developer application:&lt;br /&gt;&lt;br /&gt;    * Post-Authorize Callback URL: Facebook pings this URL when a user authorizes your application for the first time. You can also call users.isAppUser to determine if the user has authorized your application.&lt;br /&gt;    * Post-Authorize Redirect URL: You can redirect a user to this URL after the user authorizes your application for the first time. You can use this URL only if the user authorizes your application through login.php and not the login dialog.&lt;br /&gt;    * Post-Remove Callback URL: Facebook pings the URL when a user removes your application. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;For FBML canvas page applications, the parameters are sent as POST parameter. For iframe applications, the parameters are sent as GET parameters, unless you are preloading FQL using the fb_iframe_post option, in which case the parameters are sent as POST parameters.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-3602417429332552300?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/3602417429332552300/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=3602417429332552300' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/3602417429332552300'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/3602417429332552300'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/10/authorizing-applications-share-button.html' title='Authorizing Applications, share button'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-507244392786993426</id><published>2009-10-21T14:42:00.002+08:00</published><updated>2009-10-21T14:53:38.475+08:00</updated><title type='text'>Choosing between an FBML or IFrame Application(2)</title><content type='html'>Now, with XFBML, in addition to being able to embed things like fb:name and fb:profile-pic directly into your HTML, you can render any FBML tag by using server-side FBML. If you wrap your FBML inside fb:serverfbml tags, as in:&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;fb:serverfbml&gt;&lt;script type="text/fbml"&gt; ... &lt;/script&gt;&lt;/fb:serverfbml&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;...then this opens an IFrame to Facebook on the page being served from your domain, and Facebook will render the FBML in there.&lt;br /&gt;&lt;br /&gt;However, a fair amount of overhead is involved in opening the IFrame, and your CSS won't propagate into the FBML IFrame, so you won't want to put too many blocks of server-side FBML on a page. But if you need one or two snippets of FBML to make your application richer, or you want a large chunk of your page to use FBML, this makes that possible and pretty easy. &lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;br /&gt;Preload FQL&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Preload FQL lets you do these sorts of queries on both FBML and IFrame canvas pages, though it works differently for each. In general, you specify a few regular expressions that map to lists of FQL queries. If the page being requested matches any of the regular expressions, the corresponding FQL queries will be executed by Facebook when the user's browser sends the request to Facebook.&lt;br /&gt;&lt;br /&gt;For FBML applications, the results get sent along to your application's servers when Facebook requests the FBML from you. Most of the time, this makes calls to the Facebook API unnecessary, even when you need fairly complicated data from Facebook to generate the page.&lt;br /&gt;&lt;br /&gt;This is what the flow would look like for an FBML canvas page using preload FQL&lt;br /&gt;&lt;br /&gt;FBML Canvas Page Using Preload FQL&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ccheever.com/blog/wp-content/uploads/2008/09/fbml-canvas-page-preload-fgl.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 558px; height: 188px;" src="http://www.ccheever.com/blog/wp-content/uploads/2008/09/fbml-canvas-page-preload-fgl.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Preloading FQL works differently with IFrames. In order for Facebook to send data to your server along with the request for the IFrame, it has to encode the data in the URL being requested. Instead of sending the FQL result set to your server, the Facebook server sends the FQL result data down to the user's browser, attached to the outer frame that contains the Facebook chrome on the canvas. You can choose whether you want to have a lightweight redirect occur, which &lt;span style="font-weight:bold;"&gt;encodes the FQL results in the request made for your IFrame page&lt;/span&gt;. Or, if you only want to access that data on the client side, you can use the &lt;span style="font-weight:bold;"&gt;PreloadFQL_get&lt;/span&gt; method from the JavaScript client library and rewrite parts of the page on the fly using the data after it's initially rendered. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;IFrame Canvas Page using Preload FQL&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ccheever.com/blog/wp-content/uploads/2008/09/iframe-canvas-page-preload-fql.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 555px; height: 347px;" src="http://www.ccheever.com/blog/wp-content/uploads/2008/09/iframe-canvas-page-preload-fql.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Note that the preload FQL will only work on the first page that loads in your IFrame&lt;/span&gt;. If you point your links to apps.facebook.com URLs using &lt;span style="font-weight:bold;"&gt;target="_top" instead&lt;/span&gt; of just linking to different pages within the frame, you could use preload FQL on every page, but this would make all your pages load slowly&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-507244392786993426?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/507244392786993426/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=507244392786993426' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/507244392786993426'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/507244392786993426'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/10/choosing-between-fbml-or-iframe_21.html' title='Choosing between an FBML or IFrame Application(2)'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-7668344600968301725</id><published>2009-10-21T11:16:00.004+08:00</published><updated>2009-10-21T14:41:43.534+08:00</updated><title type='text'>Choosing between an FBML or IFrame Application(1)</title><content type='html'>&lt;a href="http://wiki.developers.facebook.com/index.php/Choosing_between_an_FBML_or_IFrame_Application"&gt;Choosing between an FBML or IFrame Application&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Traditional IFrame Canvas Page&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ccheever.com/blog/wp-content/uploads/2008/09/iframe-canvas-page1.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 504px; height: 335px;" src="http://www.ccheever.com/blog/wp-content/uploads/2008/09/iframe-canvas-page1.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;FBML Canvas Page&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ccheever.com/blog/wp-content/uploads/2008/09/fbml-canvas-page.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 560px; height: 181px;" src="http://www.ccheever.com/blog/wp-content/uploads/2008/09/fbml-canvas-page.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;XFBML as part of Facebook Connect as a way to quickly get social content onto any Web page, and since IFrames are just Web pages, XFBML can speed those up as well. &lt;br /&gt;&lt;br /&gt;Before XFBML, IFrame applications always had to make API calls to render social content like user names and profile pictures, and those API calls required another round trip communication between your server and Facebook before sending back content to the user's browser&lt;br /&gt;&lt;br /&gt;with XFBML, you can embed various FBML tags like fb:name and fb:profile-pic directly into the HTML that your application sends to the user's browser. Then you simply include some Facebook-specific JavaScript, and that code gets executed and scans the DOM for those tags. The JavaScript then determines all the data needed to render that content and batches it up into one API call from the user's browser to Facebook&lt;br /&gt;&lt;br /&gt;The rest of the page that isn't social content can render to the user before the API call completes. And in XFBML, we cache data on the browser so that in many cases, it isn't even necessary to make any API call to Facebook at all.&lt;br /&gt;&lt;br /&gt;IFrame Canvas Page Using XFBML - First Page Load by a User&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ccheever.com/blog/wp-content/uploads/2008/09/iframe-xfbml-first-canvas-page.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 562px; height: 356px;" src="http://www.ccheever.com/blog/wp-content/uploads/2008/09/iframe-xfbml-first-canvas-page.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;IFrame Canvas Page Using XFBML - Subsequent Page Loads by a User&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ccheever.com/blog/wp-content/uploads/2008/09/iframe-canvas-page-xfbml-subsequent-load.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 555px; height: 336px;" src="http://www.ccheever.com/blog/wp-content/uploads/2008/09/iframe-canvas-page-xfbml-subsequent-load.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-7668344600968301725?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/7668344600968301725/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=7668344600968301725' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/7668344600968301725'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/7668344600968301725'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/10/choosing-between-fbml-or-iframe.html' title='Choosing between an FBML or IFrame Application(1)'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-7332250148783471707</id><published>2009-10-19T13:57:00.002+08:00</published><updated>2009-10-19T13:59:48.604+08:00</updated><title type='text'>找該加index 的地方</title><content type='html'>&lt;a href="http://github.com/eladmeidar/rails_indexes"&gt;rails_indexes&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;script/plugin install git://github.com/eladmeidar/rails_indexes.git&lt;br /&gt;&lt;br /&gt;#用association 來找 缺少的 index&lt;br /&gt;rake db:show_me_a_migration&lt;br /&gt;&lt;br /&gt;#用 AR::Base#find calls (including: find, find_by, find_all_by, find_by_x_and_y, find_all_by_x_and_y): 來找缺少的index&lt;br /&gt;rake db:show_me_ar_find_indexes&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-7332250148783471707?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/7332250148783471707/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=7332250148783471707' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/7332250148783471707'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/7332250148783471707'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/10/index.html' title='找該加index 的地方'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-1649922101861955577</id><published>2009-10-19T13:50:00.002+08:00</published><updated>2009-10-19T13:55:40.471+08:00</updated><title type='text'>check index exist</title><content type='html'>add_index 之前檢查一下&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;class AddMissingIndexes &lt; ActiveRecord::Migration&lt;br /&gt;  def self.up&lt;br /&gt;    check_add_index :groups, :id&lt;br /&gt;    check_add_index :about_states, :confirm_email_code&lt;br /&gt;    check_add_index :messages, :id&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def self.down&lt;br /&gt;    check_remove_index :groups, :id&lt;br /&gt;    check_remove_index :about_states, :confirm_email_code&lt;br /&gt;    check_remove_index :messages, :id&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def self.check_add_index(table, column)&lt;br /&gt;    add_index table, column unless check_index_exist(table, column)&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def self.check_remove_index(table, column)&lt;br /&gt;    remove_index table, column if check_index_exist(table, column)&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  # indexes 可以找出talbe 的 indexes&lt;br /&gt;  # index_name 可以產生該生成的 index name&lt;br /&gt;  def self.check_index_exist(table, columns)&lt;br /&gt;    ActiveRecord::Base.connection.indexes(table).map(&amp;:name).include?(ActiveRecord::Base.connection.index_name(table, columns))&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-1649922101861955577?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/1649922101861955577/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=1649922101861955577' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1649922101861955577'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1649922101861955577'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/10/check-index-exist.html' title='check index exist'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-5168475089479146412</id><published>2009-10-18T21:28:00.001+08:00</published><updated>2009-10-18T21:30:44.389+08:00</updated><title type='text'>mustache  把view logic 的部份再拆出來</title><content type='html'>就是要讓view 更乾淨把logic 的部份再拆出來&lt;br /&gt;&lt;a href="http://github.com/defunkt/mustache"&gt;mustache&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-5168475089479146412?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/5168475089479146412/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=5168475089479146412' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/5168475089479146412'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/5168475089479146412'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/10/mustache-view-logic.html' title='mustache  把view logic 的部份再拆出來'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-6447087939317737227</id><published>2009-10-18T16:45:00.002+08:00</published><updated>2009-10-18T17:36:46.619+08:00</updated><title type='text'>Ruby on Rails Code Quality Checklist</title><content type='html'>&lt;a href="http://www.matthewpaulmoore.com/ruby-on-rails-code-quality-checklist#skinny"&gt;Ruby on Rails Code Quality Checklist&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;   1.  Each controller action only calls one model method other than an initial find or new.  &lt;br /&gt;        (Make custom .new or .update methods in the model with all necessary). ...&lt;br /&gt;        就是盡量把邏輯擺到model 裡, 唯一的例外就是在決定要render view or redirect的時候&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   2. Only one or two instance variables are shared between each controller and view. ...&lt;br /&gt;        保持一兩個instance variable 在controller 和 view 就好&lt;br /&gt;        這樣可以讓所有相關連的只有在需要的時候在被call 到, 而且還可以做instance-variable cache in one place&lt;br /&gt;        例如不要在controller 裡用到 @post and @related_posts 兩個instance variable, 而是create a method 給 @post, 這樣你就可以在 view 裡面直接用    @post.related_posts&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   3. All model and variable names are both immediately obvious (to a new developer) and as short as possible without using abbreviations. ...&lt;br /&gt;       取個好名字&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   4. All custom "finds" accessed from more than one place in the code use named_scope instead of a custom method. ...&lt;br /&gt;       有關find 什麼東西的, 都用named_scope 來做&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   5. A .find or .find_by_ is never called in a view or view helper. ...&lt;br /&gt;        別直接在view , find or find_by anything, 至少用一下namde_scope or custom methods to do that&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   6. There is zero custom code that duplicates functionality of a built-in function in rails. ...&lt;br /&gt;   7. Code has been aggressively DRYed during development. ...&lt;br /&gt;   8. All functionality used in two or more models has been turned into a library/module. ...&lt;br /&gt;   9. All logic duplicated between two or more apps has been turned into a gemified plugin. ...&lt;br /&gt;&lt;br /&gt;  10. STI is not used anywhere ...&lt;br /&gt;         別用STI, 用module 來代替, 如果你用STI 你會需要至少bind 兩個model, 這樣你很難回頭&lt;br /&gt;data migration 你會死&lt;br /&gt;         但是polymorphic association 是鼓勵的&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  11. Every design choice should yield the most simplistic design possible for the need of users at the current time. &lt;br /&gt;        No guesses for future functionality were designed into the application. ...&lt;br /&gt;        對於現在的情況做最簡單的設計, 不要猜測未來的情況, 你可能會猜錯&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  12. Close to full test coverage exists at the highest level of the application: on and between controller actions.  Coverage is highest for code used by the most number of end users. ...&lt;br /&gt;&lt;br /&gt;        先從user 最常用的開始測起&lt;br /&gt;  13. All tests pass before code is merged into a shared repository. ...&lt;br /&gt;&lt;br /&gt;         merge 前要測過&lt;br /&gt;  14. Every fixed defect on a deployed product has tests added to prevent regression. ...&lt;br /&gt;        替解掉的defeat 加上測試&lt;br /&gt;&lt;br /&gt;  15. Every plugin installed has been code reviewed. ...&lt;br /&gt;        檢查一下你的plugin code&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-6447087939317737227?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/6447087939317737227/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=6447087939317737227' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/6447087939317737227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/6447087939317737227'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/10/ruby-on-rails-code-quality-checklist.html' title='Ruby on Rails Code Quality Checklist'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-4183045668010277270</id><published>2009-10-18T12:53:00.003+08:00</published><updated>2009-10-18T13:05:33.753+08:00</updated><title type='text'>Install any HTML theme/template into your Rails app</title><content type='html'>&lt;a href="http://drnicwilliams.com/2009/10/06/install-any-html-themetemplate-into-your-rails-app/"&gt;Install any HTML theme/template into your Rails app&lt;/a&gt;&lt;br /&gt;&lt;a href="http://github.com/drnic/install_theme"&gt;install_theme&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.oswd.org/"&gt;open source web design&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;幫你用來快速套template 的&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;# lowerright:text 的部份就是指定content的部份&lt;br /&gt;# partial 就是指定哪邊會變partial, 最基本的就是menu&lt;br /&gt;# 指定path 有不同的指定方式XPath or CSS path 都可以&lt;br /&gt;# install_theme . path/to/theme/folder ".lowerright:text" --partial "menu:.nav:text"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;$ gem install install_theme&lt;br /&gt;$ rails my_app&lt;br /&gt;$ cd my_app&lt;br /&gt;$ install_theme . path/to/theme/folder ".lowerright:text" --partial "menu://div[@class='nav']/text()"&lt;br /&gt;  create  app/app/helpers/template_helper.rb&lt;br /&gt;  create  app/controllers/original_template_controller.rb&lt;br /&gt;  create  app/helpers/template_helper.rb&lt;br /&gt;  create  app/views/layouts/_menu.html.erb&lt;br /&gt;  create  app/views/layouts/application.html.erb&lt;br /&gt;  create  app/views/original_template/index.html.erb&lt;br /&gt;  create  public/images/footer.png&lt;br /&gt;  ...&lt;br /&gt;  create  public/stylesheets/style.css&lt;br /&gt;&lt;br /&gt;Your theme has been installed into your app.&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;#可以用這樣來做menu 的選擇&lt;br /&gt;&lt;br /&gt;module TemplateHelper&lt;br /&gt;  def render_or_default(partial, default = partial)&lt;br /&gt;    render :partial =&gt; partial&lt;br /&gt;  rescue ActionView::MissingTemplate&lt;br /&gt;    begin&lt;br /&gt;      render :partial =&gt; "layouts/#{default}"&lt;br /&gt;    rescue ActionView::MissingTemplate&lt;br /&gt;      nil&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-4183045668010277270?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/4183045668010277270/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=4183045668010277270' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4183045668010277270'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4183045668010277270'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/10/install-any-html-themetemplate-into.html' title='Install any HTML theme/template into your Rails app'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-1157734401483772297</id><published>2009-10-17T07:27:00.002+08:00</published><updated>2009-10-17T07:33:44.148+08:00</updated><title type='text'>[Scale] Scale Frontend 應該注意的五件事</title><content type='html'>&lt;a href="http://rails.pixnet.net/blog/post/29565569"&gt;[Scale] Scale Frontend 應該注意的五件事&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.engineyard.com/blog/2009/rails-in-the-wild-5-client-side-performance-observations/"&gt;Rails in the Wild: 5 Client-Side Performance Observations&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;1. It’s easy to forget to compress your JavaScript and CSS&lt;br /&gt;&lt;br /&gt;要記得 :cache =&gt; true&lt;br /&gt;要記得壓 js 和 css&lt;br /&gt;&lt;br /&gt;2. Watch out for slow third party services&lt;br /&gt;&lt;br /&gt;都是慢在第三方&lt;br /&gt;google ads, analytics 也會托慢, 請用 &lt;a href="http://github.com/choonkeat/postload_google_ads"&gt;postload_google_ads&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3. Using multiple image hosts doesn’t always mean higher performance&lt;br /&gt;&lt;br /&gt;拆那麼多台未必會比較快&lt;br /&gt;&lt;br /&gt;4. S3 is NOT a Webserver!&lt;br /&gt;&lt;br /&gt;S3 是 storage ，不是 web server。所以不要一股腦的把東西往上丟，要注意有沒有敏感資訊，而且 s3p 是沒有幫忙做 gzip 的。&lt;br /&gt;&lt;br /&gt;5. Most performance variability is NOT attributable to page factors&lt;br /&gt;&lt;br /&gt;速度慢通常是慢在後端..&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-1157734401483772297?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/1157734401483772297/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=1157734401483772297' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1157734401483772297'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1157734401483772297'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/10/scale-scale-frontend.html' title='[Scale] Scale Frontend 應該注意的五件事'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-1845452006765306560</id><published>2009-10-16T16:46:00.003+08:00</published><updated>2009-10-16T17:31:52.268+08:00</updated><title type='text'>clearance 的 generator</title><content type='html'>&lt;a href="http://wiki.github.com/thoughtbot/clearance"&gt;clearance&lt;/a&gt;&lt;br /&gt;&lt;a href="http://api.rubyonrails.org/classes/Rails/Generator/Commands/Create.html#M002448"&gt;Class Rails::Generator::Commands::Create&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;#這邊是需要的library&lt;br /&gt;require File.expand_path(File.dirname(__FILE__) + "/lib/insert_commands.rb")&lt;br /&gt;require File.expand_path(File.dirname(__FILE__) + "/lib/rake_commands.rb")&lt;br /&gt;require 'factory_girl'&lt;br /&gt;&lt;br /&gt;class ClearanceGenerator &lt; Rails::Generator::Base&lt;br /&gt;&lt;br /&gt;  def manifest&lt;br /&gt;    record do |m|&lt;br /&gt;       # 原來可以這樣insert GOOD&lt;br /&gt;      m.insert_into "app/controllers/application_controller.rb",&lt;br /&gt;                    "include Clearance::Authentication"&lt;br /&gt;&lt;br /&gt;      user_model = "app/models/user.rb"&lt;br /&gt;      if File.exists?(user_model)&lt;br /&gt;        m.insert_into user_model, "include Clearance::User"&lt;br /&gt;      else&lt;br /&gt;        #原來也可以生目錄&lt;br /&gt;        m.directory File.join("app", "models")&lt;br /&gt;        m.file "user.rb", user_model&lt;br /&gt;      end&lt;br /&gt;&lt;br /&gt;      m.directory File.join("test", "factories")&lt;br /&gt;      m.file "factories.rb", "test/factories/clearance.rb"&lt;br /&gt;&lt;br /&gt;      #還可以選擇用哪個file migrate, 叫啥名字&lt;br /&gt;      m.migration_template "migrations/#{migration_name}.rb",&lt;br /&gt;                           'db/migrate',&lt;br /&gt;                           :migration_file_name =&gt; "clearance_#{migration_name}"&lt;br /&gt;&lt;br /&gt;      m.readme "README"&lt;br /&gt;    end&lt;br /&gt;  private&lt;br /&gt;&lt;br /&gt;  def migration_name&lt;br /&gt;    #可以check table 在不在&lt;br /&gt;    if ActiveRecord::Base.connection.table_exists?(:users)&lt;br /&gt;      'update_users'&lt;br /&gt;    else&lt;br /&gt;      'create_users'&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#--------------------------------------------------&lt;br /&gt;Rails::Generator::Commands::Create.class_eval do&lt;br /&gt;  def insert_into(file, line)&lt;br /&gt;    logger.insert "#{line} into #{file}"&lt;br /&gt;    unless options[:pretend] || file_contains?(file, line)&lt;br /&gt;      gsub_file file, /^(class|module) .+$/ do |match|&lt;br /&gt;        "#{match}\n  #{line}"&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end   &lt;br /&gt;&lt;/textarea&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;#/clearance/templates/migrations/create_users.rb&lt;br /&gt;class ClearanceCreateUsers &lt; ActiveRecord::Migration&lt;br /&gt;  def self.up&lt;br /&gt;    create_table(:users) do |t|&lt;br /&gt;      t.string   :email&lt;br /&gt;      t.string   :encrypted_password, :limit =&gt; 128&lt;br /&gt;      t.string   :salt,               :limit =&gt; 128&lt;br /&gt;      t.string   :confirmation_token, :limit =&gt; 128&lt;br /&gt;      t.string   :remember_token,     :limit =&gt; 128&lt;br /&gt;      t.boolean  :email_confirmed, :default =&gt; false, :null =&gt; false&lt;br /&gt;      t.timestamps&lt;br /&gt;    end &lt;br /&gt;  &lt;br /&gt;    add_index :users, [:id, :confirmation_token]&lt;br /&gt;    add_index :users, :email&lt;br /&gt;    add_index :users, :remember_token&lt;br /&gt;  end&lt;br /&gt;  &lt;br /&gt;  def self.down&lt;br /&gt;    drop_table :users&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#-------------------------------------&lt;br /&gt;#/clearance/templates/migrations/update_users.rb&lt;br /&gt;class ClearanceUpdateUsers &lt; ActiveRecord::Migration&lt;br /&gt;  def self.up&lt;br /&gt;&lt;%&lt;br /&gt;      # ActiveRecord::Base.connection.columns(:users).collect { |each| each.name } = User.columns.map { |each| each.name }&lt;br /&gt;      existing_columns = ActiveRecord::Base.connection.columns(:users).collect { |each| each.name }&lt;br /&gt;      columns = [&lt;br /&gt;        [:email,              't.string :email'],&lt;br /&gt;        [:encrypted_password, 't.string :encrypted_password, :limit =&gt; 128'],&lt;br /&gt;        [:salt, 't.string :salt, :limit =&gt; 128'],&lt;br /&gt;        [:confirmation_token, 't.string :confirmation_token, :limit =&gt; 128'],&lt;br /&gt;        [:remember_token, 't.string :remember_token, :limit =&gt; 128'],&lt;br /&gt;        [:email_confirmed, 't.boolean :email_confirmed, :default =&gt; false, :null =&gt; false']&lt;br /&gt;      ].delete_if {|c| existing_columns.include?(c.first.to_s)}&lt;br /&gt;-%&gt;   &lt;br /&gt;    change_table(:users) do |t|&lt;br /&gt;&lt;% columns.each do |c| -%&gt;&lt;br /&gt;      &lt;%= c.last %&gt;&lt;br /&gt;&lt;% end -%&gt;&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;&lt;%&lt;br /&gt;    #連有哪些index 也可以看&lt;br /&gt;    existing_indexes = ActiveRecord::Base.connection.indexes(:users)&lt;br /&gt;    index_names = existing_indexes.collect { |each| each.name }&lt;br /&gt;    new_indexes = [&lt;br /&gt;      [:index_users_on_id_and_confirmation_token, 'add_index :users, [:id, :confirmation_token]'],&lt;br /&gt;      [:index_users_on_email,        'add_index :users, :email'],&lt;br /&gt;      [:index_users_on_remember_token,        'add_index :users, :remember_token']&lt;br /&gt;    ].delete_if { |each| index_names.include?(each.first.to_s) }&lt;br /&gt;-%&gt;&lt;br /&gt;&lt;% new_indexes.each do |each| -%&gt;&lt;br /&gt;    &lt;%= each.last %&gt;&lt;br /&gt;&lt;% end -%&gt;&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def self.down&lt;br /&gt;    change_table(:users) do |t|&lt;br /&gt;&lt;% unless columns.empty? -%&gt;&lt;br /&gt;      t.remove &lt;%= columns.collect { |each| ":#{each.first}" }.join(',') %&gt;&lt;br /&gt;&lt;% end -%&gt;&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-1845452006765306560?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/1845452006765306560/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=1845452006765306560' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1845452006765306560'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1845452006765306560'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/10/clearance-generator.html' title='clearance 的 generator'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-6299977871582522948</id><published>2009-10-16T05:50:00.001+08:00</published><updated>2009-10-16T05:52:39.183+08:00</updated><title type='text'>JavaScript 中的 document.createDocumentFragment</title><content type='html'>&lt;a href="http://blog.ericsk.org/archives/1358"&gt;JavaScript 中的 document.createDocumentFragment&lt;/a&gt;&lt;br /&gt;&lt;textarea name="code" class="javascript"&gt;&lt;br /&gt;var fragment = document.createDocumentFragment();&lt;br /&gt;for (var i in some_array) {&lt;br /&gt;    var node = document.createElement('option');&lt;br /&gt;    node.innerHTML = '....';&lt;br /&gt;    fragment.appendChild(node);&lt;br /&gt;}&lt;br /&gt;targetNode.appendChild(fragment);&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;在這段程式碼中，使用了 document.createDocumentFragment() 這個函式產生一個 document fragment，你可以把它想作是一個處理 DOM element 的 buffer，把欲生成的 DOM element 先加入到這個 fragment 中，最後再一次加到頁面的 DOM 結構中，這樣的作法比起在迴圈中一直 appendChild 來得快上許多，當然更重要的是，問題也被解決了 :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-6299977871582522948?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/6299977871582522948/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=6299977871582522948' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/6299977871582522948'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/6299977871582522948'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/10/javascript-documentcreatedocumentfragme.html' title='JavaScript 中的 document.createDocumentFragment'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-2013434836201719917</id><published>2009-10-06T17:46:00.001+08:00</published><updated>2009-10-06T17:48:37.626+08:00</updated><title type='text'>ruby binary code</title><content type='html'>有時候想要return 一些binary code 東西要怎樣帶勒&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;#注意外面要雙引號喔&lt;br /&gt;return :text =&gt; "aaaa\r\nbbbb"&lt;br /&gt;#或&lt;br /&gt;return :text =&gt; "aaaa\x0a\x0dbbbb"&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-2013434836201719917?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/2013434836201719917/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=2013434836201719917' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2013434836201719917'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2013434836201719917'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/10/ruby-binary-code.html' title='ruby binary code'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-4624581830783418667</id><published>2009-10-05T20:45:00.002+08:00</published><updated>2009-10-05T20:49:21.193+08:00</updated><title type='text'>console tips</title><content type='html'>&lt;a href="http://tagaholic.me/2009/03/13/hirb-irb-on-the-good-stuff.html"&gt;Hirb - Irb On The Good Stuff&lt;/a&gt;&lt;br /&gt;可以看到sql 結果的&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;  gem install cldwalker-hirb —source http://gems.github.com&lt;br /&gt;  # Load hirb and enable view framework&lt;br /&gt;  irb&gt;&gt; require 'hirb'&lt;br /&gt;  =&gt; true&lt;br /&gt;  irb&gt;&gt; Hirb::View.enable&lt;br /&gt;  =&gt; nil&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;可以看到sql 指令的&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;# ~/.irbrc file &lt;br /&gt;script_console_running = ENV.include?('RAILS_ENV') &amp;&amp; IRB.conf[:LOAD_MODULES] &amp;&amp; IRB.conf[:LOAD_MODULES].include?('console_with_helpers')&lt;br /&gt;rails_running = ENV.include?('RAILS_ENV') &amp;&amp; !(IRB.conf[:LOAD_MODULES] &amp;&amp; IRB.conf[:LOAD_MODULES].include?('console_with_helpers'))&lt;br /&gt;irb_standalone_running = !script_console_running &amp;&amp; !rails_running&lt;br /&gt;&lt;br /&gt;if script_console_running&lt;br /&gt;  require 'logger'&lt;br /&gt;  Object.const_set(:RAILS_DEFAULT_LOGGER, Logger.new(STDOUT))&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-4624581830783418667?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/4624581830783418667/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=4624581830783418667' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4624581830783418667'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4624581830783418667'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/10/console-tips.html' title='console tips'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-7326420114635944497</id><published>2009-10-05T20:13:00.002+08:00</published><updated>2009-10-05T20:41:47.665+08:00</updated><title type='text'>has_many , time now, assocation</title><content type='html'>&lt;a href="http://www.spacevatican.org/2008/11/9/do-you-know-when-your-code-runs"&gt;Do you know when your code runs?&lt;/a&gt;&lt;br /&gt;有時候你時候你會發現你在你下的conditions 有關於時間的, 跑起來有點怪怪的&lt;br /&gt;&lt;br /&gt;在development 沒問題, 在production 卻不正常&lt;br /&gt;&lt;br /&gt;仔細看會發現時間統統都是static 的了, 因為production 並不會每次都去reload class&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;class Person &lt; ActiveRecord::Base&lt;br /&gt;  has_many :posts&lt;br /&gt;  has_many :recent_posts, :class_name =&gt; 'Post', :conditions =&gt; ["created_at &gt; ?", 1.week.ago]&lt;br /&gt;  validates_inclusion_of :birth_date, :in =&gt; (20.years.ago..13.years.ago), &lt;br /&gt;                            :message =&gt; "You must be a teenager to signup", :on =&gt; :create&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class Post &lt; ActiveRecord::Base&lt;br /&gt;  named_scope :recent, :conditions =&gt; ["created_at &gt; ?", 1.week.ago]&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;這時候只要換個寫法&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;#make one with no arguments, just to ensure that the time condition is evaluated whenever the scope is accessed. &lt;br /&gt;class Post&lt;br /&gt;  named_scope :recent, lambda { {:conditions =&gt; 1.week.ago}}&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#Active Record will perform that interpolation again at the point where sql is generated&lt;br /&gt;class Person &lt; ActiveRecord::Base&lt;br /&gt;  has_many :recent_posts, :class_name =&gt; 'Post', &lt;br /&gt;           :conditions =&gt; "created_at &gt; #{1.week.ago.to_s(:db)}"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#Validations can't play any of the clever little games that the other 2 examples can. You'll just have to something like&lt;br /&gt;class Person &lt; ActiveRecord::Base&lt;br /&gt;  validate_on_create :is_a_teenager&lt;br /&gt;&lt;br /&gt;  def is_a_teenager&lt;br /&gt;    unless birth_date &lt; 13.years.ago &amp;&amp; birth_date &gt; 20.years.ago&lt;br /&gt;      ...&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-7326420114635944497?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/7326420114635944497/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=7326420114635944497' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/7326420114635944497'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/7326420114635944497'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/10/hasmany-time-now-assocation.html' title='has_many , time now, assocation'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-7876497267631881696</id><published>2009-10-02T17:22:00.001+08:00</published><updated>2009-10-02T17:24:22.760+08:00</updated><title type='text'>跨browser 播音樂</title><content type='html'>&lt;a href="http://www.htmlcodetutorial.com/embeddedobjects/_EMBED.html"&gt;http://www.htmlcodetutorial.com/embeddedobjects/_EMBED.html&lt;/a&gt;&lt;br /&gt;&lt;textarea name="code" class="html"&gt;&lt;br /&gt;&lt;[embed src="symphony.mid" autostart="false" width="0" height="0" id="music"]&gt;&lt;br /&gt;&lt;br /&gt;var music = $("#music")[0];&lt;br /&gt;music.Stop();&lt;br /&gt;&lt;br /&gt;music.Play();&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-7876497267631881696?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/7876497267631881696/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=7876497267631881696' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/7876497267631881696'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/7876497267631881696'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/10/browser.html' title='跨browser 播音樂'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-2602187356551927286</id><published>2009-10-01T09:03:00.004+08:00</published><updated>2009-10-06T14:28:53.009+08:00</updated><title type='text'>Facebook app memo</title><content type='html'>&lt;a href="http://brantinteractive.com/2008/03/15/facebook-development-choosing-fbml-or-iframe-as-your-application-type/"&gt;Facebook development: choosing FBML or iframe as your application type&lt;/a&gt;&lt;br /&gt;&lt;a href="http://apps.new.facebook.com/facebooker_tutorial/"&gt;http://apps.new.facebook.com/facebooker_tutorial/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;1. Set up New application&lt;br /&gt;http://www.facebook.com/developers/&lt;br /&gt;&lt;br /&gt;2. remember your api key and serect key&lt;br /&gt;&lt;br /&gt;3. Canvas/畫布 setting&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;api key, serect key&lt;br /&gt;&lt;br /&gt;they let our application verify that requests are coming from Facebook.&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;Facebook sends us the ID of the current user and their whole list of friends on&lt;br /&gt;every request. That makes our life quite a bit easier. It also can cause&lt;br /&gt;some security problems.&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;All requests come from Facebook. To make sure this is the case, we can&lt;br /&gt;verify the signature that is sent by Facebook on every request. A digital&lt;br /&gt;signature is a way to use cryptography to verify that something actually&lt;br /&gt;came from the person who it appears to be from.4 Facebook sends a&lt;br /&gt;number of parameters that start with fb_sig. All these parameters are&lt;br /&gt;used in the signature validation.&lt;br /&gt;&lt;br /&gt;When Facebook sends our applications a request, it builds a string&lt;br /&gt;that includes all the fb_sig parameters in alphabetical order. It then&lt;br /&gt;adds our secret key to the end of that string and calculates the MD5 sum.&lt;br /&gt;&lt;br /&gt;When Facebooker receives a request, it goes through the&lt;br /&gt;same steps to recalculate the signature. If the value that Facebooker&lt;br /&gt;calculates matches the one in our request, it proves that the request&lt;br /&gt;came from somebody who knows our secret key.&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;Rails included a feature to stop cross-site forgery&lt;br /&gt;attacks. Unfortunately, this feature doesn’t play well with Facebook.&lt;br /&gt;We’ll need to disable it by editing environment.rb and setting allow_forgery_&lt;br /&gt;protection to false,&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;hr&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-2602187356551927286?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/2602187356551927286/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=2602187356551927286' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2602187356551927286'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/2602187356551927286'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/10/facebook-app-memo.html' title='Facebook app memo'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-1661420896896061220</id><published>2009-09-29T14:12:00.003+08:00</published><updated>2009-09-30T10:01:00.330+08:00</updated><title type='text'>Session Management</title><content type='html'>When a new session is created, Rails automatically sends a cookie to the browser containing the session id&lt;br /&gt;&lt;br /&gt;The data structure takes the form of a hash, identified by a unique session id, a 32-character string of random hex number&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Disabling Sessions for Robots&lt;/span&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;class ApplicationController &lt; ActionController::Base&lt;br /&gt;session :off, :if =&gt; lambda {|req| req.user_agent =~/(Google|Slurp)/i}&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;Selectively Enabling Sessions&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;class ApplicationController &lt; ActionController::Base&lt;br /&gt;session :off&lt;br /&gt;&lt;br /&gt;#You can’t say session :on in a subclass of ApplicationController—it won’t work, but surprisingly, you can say session :disable =&gt; false.&lt;br /&gt;&lt;br /&gt;class AdminController &lt; ApplicationController&lt;br /&gt;session :disable =&gt; false&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;# the session will only work over HTTPS&lt;br /&gt;session :session_secure =&gt; true&lt;/textarea&gt;&lt;br /&gt;The Controversial CookieStore&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;class CGI::Session::CookieStore&lt;br /&gt;def generate_digest(data)&lt;br /&gt;# replace this line with your own encryption logic&lt;br /&gt;Digest::SHA512.hexdigest “#{data}#{@secret}”&lt;br /&gt;end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#Another problem with cookie-based session storage is its vulnerability to replay&lt;br /&gt;attacks&lt;br /&gt;The short answer is: Do not store sensitive data in the session. Ever. The longer&lt;br /&gt;answer is that coordination of nonces across multiple servers would require remote&lt;br /&gt;process interaction on a per-request basis, which negates the benefits of using the&lt;br /&gt;cookie session storage to begin with.&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;Timing Out and Session Life Cycle&lt;br /&gt;Session Timeout Plugin for Rails&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;class ApplicationController &lt; ActionController::Base&lt;br /&gt;session_times_out_in 20.minutes,&lt;br /&gt;:after_timeout =&gt; proc {|controller| logger.info “Session expired”&lt;br /&gt;}&lt;br /&gt;end&lt;/textarea&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&gt;&gt; CGI::Session::ActiveRecordStore::Session.find:first&lt;br /&gt;=&gt; #&lt;CGI::Session::ActiveRecordStore::Session:0x26fe65c&lt;br /&gt;&lt;br /&gt;@attributes={“updated_at”=&gt;”2006-11-29 02:06:01”,&lt;br /&gt;“session_id”=&gt;”73bb9cd7fd19a5c1cae8cd0fda0cb6bb”, “id”=&gt;”1”,&lt;br /&gt;“data”=&gt;”BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNo\nSG&lt;br /&gt;FzaHsABjoKQHVzZWR7AA==\n”}&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;Cookies&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;#If you are really intent on being able to access cookies in your helpers or views,there is a simple solution. Simply declare cookies to be a helper method:&lt;br /&gt;&lt;br /&gt;class MyController &lt; ActionController::Base&lt;br /&gt;helper_method :cookies&lt;/textarea&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;cookies[:login] = {:value =&gt; @user.security_token,&lt;br /&gt;:domain =&gt; ‘.domain.com’,&lt;br /&gt;:expires =&gt; Time.now.next_year }&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-1661420896896061220?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/1661420896896061220/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=1661420896896061220' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1661420896896061220'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1661420896896061220'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/blog-post_29.html' title='Session Management'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-8973264753546001784</id><published>2009-09-25T06:31:00.009+08:00</published><updated>2010-01-05T00:22:30.261+08:00</updated><title type='text'>Heroku memo</title><content type='html'>&lt;a href="http://remi.org/2009/04/23/deploying-rails-and-rack-applications-to-heroku.html"&gt;Deploying Ruby Web Applications to Heroku&lt;/a&gt;&lt;br /&gt;&lt;a href="http://docs.heroku.com/custom-domains"&gt;custom domain&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.dbanotes.net/arch/heroku_architecture.html"&gt;學習 HeroKu 的架構設計&lt;/a&gt;&lt;br /&gt;&lt;a href="http://tammersaleh.com/posts/automatically-generate-heroku-gems-file"&gt;generate gem file by rake&lt;/a&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;sudo gem install heroku&lt;br /&gt;&lt;br /&gt;heroku list&lt;br /&gt;&lt;br /&gt;heroku create&lt;br /&gt;&lt;br /&gt;git push heroku master&lt;br /&gt;&lt;br /&gt;#done&lt;br /&gt;&lt;br /&gt;#刪除&lt;br /&gt;demo$ heroku destroy --app sharp-warrior-99&lt;br /&gt;&lt;br /&gt;#&lt;br /&gt;heroku db:push&lt;br /&gt;（這個命令會使用taps，如果沒有安裝，請先安裝。）&lt;br /&gt;&lt;br /&gt;#-----------------memo&lt;br /&gt;=== Example:&lt;br /&gt;rails myapp&lt;br /&gt;cd myapp&lt;br /&gt;git init&lt;br /&gt;git add .&lt;br /&gt;git commit -m "my new app"&lt;br /&gt;heroku create&lt;br /&gt;git push heroku master&lt;br /&gt;#-----------------&lt;br /&gt;&lt;br /&gt;#----------------memo2&lt;br /&gt;Permission denied (publickey).&lt;br /&gt;fatal: The remote end hung up unexpectedly&lt;br /&gt;:$ heroku keys:add&lt;br /&gt;#----------------&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#----------------memo3&lt;br /&gt;heroku rake gems:install --app [app-name]&lt;br /&gt;&lt;br /&gt;#Push database onto heroku&lt;br /&gt;heroku db:push&lt;br /&gt;&lt;br /&gt;#Push config onto heroku&lt;br /&gt;rake heroku:config --app [heroku app name]&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-8973264753546001784?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/8973264753546001784/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=8973264753546001784' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8973264753546001784'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8973264753546001784'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/heroku-memo.html' title='Heroku memo'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-830515322956578409</id><published>2009-09-23T21:15:00.001+08:00</published><updated>2009-09-23T21:20:34.996+08:00</updated><title type='text'>亂看 redmine code memo</title><content type='html'>&lt;textarea name="code" class="ruby"&gt;  def self.up&lt;br /&gt;    create_table :groups_users, :id =&gt; false do |t|&lt;br /&gt;      t.column :group_id, :integer, :null =&gt; false&lt;br /&gt;      t.column :user_id, :integer, :null =&gt; false&lt;br /&gt;    end&lt;br /&gt;    add_index :groups_users, [:group_id, :user_id], :unique =&gt; true, :name =&gt; :groups_users_ids&lt;br /&gt;  end&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-830515322956578409?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/830515322956578409/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=830515322956578409' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/830515322956578409'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/830515322956578409'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/redmine-code-memo.html' title='亂看 redmine code memo'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-3767662250638771888</id><published>2009-09-22T18:04:00.002+08:00</published><updated>2009-09-22T18:08:37.978+08:00</updated><title type='text'>A Month in Rails</title><content type='html'>&lt;a href="http://weblog.rubyonrails.org/2009/9/2/a-month-in-rails"&gt;A Month in Rails&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Master-slave&lt;br /&gt;&lt;a href="http://codeshooter.wordpress.com/2009/08/24/why-i-am-not-using-masochism-for-my-master-slave-setups-and-why-monkey-patching-isn%E2%80%99t-the-only-solution/"&gt;Why I am not using Masochism for my master-slave setups and why monkey-patching isn’t the only solution&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Password security&lt;br /&gt;&lt;a href="http://blog.phusion.nl/2009/08/13/securely-store-passwords-with-bcrypt-ruby-now-compatible-with-jruby-and-ruby-1-9/"&gt;&lt;br /&gt;Securely store passwords with bcrypt-ruby; now compatible with JRuby and Ruby 1.9&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;A rails plugin to store a collection of boolean attributes in a single ActiveRecord column as a bit field.&lt;br /&gt;把boolean 欄位用一個integer column 取代&lt;br /&gt;&lt;a href="http://github.com/xing/flag_shih_tzu"&gt;flag_shih_tzu&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;security model&lt;br /&gt;&lt;a href="http://www.mashd.cc/tag/lockbox"&gt;acts_as_lockbox for your Rails Models&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-3767662250638771888?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/3767662250638771888/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=3767662250638771888' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/3767662250638771888'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/3767662250638771888'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/month-in-rails.html' title='A Month in Rails'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-454102107312264083</id><published>2009-09-22T17:17:00.002+08:00</published><updated>2009-09-22T17:29:30.322+08:00</updated><title type='text'>Observational: Better Observers for ActiveRecord</title><content type='html'>&lt;a href="http://jamesgolick.com/2009/8/5/observational-better-observers-for-activerecord.html"&gt;Observational: Better Observers for ActiveRecord&lt;/a&gt;&lt;br /&gt;一個比較好的observer&lt;br /&gt;1. 老地方, 可是寄信基本上這應該不干 User 的事, 所以把它搬走&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;class User&lt;br /&gt;  after_create :send_welcome_email&lt;br /&gt;&lt;br /&gt;  protected&lt;br /&gt;    def send_welcome_email&lt;br /&gt;      Notifier.deliver_welcome_email(self)&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;2. 把它搬到 observer 裡, 可是如果很多地方都要寄信, 就很麻煩, 要多一堆file&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;class UserObserver &lt; ActiveRecord::Observer&lt;br /&gt;  def after_create(user)&lt;br /&gt;    Notifier.deliver_welcome_email(user)&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;3. 所以就搬到寄信的地方 然後由它observe 看起來合情合理&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;class Notifier &lt; ActionMailer::Base&lt;br /&gt;  observes :user, :after =&gt; :create, :invokes =&gt; :deliver_welcome_email&lt;br /&gt;&lt;br /&gt;  def welcome_email(user)&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-454102107312264083?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/454102107312264083/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=454102107312264083' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/454102107312264083'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/454102107312264083'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/observational-better-observers-for.html' title='Observational: Better Observers for ActiveRecord'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-8402349942740797871</id><published>2009-09-22T15:32:00.000+08:00</published><updated>2009-09-22T15:34:50.339+08:00</updated><title type='text'>cookie, session and request object</title><content type='html'>* Cookie物件&lt;br /&gt;&lt;br /&gt;Cookie物件會藉由瀏覽器所提供Cookie功能,將資訊記錄在用戶端電腦裡面,也就是利用Cookie物件來紀錄判斷某個使用者是否曾經進入本網站,當瀏覽者離線,Cookie物件資料紀錄仍然存在用戶端電腦.(當瀏覽器停用cookie設定,此功能就會失效)&lt;br /&gt;&lt;br /&gt;Session物件:紀錄Session中的各種描述資訊與邏輯關係,和Cookie不同的是Session可以儲存任意的物件.&lt;br /&gt;Session處理過程:&lt;br /&gt;當伺服器皆收用戶發送的請求後,ROR就會尋找一用戶Session ID,如果沒有該用戶Session ID,會立即建立一個Session,並且分配Session ID,同時同Cookie形式將Session ID保存到用戶瀏覽器上面.之後ROR會根據Session ID來找到保存在伺服器端的Session資料,並且利用Session物件來對Session做各種操作.&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;    * request物件:應用於使用者各種請求,它允許開發者透過某些方法來請求資訊.&lt;br /&gt;&lt;br /&gt;常用方法:&lt;br /&gt;1.delete? (用於確定是否為一個刪除操作要求)&lt;br /&gt;2.get? (用於確定是否為一個GET的請求)&lt;br /&gt;3.post? (用於確定是否為一個POST請求)&lt;br /&gt;4.host (用於取得使用者主機的IP位置)&lt;br /&gt;5.protocol(用於確定請求的協議類型)&lt;br /&gt;6.env (用於取得環境變數的資訊)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-8402349942740797871?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/8402349942740797871/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=8402349942740797871' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8402349942740797871'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8402349942740797871'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/cookie-session-and-request-object.html' title='cookie, session and request object'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-1733967622328963438</id><published>2009-09-22T11:10:00.001+08:00</published><updated>2009-09-22T11:11:50.625+08:00</updated><title type='text'>cron job 跑rake</title><content type='html'>&lt;a href="http://joshuahoover.com/2008/08/23/how-to-schedule-a-ruby-on-rails-rake-task-via-cron/"&gt;How to Schedule a Ruby on Rails Rake Task Via Cron&lt;/a&gt;&lt;br /&gt;*/5 * * * * cd /var/www/apps/rails_app/ &amp;&amp; /usr/local/bin/rake RAILS_ENV=production rake_task:goes_here&lt;br /&gt;&lt;br /&gt;注意它是用 /usr/local/bin/rake&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-1733967622328963438?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/1733967622328963438/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=1733967622328963438' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1733967622328963438'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1733967622328963438'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/cron-job-rake.html' title='cron job 跑rake'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-8065529396392001931</id><published>2009-09-15T05:57:00.004+08:00</published><updated>2009-09-17T15:44:37.347+08:00</updated><title type='text'>git memo</title><content type='html'>&lt;a href="http://ihower.idv.tw/blog/archives/2591"&gt;Git 版本控制系統 (1)&lt;/a&gt;&lt;br /&gt;&lt;a href="http://ihower.idv.tw/blog/archives/2620"&gt;Git 版本控制系統(2) 開 branch 分支和操作遠端 repo.&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.qweruiop.org/nchcrails/posts/49"&gt;Git 原始碼管理&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.dotblogs.com.tw/billy3321/archive/2009/02/06/7064.aspx"&gt;使用Git與Github管理軟體開發專案&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;git add . 加入所有檔案，包括所有還沒有被追蹤(untracked)的檔案&lt;br /&gt;git add -i 進入互動模式，你甚至可以只 Add 檔案裡面其中的一段程式碼到 staging area 去(稱作patch)&lt;br /&gt;git add -u 只加更新的檔案，不加入還沒有追蹤的檔案 (跟 git commit -a 涵蓋的範圍相同)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;git commit -m "blah" 如果沒加 -m 的話, 會開編輯器輸入 commit log (可以在.gitconfig中設定編輯器)&lt;br /&gt;git commit -a -m "foobar" 全部修改的檔案都 add 後 commit 出去 (不包括 untracked 的新檔案)&lt;br /&gt;git commit -v 會開編輯器加上 diff 註解&lt;br /&gt;&lt;br /&gt;git rm foobar 刪除&lt;br /&gt;git mv old_file new_file 改檔名&lt;br /&gt;&lt;br /&gt;git diff 是比較 working tree 跟 staging area&lt;br /&gt;git diff --cached 是比較 staging area 跟本來的 repo.&lt;br /&gt;git diff HEAD 是比較 working tree 跟本來的 repo.&lt;br /&gt;&lt;br /&gt;git reset HEAD filename 會從 staging area 狀態回到 unstaging 或 untracked (檔案內容並不會改變)&lt;br /&gt;git checkout filename 會從 unstaging 狀態回到最初 repo. 的檔案(檔案內容變回修改前)&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;git branch &lt;new_branch_name&gt; 建立本地 local branch&lt;br /&gt;git branch -m &lt;old_name&gt; &lt;new_name&gt; 改名字 (如果有同名會失敗，改用 -M 可以強制覆蓋)&lt;br /&gt;git branch 列出目前有那些 branch 以及目前在那個 branch&lt;br /&gt;git checkout &lt;branch_name&gt; 切換 branch (注意到如果你有檔案修改了卻還沒 commit，會不能切換 branch，解法稍後會談)&lt;br /&gt;git checkout -b &lt;new_branch_name&gt; (&lt;from_branch_name&gt;) 本地建立 branch 並立即 checkout 切換過去&lt;br /&gt;git branch -d &lt;branch_name&gt; 刪除 local branch&lt;br /&gt;&lt;br /&gt;git merge &lt;branch_name&gt; 合併另一個 branch，若沒有 conflict 衝突會直接 commit。若需要解決衝突則會再多一個 commit。&lt;br /&gt;git merge --squash &lt;branch_name&gt; 將另一個 branch 的 commit 合併為一筆，特別適合需要做實驗的 fixes bug 或 new feature，最後只留結果。合併完不會幫你先 commit。&lt;br /&gt;git cherry-pick 321d76f 只合併特定其中一個 commit。如果要合併多個，可以加上 -n 指令就不會先幫你 commit，這樣可以多 pick幾個要合併的 commit，最後再 git commit 即可。&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;git push 預設的遠端是 origin，並且會將所有有和 remote 有對應的 local branch 都 push 上去。如果要把新的 local branch push 上去，需要下 git push origin &lt;local_vranch_name&gt; 指令。&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;如果今天tom的test repo有了新的變更，告訴billy，billy要將變更merge到自己的repo中，可以在本地端輸入&lt;br /&gt;&lt;br /&gt;    git pull git://github.com/tom/test.git&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;pull這個指令其實涵蓋了fetch(將變更複製回來)以及merge。&lt;br /&gt;因此經過merge後，tom的變更就加入到billy的repo囉！&lt;br /&gt;&lt;br /&gt;另外版本控制系統的branch功能也很有意思，若您的程式碼同時要修改bug，又要加入新功能，可以fork出一個branch，一個專門修bug，一個專門加入新功能，等到穩定後再來merge&lt;br /&gt;&lt;br /&gt;    git branch bug_fix #建立branch，名為bug_fix&lt;br /&gt;    git checkout bug_fix #切換到bug_fix這個branch&lt;br /&gt;    git checkout master #換為主要的repo&lt;br /&gt;    git merge bug_fix #把bug_fix這個branch和現在的branch合併&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;若有branch在remote，想要查看並checkout出來&lt;br /&gt;&lt;br /&gt;    git branch -r #查看遠端branch&lt;br /&gt;    git checkout -b bug_fix_local bug_fix_remote #把本機端切換為遠端的bug_fix_remote branch，並命名為bug_fix_local&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;還有其他可以觀看repo狀態的工具&lt;br /&gt;&lt;br /&gt;    git log #可以查看每次commit的改變&lt;br /&gt;    git diff #可以查看最近一次改變的內容，加上參數可以看其他的改變，並互相比較&lt;br /&gt;    git show #可以看某次的變更&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-8065529396392001931?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/8065529396392001931/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=8065529396392001931' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8065529396392001931'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8065529396392001931'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/git-memo_15.html' title='git memo'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-837950993793901012</id><published>2009-09-14T21:17:00.001+08:00</published><updated>2009-09-14T21:19:12.516+08:00</updated><title type='text'>如何設計有效的佈局？</title><content type='html'>&lt;a href="http://ucdchina.com/snap/4684"&gt;如何設計有效的佈局？&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;將任務相關的重要信息要直接表現在控件上。用戶更傾向於關注交互控件上的標籤，而不是輔助型的靜態文本。&lt;br /&gt;&lt;br /&gt;    * 以8px為橫向柵格單位，頁面所有元素寬度都可以是2的倍數，包括圖片和版塊寬度，這樣可以在一定程度上加快頁面（特別是對於J-PEG圖片）的渲染速度（基於計算機內部二進制的運算機制）。其在擴展和兼容性上也有一定優勢。&lt;br /&gt;&lt;br /&gt;    * 在阿里巴巴中文站中，佈局間距的最小單位為8px，佈局區塊採用32px（8px*4）和24（8px*3）兩種粒度單位，分別組成以下兩種可實現的柵格系統：&lt;br /&gt;&lt;br /&gt;在綜合考慮當下主流分辨率情況、瀏覽器外觀對顯示空間的佔用、人機工程學中對水平視角和聚焦範圍的規定以及8px單位等多種因素後，我們認為960px是一個相對更加合理的頁面寬度。在阿里巴巴中文網站中，推薦使用定寬960px的頁面，去除左右各4px的邊距，中間的可視寬度為952px。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-837950993793901012?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/837950993793901012/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=837950993793901012' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/837950993793901012'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/837950993793901012'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/blog-post.html' title='如何設計有效的佈局？'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-1394990769726266075</id><published>2009-09-14T10:40:00.001+08:00</published><updated>2009-09-14T10:44:12.130+08:00</updated><title type='text'>網頁編碼問題  與  META</title><content type='html'>&lt;a href="http://blog.miniasp.com/post/2007/11/Explain-A-frequently-used-META-content-type.aspx"&gt;一個常用又不知道是做什麼用的 META 設定 &lt;/a&gt;&lt;br /&gt;&lt;br /&gt;正確來說，這段 META 是定義「網頁送出的編碼字集」，而不是用來定義「該網頁應該顯示的字集」！ &lt;br /&gt;&lt;a href="http://blog.miniasp.com/post/2009/09/How-browser-handle-web-character-encoding.aspx"&gt;&lt;br /&gt;關於各瀏覽器對網頁與文字編碼的處理規則研究整理 &lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;當你的網頁編碼為 Big5 字集，但你需要表單送出時用 GB2312 字集送出的話，就可以利用以下步驟完成此任務：&lt;br /&gt;&lt;br /&gt;1. 伺服器回應網頁要求時明確指定瀏覽器應顯示的字集&lt;br /&gt;&lt;br /&gt;Response.ContentType = "text/html; charset=big5";&lt;br /&gt;&lt;br /&gt;2. 在網頁 HTML 中加入 META 標籤，明確指定 Content-Type 與字集&lt;br /&gt;&lt;br /&gt;&lt;[meta http-equiv="Content-Type" content="text/html; charset=gb2312" /]&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-1394990769726266075?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/1394990769726266075/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=1394990769726266075' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1394990769726266075'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1394990769726266075'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/meta.html' title='網頁編碼問題  與  META'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-8264964452837932037</id><published>2009-09-14T06:31:00.001+08:00</published><updated>2009-09-14T06:33:25.691+08:00</updated><title type='text'>git memo</title><content type='html'>github 不知道為為啥我複製出來的網址是https 的&lt;br /&gt;所以跑出 &lt;span style="font-weight:bold;"&gt;remote HEAD refers to nonexistent ref, unable to checkout&lt;/span&gt;. 的錯誤&lt;br /&gt;&lt;br /&gt;git clone git@github.com:ooxx 這樣的才對&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-8264964452837932037?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/8264964452837932037/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=8264964452837932037' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8264964452837932037'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8264964452837932037'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/git-memo.html' title='git memo'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-6579405324881377361</id><published>2009-09-13T12:02:00.005+08:00</published><updated>2010-04-20T16:21:50.667+08:00</updated><title type='text'>Railscast skill(9)</title><content type='html'>&lt;a href="http://railscasts.com/episodes/99-complex-partials"&gt;Complex Partials&lt;/a&gt;&lt;br /&gt;&lt;a href="http://mmm.javaeye.com/blog/115307"&gt;Rendering partials with layouts&lt;/a&gt;&lt;br /&gt;view 重複的部份  不只是裡面 也有可能是外面, render 的參數也可以代layout&lt;br /&gt;Partials can have their own layouts applied to them. These layouts are different than the ones that are specified globally&lt;br /&gt;for the entire action, but they work in a similar fashion. Imagine a list with two types of users: &lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;    &lt;% render(:layout =&gt; "administrator", :locals =&gt; { :user =&gt; chief }) do %&gt;  &lt;br /&gt;      Title: &lt;%= chief.title %&gt;  &lt;br /&gt;    &lt;% end %&gt;  &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   &lt;!-- app/views/users/_administrator.html.erb --&gt; &lt;br /&gt;   &lt;div id="administrator"&gt;  &lt;br /&gt;      Budget: $&lt;%= user.budget %&gt;  &lt;br /&gt;      &lt;%= yield if block_given? %&gt;&lt;br /&gt;    &lt;/div&gt;  &lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://railscasts.com/episodes/39-customize-field-error"&gt;Customize Field Error&lt;/a&gt;&lt;br /&gt;可以自訂error msg 的格式&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;# environment.rb&lt;br /&gt;ActionView::Base.field_error_proc = Proc.new do |html_tag, instance_tag|&lt;br /&gt;  "&lt;span class='field_error'&gt;#{html_tag}&lt;/span&gt;"&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-6579405324881377361?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/6579405324881377361/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=6579405324881377361' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/6579405324881377361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/6579405324881377361'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/railscast-skill9.html' title='Railscast skill(9)'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-1054004146138757697</id><published>2009-09-11T11:14:00.005+08:00</published><updated>2009-09-17T07:16:41.664+08:00</updated><title type='text'>Railscast skill(8)</title><content type='html'>&lt;a href="http://railscasts.com/episodes/86-logging-variables"&gt;Logging Variables&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ruby-doc.org/core/classes/Kernel.html#M005922"&gt;eval&lt;/a&gt; 執行後面的 ruby code&lt;br /&gt;&lt;a href="http://www.ruby-doc.org/core/classes/Binding.html"&gt;binding&lt;/a&gt; 可以把當時的環境存起來&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;irb(main):003:0&gt; eval('1 + 2')&lt;br /&gt;=&gt; 3&lt;br /&gt;irb(main):004:0&gt; eval('[1] + [2]')&lt;br /&gt;=&gt; [1, 2]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# models/product.rb&lt;br /&gt;logger.debug_variables(binding)&lt;br /&gt;&lt;br /&gt;#想替logger object 加 method, 可是因為需要當時的環境 來拿它的 local_variables 和 instance_variables&lt;br /&gt;# config/initializers/logger_additions.rb&lt;br /&gt;logger = ActiveRecord::Base.logger&lt;br /&gt;def logger.debug_variables(bind)&lt;br /&gt;  vars = eval('local_variables + instance_variables', bind)&lt;br /&gt;  vars.each do |var|&lt;br /&gt;    debug  "#{var} = #{eval(var, bind).inspect}"&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://railscasts.com/episodes/56-the-logger"&gt;The Logger&lt;/a&gt;&lt;br /&gt;message 四個等級 debug, info , error, fatal&lt;br /&gt;development default 是 debug, 表示debug 以上的都可以看到, mysql instruction message 是在debug mode 所以  production 看不到&lt;br /&gt;production  是 info&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;# 可以自己overwrite message format&lt;br /&gt;# environment.rb&lt;br /&gt;Rails::Initializer.run do |config|&lt;br /&gt;  config.active_record.colorize_logging = false&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class Logger&lt;br /&gt;  def format_message(level, time, progname, msg)&lt;br /&gt;    "#{time.to_s(:db)} #{level} -- #{msg}\n"&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# 可以自己設定自己想看的level&lt;br /&gt;# 或者是overwrite 掉 logger object&lt;br /&gt;# environments/production.rb&lt;br /&gt;config.log_level = :debug&lt;br /&gt;config.logger = Logger.new(...) # or log4r&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#讓你在console執行指令也可以看到 mysql output&lt;br /&gt;# ~/.irbrc&lt;br /&gt;if ENV.include?('RAILS_ENV') &amp;&amp; !Object.const_defined?('RAILS_DEFAULT_LOGGER')&lt;br /&gt;  require 'logger'&lt;br /&gt;  RAILS_DEFAULT_LOGGER = Logger.new(STDOUT)&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://railscasts.com/episodes/85-yaml-configuration-file"&gt;YAML Configuration File&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;整理變數的好方法, 放在yml 裡, 還可以靠程式根據不同的環境load 進不同的變數&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;# config/initializers/load_config.rb&lt;br /&gt;APP_CONFIG = YAML.load_file("#{RAILS_ROOT}/config/config.yml")[RAILS_ENV]&lt;br /&gt;&lt;br /&gt;# config/config.yml&lt;br /&gt;development:&lt;br /&gt;  perform_authentication: false&lt;br /&gt;&lt;br /&gt;test:&lt;br /&gt;  perform_authentication: false&lt;br /&gt;&lt;br /&gt;production:&lt;br /&gt;  perform_authentication: true&lt;br /&gt;  username: admin&lt;br /&gt;  password: secret&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-1054004146138757697?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/1054004146138757697/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=1054004146138757697' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1054004146138757697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/1054004146138757697'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/railscast-skill8.html' title='Railscast skill(8)'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-577249839536939524</id><published>2009-09-10T21:40:00.003+08:00</published><updated>2009-09-10T22:07:01.392+08:00</updated><title type='text'>Railscast skill (7)</title><content type='html'>&lt;a href="http://railscasts.com/episodes/28-in-groups-of"&gt;in_groups_of&lt;/a&gt;&lt;br /&gt;定量分組時在用的&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;&lt;!-- tasks/index.rhtml --&gt;&lt;br /&gt;&lt;table&gt;&lt;br /&gt;&lt;% @tasks.in_groups_of(4, false) do |row_tasks| %&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;% for task in row_tasks %&gt;&lt;br /&gt;      &lt;td&gt;&lt;%= task.name %&gt;&lt;/td&gt;&lt;br /&gt;    &lt;% end %&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;&lt;% end %&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://railscasts.com/episodes/29-group-by-month"&gt;group_by Month&lt;/a&gt;&lt;br /&gt;group_by 好棒, 想用啥分類就分&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;# tasks_controller.rb&lt;br /&gt;def index&lt;br /&gt;  @tasks = Task.find(:all, :order =&gt; 'due_at, id', :limit =&gt; 50)&lt;br /&gt;  @task_months = @tasks.group_by { |t| t.due_at.beginning_of_month }&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- tasks/index.rhtml --&gt;&lt;br /&gt;&lt;% @task_months.sort.each do |month, tasks| %&gt;&lt;br /&gt;  &lt;h2&gt;&lt;%= month.strftime('%B') %&gt;&lt;/h2&gt;&lt;br /&gt;  &lt;% for task in tasks %&gt;&lt;br /&gt;    &lt;div class="task"&gt;&lt;br /&gt;      &lt;strong&gt;&lt;%= task.name %&gt;&lt;/strong&gt;&lt;br /&gt;      due on &lt;%= task.due_at.to_date.to_s(:long) %&gt;&lt;br /&gt;    &lt;/div&gt;&lt;br /&gt;  &lt;% end %&gt;&lt;br /&gt;&lt;% end %&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-577249839536939524?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/577249839536939524/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=577249839536939524' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/577249839536939524'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/577249839536939524'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/railscast-skill-7.html' title='Railscast skill (7)'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-481310297554185282</id><published>2009-09-10T15:11:00.006+08:00</published><updated>2009-09-10T18:33:59.608+08:00</updated><title type='text'>Railscast skill (6)</title><content type='html'>&lt;a href="http://railscasts.com/episodes/20-restricting-access"&gt;Restricting Access&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;helper_method 可以把某些controller 的method 弄到helper 一起用&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;&lt;!-- episodes/index.rhtml --&gt;&lt;br /&gt;&lt;% if admin? %&gt;&lt;br /&gt;  &lt;%= link_to 'New Episode', new_episode_path %&gt;&lt;br /&gt;&lt;% end %&gt;&lt;br /&gt;&lt;br /&gt;# controllers/application.rb&lt;br /&gt;helper_method :admin?&lt;br /&gt;&lt;br /&gt;protected&lt;br /&gt;&lt;br /&gt;def admin?&lt;br /&gt;  false&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def authorize&lt;br /&gt;  unless admin?&lt;br /&gt;    flash[:error] = "unauthorized access"&lt;br /&gt;    redirect_to home_path&lt;br /&gt;    false&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# episodes_controller.rb&lt;br /&gt;before_filter :authorize, :except =&gt; :index&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://railscasts.com/episodes/48-console-tricks"&gt;Console Tricks&lt;/a&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;# 好一個 sandbox&lt;br /&gt;ruby script/console --sandbox&lt;br /&gt;Loading development environment in sandbox (Rails 2.2.2)&lt;br /&gt;Any modifications you make will be rolled back on exit&lt;br /&gt;&gt;&gt;&lt;br /&gt;&lt;br /&gt;# 好一個 y&lt;br /&gt;&gt;&gt; y User.first&lt;br /&gt;--- !ruby/object:User &lt;br /&gt;attributes: &lt;br /&gt;  updated_at: 2009-09-10 06:45:46&lt;br /&gt;  email_notify: "1"&lt;br /&gt;  remember: "0"&lt;br /&gt;  nickname: shlee&lt;br /&gt;  id: "1"&lt;br /&gt;&lt;br /&gt;# helper&lt;br /&gt;&gt;&gt; helper.text_field_tag :foo&lt;br /&gt;=&gt; "&lt;input id=\"foo\" name=\"foo\" type=\"text\" /&gt;"&lt;br /&gt;&lt;br /&gt;# app 好物, hash_for_............ 好物&lt;br /&gt;&gt;&gt; app.methods.grep(/_path$/)&lt;br /&gt;&gt;&gt; app.homepage_path&lt;br /&gt;=&gt; "/"&lt;br /&gt;&gt;&gt; app.hash_for_homepage_path&lt;br /&gt;=&gt; {:action=&gt;"index", :only_path=&gt;true, :controller=&gt;"tc2", :use_route=&gt;:homepage}&lt;br /&gt;&lt;br /&gt;# 可以自訂method 在 ~/.irbrc 裡&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://railscasts.com/episodes/53-handling-exceptions"&gt;Handling Exceptions&lt;/a&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;#除了在 在product.rb 裡的設定&lt;br /&gt;config.action_controller.consider_all_requests_local = false&lt;br /&gt;&lt;br /&gt;#還必須在application controller裡overwrite 掉 local_request? 這樣你在那邊用localhost:3000 它才會認出你是localhost 來的, 這樣才會丟500那種頁面給你&lt;br /&gt;# 所以其實也可以在裡面多加上 admin 的判斷 如果是admin 的話 就讓它丟那種詳細的 error message&lt;br /&gt;# application.rb&lt;br /&gt;def local_request?&lt;br /&gt;  false&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#要overwirte 一些exception 就可以在這用&lt;br /&gt;def rescue_action_in_public(exception)&lt;br /&gt;  case exception&lt;br /&gt;  when ActiveRecord::RecordNotFound&lt;br /&gt;    render :file =&gt; "#{RAILS_ROOT}/public/404.html", :status =&gt; 404&lt;br /&gt;  else&lt;br /&gt;    super&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://railscasts.com/episodes/46-catch-all-route"&gt;Catch-all Route&lt;/a&gt;&lt;br /&gt;可以利用這招把所有奇怪的route 路徑都拿去 在controller 裡面在做些有的沒的處理&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;# routes.rb&lt;br /&gt;map.connect '*path', :controller =&gt; 'redirect', :action =&gt; 'index'&lt;br /&gt;&lt;br /&gt;# redirect_controller.rb&lt;br /&gt;def index&lt;br /&gt;  product = Product.find(:first, :conditions =&gt; ["name LIKE ?", "#{params[:path].first}%"])&lt;br /&gt;  redirect_to product_path(product)&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-481310297554185282?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/481310297554185282/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=481310297554185282' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/481310297554185282'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/481310297554185282'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/railscast-skill-6.html' title='Railscast skill (6)'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-5584916414457504424</id><published>2009-09-10T10:55:00.003+08:00</published><updated>2009-09-10T12:13:30.381+08:00</updated><title type='text'>Railscast skill (5)</title><content type='html'>&lt;a href="http://railscasts.com/episodes/101-refactoring-out-helper-object"&gt;Refactoring Out Helper Object&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;某些 method 需要很多其他的小 method 可是放在application helper 裡 又不是算大家都會用到的東西, 這時候就可以把它搬到外面弄成一個class,&lt;br /&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;# application_helper.rb&lt;br /&gt;def render_stars(rating)&lt;br /&gt;  #傳self 進去&lt;br /&gt;  StarsRenderer.new(rating, self).render_stars&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# helpers/stars_renderer.rb&lt;br /&gt;class StarsRenderer&lt;br /&gt;  def initialize(rating, template)&lt;br /&gt;    @rating = rating&lt;br /&gt;    @template = template&lt;br /&gt;  end&lt;br /&gt;  &lt;br /&gt;  def render_stars&lt;br /&gt;    content_tag :div, star_images, :class =&gt; 'stars'&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  private&lt;br /&gt;  &lt;br /&gt;  def star_images&lt;br /&gt;    (0...5).map do |position|&lt;br /&gt;      star_image(((@rating-position)*2).round)&lt;br /&gt;    end.join&lt;br /&gt;  end&lt;br /&gt;  &lt;br /&gt;  def star_image(value)&lt;br /&gt;    image_tag "/images/#{star_type(value)}_star.gif", :size =&gt; '15x15'&lt;br /&gt;  end&lt;br /&gt;  &lt;br /&gt;  def star_type(value)&lt;br /&gt;    if value &lt;= 0&lt;br /&gt;      'empty'&lt;br /&gt;    elsif value == 1&lt;br /&gt;      'half'&lt;br /&gt;    else&lt;br /&gt;      'full'&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;  &lt;br /&gt;  #好技巧&lt;br /&gt;  def method_missing(*args, &amp;block)&lt;br /&gt;    @template.send(*args, &amp;block)&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://railscasts.com/episodes/103-site-wide-announcements"&gt;Site Wide Announcements&lt;/a&gt;&lt;br /&gt;又用了controller 的 javascripts 的技巧  不過這邊這個要注意一下 route 要加上format&lt;br /&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;&lt;!-- layouts/application.html.erb --&gt;&lt;br /&gt;# helper method 後面直接可以接method ㄟ 棒&lt;br /&gt;&lt;% unless current_announcements.empty? %&gt;&lt;br /&gt;&lt;div id="announcement"&gt;&lt;br /&gt;  &lt;% for announcement in current_announcements %&gt;&lt;br /&gt;    &lt;p&gt;&lt;%=h announcement.message %&gt;&lt;/p&gt;&lt;br /&gt;  &lt;% end %&gt;&lt;br /&gt;  &lt;p&gt;&lt;%= link_to_remote "Hide this message", :url =&gt; "/javascripts/hide_announcement.js" %&gt;&lt;/p&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;% end %&gt;&lt;br /&gt;&lt;br /&gt;# models/announcement.rb&lt;br /&gt;# 注意一下with_scope 用法&lt;br /&gt;def self.current_announcements(hide_time)&lt;br /&gt;  with_scope :find =&gt; { :conditions =&gt; "starts_at &lt;= now() AND ends_at &gt;= now()" } do&lt;br /&gt;    if hide_time.nil?&lt;br /&gt;      find(:all)&lt;br /&gt;    else&lt;br /&gt;      find(:all, :conditions =&gt; ["updated_at &gt; ? OR starts_at &gt; ?", hide_time, hide_time])&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# application_helper.rb&lt;br /&gt;# 直接用session 來記有沒有看過 GOOD&lt;br /&gt;def current_announcements&lt;br /&gt;  @current_announcements ||= Announcement.current_announcements(session[:announcement_hide_time])&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# javascripts_controller.rb&lt;br /&gt;def hide_announcement&lt;br /&gt;  session[:announcement_hide_time] = Time.now&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# hide_announcement.js.rjs&lt;br /&gt;page[:announcement].hide&lt;br /&gt;&lt;br /&gt;# routes.rb&lt;br /&gt;map.connect ":controller/:action.:format"&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-5584916414457504424?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/5584916414457504424/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=5584916414457504424' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/5584916414457504424'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/5584916414457504424'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/railscast-skill-5.html' title='Railscast skill (5)'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-8906114263784017617</id><published>2009-09-09T17:51:00.002+08:00</published><updated>2009-09-09T18:22:52.606+08:00</updated><title type='text'>Railscast skill (4)</title><content type='html'>&lt;a href="http://railscasts.com/episodes/30-pretty-page-title"&gt;Pretty Page Title&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;把content_for 弄簡潔了, yield 也要有default&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;# application_helper.rb&lt;br /&gt;def title(page_title)&lt;br /&gt;  content_for(:title) { page_title }&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- layouts/application.rhtml --&gt;&lt;br /&gt;&lt;[title&gt;Shoppery - &lt;%= yield(:title) || "The Place to Buy Stuff" %&gt;&lt;/title]&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://railscasts.com/episodes/69-markaby-in-helper"&gt;Markaby in Helper&lt;/a&gt;&lt;br /&gt;也可以在helper 裡用render :partial  或者是用content_tag 去拼view&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;# in helper&lt;br /&gt;def simple_error_messages_for(object_name)&lt;br /&gt;  object = instance_variable_get("@#{object_name}")&lt;br /&gt;  return if object.errors.empty?&lt;br /&gt;  &lt;br /&gt;  markaby do&lt;br /&gt;    div.error_messages! do&lt;br /&gt;      h2 "#{pluralize(object.errors.count, 'error')} occurred"&lt;br /&gt;      p "There were problems with the following fields:"&lt;br /&gt;      ul do&lt;br /&gt;        object.errors.each_full do |msg|&lt;br /&gt;          li msg&lt;br /&gt;        end&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def markaby(&amp;block)&lt;br /&gt;  Markaby::Builder.new({}, self, &amp;block)&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-8906114263784017617?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/8906114263784017617/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=8906114263784017617' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8906114263784017617'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/8906114263784017617'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/railscast-skill-4.html' title='Railscast skill (4)'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-559065491439614562</id><published>2009-09-09T16:06:00.002+08:00</published><updated>2009-09-09T16:09:04.725+08:00</updated><title type='text'>oink , logger parser, memory</title><content type='html'>&lt;a href="http://github.com/noahd1/oink/tree/master"&gt;oink&lt;/a&gt;&lt;br /&gt;Log parser to identify actions which significantly increase VM heap size&lt;br /&gt;&lt;br /&gt;可以讓log 多出memory 的紀錄&lt;br /&gt;Feb 08 11:39:54 ey33-s00302 rails[9076]: Memory usage: 316516 | PID: 9076&lt;br /&gt;&lt;br /&gt;也可做report 來查 哪些request or action 耗 memory 比較多&lt;textarea name="code" class="ruby"&gt;  $ oink --threshold=75 /tmp/logs/*&lt;br /&gt;  ---- MEMORY THRESHOLD ----&lt;br /&gt;  THRESHOLD: 75 MB&lt;br /&gt;&lt;br /&gt;  -- SUMMARY --&lt;br /&gt;  Worst Requests:&lt;br /&gt;  1. Feb 02 16:26:06, 157524 KB, SportsController#show&lt;br /&gt;  2. Feb 02 20:11:54, 134972 KB, DashboardsController#show&lt;br /&gt;  3. Feb 02 19:06:13, 131912 KB, DashboardsController#show&lt;br /&gt;  4. Feb 02 08:07:46, 115448 KB, GroupsController#show&lt;br /&gt;  5. Feb 02 12:19:53, 112924 KB, GroupsController#show&lt;br /&gt;  6. Feb 02 13:03:00, 112064 KB, ColorSchemesController#show&lt;br /&gt;  7. Feb 02 13:01:59, 109148 KB, SessionsController#create&lt;br /&gt;  8. Feb 02 06:11:17, 108456 KB, PublicPagesController#join&lt;br /&gt;  9. Feb 02 08:43:06, 94468 KB, CommentsController#create&lt;br /&gt;  10. Feb 02 20:49:44, 82340 KB, DashboardsController#show&lt;br /&gt;&lt;br /&gt;  Worst Actions:&lt;br /&gt;  10, DashboardsController#show&lt;br /&gt;  9, GroupsController#show&lt;br /&gt;  5, PublicPagesController#show&lt;br /&gt;  5, UsersController#show&lt;br /&gt;  3, MediaController#show&lt;br /&gt;  2, SportsController#show&lt;br /&gt;  1, SessionsController#create&lt;br /&gt;  1, GroupInvitesController#by_email&lt;br /&gt;  1, MediaController#index&lt;br /&gt;  1, PostsController#show&lt;br /&gt;  1, PhotoVotesController#create&lt;br /&gt;  1, AlbumsController#index&lt;br /&gt;  1, SignupsController#new&lt;br /&gt;  1, ColorSchemesController#show&lt;br /&gt;  1, PublicPagesController#join&lt;br /&gt;  1, CommentsController#create&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-559065491439614562?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/559065491439614562/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=559065491439614562' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/559065491439614562'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/559065491439614562'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/oink-logger-parser-memory.html' title='oink , logger parser, memory'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-5911068605710776971</id><published>2009-09-09T15:40:00.002+08:00</published><updated>2009-09-09T15:44:36.146+08:00</updated><title type='text'>benchmark</title><content type='html'>&lt;a href="http://blog.evanweaver.com/articles/2006/12/13/benchmark/"&gt;convenient benchmark&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;在 ~/.irbrc &lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;def benchmark&lt;br /&gt;  cur = Time.now&lt;br /&gt;  result = yield&lt;br /&gt;  print "#{cur = Time.now - cur} seconds"&lt;br /&gt;  puts " (#{(cur / $last_benchmark * 100).to_i - 100}% change)" rescue puts ""&lt;br /&gt;  $last_benchmark = cur&lt;br /&gt;  result&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;就可以在consloe 輕鬆的做benchmark&lt;br /&gt;&gt;&gt; benchmark{ User.find(2).records.wake.count}&lt;br /&gt;0.00197 seconds (-1% change)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-5911068605710776971?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/5911068605710776971/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=5911068605710776971' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/5911068605710776971'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/5911068605710776971'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/benchmark.html' title='benchmark'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-3742030057049309186</id><published>2009-09-09T15:09:00.004+08:00</published><updated>2009-09-09T15:40:22.160+08:00</updated><title type='text'>index , mysql slow qurey</title><content type='html'>&lt;a href="http://robots.thoughtbot.com/post/163627511/a-grand-piano-for-your-violin"&gt;A grand piano for your violin, 一篇關於哪些地方需要建index 的好文&lt;/a&gt;&lt;br /&gt;&lt;a href="http://blog.evanweaver.com/articles/2007/02/12/table-indexes-in-rails/"&gt;table indexes in rails &lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://plog.longwin.com.tw/post/1/234"&gt;找出 MySQL 哪些 Query 速度較慢&lt;/a&gt;&lt;br /&gt;&lt;a href="http://bbs.mychat.to/sindex.php?t736694.html"&gt; 檢查 mysql sql 效能使用 MySQL Slow Queries&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.xspace.idv.tw/bo_blog/read.php?57"&gt;MySQL 常用指令筆記(問答)&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-3742030057049309186?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/3742030057049309186/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=3742030057049309186' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/3742030057049309186'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/3742030057049309186'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/index-sql-slow-qurey.html' title='index , mysql slow qurey'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-5353041486974960019</id><published>2009-09-09T10:56:00.002+08:00</published><updated>2009-09-09T11:12:38.901+08:00</updated><title type='text'>Railscast skill  (3)</title><content type='html'>&lt;a href="http://railscasts.com/episodes/102-auto-complete-association"&gt;Auto-Complete Association&lt;/a&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;# product.rb&lt;br /&gt;def category_name&lt;br /&gt;  category.name if category&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# 注意可以用這樣生 association&lt;br /&gt;def category_name=(name)&lt;br /&gt;  self.category = Category.find_or_create_by_name(name) unless name.blank?&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# categories_controller.rb&lt;br /&gt;def index&lt;br /&gt;  @categories = Category.find(:all, :conditions =&gt; ['name LIKE ?', "%#{params[:search]}%"])&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;&lt;!-- products/_form.html.erb --&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;  &lt;%= f.label :category_name %&gt;&lt;br /&gt;  &lt;%= text_field_with_auto_complete :product, :category_name, { :size =&gt; 15 }, { :url =&gt; formatted_categories_path(:js), :method =&gt; :get, :param_name =&gt; 'search' } %&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- categories/index.js.erb --&gt;&lt;br /&gt;&lt;%= auto_complete_result @categories, :name %&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-5353041486974960019?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/5353041486974960019/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=5353041486974960019' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/5353041486974960019'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/5353041486974960019'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/railscast-skill-3.html' title='Railscast skill  (3)'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-630587874177549254.post-4220967209613534634</id><published>2009-09-08T16:33:00.006+08:00</published><updated>2009-09-08T18:22:16.550+08:00</updated><title type='text'>Screencasts skill  (II)</title><content type='html'>&lt;a href="http://railscasts.com/episodes/88-dynamic-select-menus"&gt;Dynamic Select Menus&lt;/a&gt;&lt;br /&gt;可以用生個javascript stylesheets controller 來動態生js , css&lt;br /&gt;在利用content_for 動態 include&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;# application_helper.rb&lt;br /&gt;def javascript(*files)&lt;br /&gt;  content_for(:head) { javascript_include_tag(*files) }&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def stylesheet(*files)&lt;br /&gt;  content_for(:head) { stylesheet_link_tag(*files) }&lt;br /&gt;end&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://railscasts.com/episodes/31-formatting-time"&gt;Formatting Time&lt;/a&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;# config/environment.rb&lt;br /&gt;Time::DATE_FORMATS[:due_time] = "due on %B %d at %I:%M %p"&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://railscasts.com/episodes/14-performing-calculations-on-models"&gt;Performing Calculations on Models&lt;/a&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;Task.sum(:priority)&lt;br /&gt;Task.sum(:priority, :conditions =&gt; 'complete=0')&lt;br /&gt;Task.maximum(:priority)&lt;br /&gt;Task.minimum(:priority)&lt;br /&gt;Task.average(:priority)&lt;br /&gt;p = Project.find(:first)&lt;br /&gt;p.tasks.sum(:priority)&lt;br /&gt;p.tasks.sum(:priority, :conditions =&gt; 'complete=0')&lt;br /&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://railscasts.com/episodes/59-optimistic-locking"&gt;Optimistic Locking&lt;/a&gt;&lt;br /&gt;&lt;textarea name="code" class="ruby"&gt;&lt;br /&gt;rescue ActiveRecord::StaleObjectError&lt;br /&gt;  @product.reload&lt;br /&gt;  render :action =&gt; 'conflict'&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- _form.rhtml --&gt;&lt;br /&gt;&lt;%= f.hidden_field :lock_version %&gt;&lt;br /&gt;&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/630587874177549254-4220967209613534634?l=ilakeruby.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ilakeruby.blogspot.com/feeds/4220967209613534634/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=630587874177549254&amp;postID=4220967209613534634' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4220967209613534634'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/630587874177549254/posts/default/4220967209613534634'/><link rel='alternate' type='text/html' href='http://ilakeruby.blogspot.com/2009/09/screencasts-skill-ii.html' title='Screencasts skill  (II)'/><author><name>Lake</name><uri>http://www.blogger.com/profile/14874411916695030891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_f-VYeaK4J8U/SoTGAgOJ9MI/AAAAAAAAASg/1k1avrBn7H8/S220/3529746949_b4ef6a3b62.jpg'/></author><thr:total>0</thr:total></entry></feed>
