2008年5月30日 星期五

ubuntu, Problem I meet

vim + vim.rails 爛掉http://soyunperdedor.com/node/24

firefox 位址列, 搜尋列一直閃 http://blog.candyz.org/20061027/1399

2008年5月19日 星期一

yield 用在啥時?


目的是想要拿到準確率最高的人的partial, 先從cache 拿, 拿不到再自己生出來

當然可以用一連串的 if, else 來做, 但是這樣便會把邏輯放在controller, 我們的希望是可以把邏輯儘量都放在model裡, 但是有時候又需要controller裡的一東西, 那這時當然就需要傳參數了, 當我們需要的參數一段code, 這時候就需要yield了

== controller ==
#Partial 先去cache 裡拿partial, 希望可以直接拿回需要的東西
@most_popular_users = Partial.get_cache do
users = User.most_accurate_user
@most_popular_users = render_to_string :partial => partial
end

== Partial model ==
def self.get_cache
# 先從cache 拿, 拿的到就直接回家
unless content = get_page_from_cache_or_db(key)
#拿不到就會到這邊來, 用傳進來的code 把需要的內容生出來, 存cache後 丟回去
content = yield
save_page_to_cache_and_db(key,content)
content
end


反正就是為了讓邏輯留在model 用的

2008年5月18日 星期日

will_paginate, paging_enumerator

http://errtheblog.com/posts/56-im-paginating-again
http://rock.errtheblog.com/will_paginate

PagingEnumerator 想要一次只取10筆的分頁作法
PagingEnumerator 自己去new

==controller==
@items = NewsItem.find_all_news(order, 10, params[:page])

==model==
def self.find_all_news(order, size, page)
offset = ((page.to_i.nonzero? || 1) -1 ) * size
total = NewsItem.count
total = total > 10000 ? 10000 : total
news = NewsItem.find(:all, :order => order, :limit => size, :offset => offset)
PagingEnumerator.new(size, total, false, page, 1) do news end
end

[css]relative, absolute

http://www.wowbox.com.tw/blog/article.asp?id=968
http://www.w3schools.com/css/css_positioning.asp

relative, absolute 都會受到包含自己的element的absolute或relative的position影響

並沒有absolute就不會受到影響這種事情, 自己玩一下比較清楚 absolute, relative 互相包來包去

group, distinct

http://api.rubyonrails.org/classes/ActiveRecord/Calculations/ClassMethods.html#M001342
http://www.1keydata.com/tw/sql/sqlgroupby.html
http://www.1keydata.com/tw/sql/sqldistinct.html

Record.count(:conditions => "success = true", :group => 'user_id')
每個人的成功次數

Record.calculate(:count, :all, :group => 'user_id')
給個人有幾筆紀錄

time, setTimeout, setInterval, fadeOut, callback, 跑馬燈

  1. 自己用setTimeout 做interval 比較好, 爆掉一次就讓他爆掉, 別用setInterval錯了還一直跑,利用 setTimeout 自己call 自己
  2. fadeOut後, 才做替換html的hide動作, 需要將他放到callback 裡, 不然html hide和fadeOut是同步的這樣會直接看到消失而已
  3. 可以將跑馬燈需要的option 藏起來, 像這樣藏在hidden_forum裡, 用size()可以知道裡面包含幾個

<div id='hidden_forum' style='display:none'>
<div>abc</div>
<div>def</div>
</div>

<script type="text/javascript">
var index = 0;
var shuffler;
var news;
var max_news;

function replace_news(){
index = index % max_news
news = $('#hidden_forum div:eq('+index+')').clone();
shuffler.fadeOut('slow', function() {shuffler.html(news.html()).hide().fadeIn('slow') });
index++;
if(max_news > 1) { var dummy = setTimeout(replace_news, 5000); }
}

$(function(){
max_news = $('#hidden_forum div').size();

if(max_news > 0){
shuffler = $('div.news div');
replace_news();
}
});
</script>

setTimeout, setInterval

自己用setTimeout 做interval 比較好, 爆掉一次就讓他爆掉, 別像setInterval 一直跑

rails 頁面產生的順序

content => layout, 所以如果有些include的東西如果放在layout 而且還在head 後面就不會include進來, 因為head早就生完了

==layout: application.rhtml==

<head>
... //head在這

<%= yield :page %>
</head>
<body>
<%= render :partial => 'not_include' %> // 到body才去生這個partial
</body>

==partial: not_include.rhtml==
<% content_for :page do%>
<%= javascript_include_tag "hope_in_head" %> // 想要生在head裡, 可是head早就生完了
<% end %>

trim, anchor

http://docs.jquery.com/Utilities/jQuery.trim

利用trim 去掉頭尾空白長度還是沒大於0 就是空的
$('form_element').submit()
link 如果找不到anchor 就會直接跳top, 所以要return false

if ($.trim(rsp_modal.find('#comment_content').val()).length > 0){
rsp_modal.find('form').submit();
return false;
}



設anchor
<a href="#01">GO TOP</a>

<a name="01" id="01"></a>

url_for

http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#M000912

url_for 生出的是包含host 的url, 如果不要的話有:only_path可以用
基本上站內的連結用path就好, 站外比較需要包含host

link_to 建出的的基本上都是只有path的

Rails hosting

Rails server 架設的一些觀念
http://lightyror.thegiive.net/2006/12/ruby-on-rails_30.html

買的share server的架設步驟(最便宜的方案 XD)
http://www.hostingrails.com/forums/wiki_thread/1

mod_rails for apache
http://lightyror.thegiive.net/2008/04/modrails-passenger-release.html

2008年5月8日 星期四

routes with_options

http://api.rubyonrails.org/classes/ActionController/Routing.html
http://ihower.idv.tw/blog/
http://weblog.jamisbuck.org/2007/1/24/object-with_options

#Object#with_options

最常用在 routes.rb,不過其實任意物件都可以用,他會將參數自動 merge 到 method call 的 hash 參數:

map.with_options( :controller => "people" ) do |p|
p.root :action => "index"
p.about :action => "about"
end


這樣替route 取名root , about
rails 替我們提供了url, path

root_url 可以替我們建出full path

root_path 建出的是URI path ( 沒包含host 的部份)

redirect_to root_path

2008年5月7日 星期三

db associations has_many through source class_name

http://blog.hasmanythrough.com/2007/10/30/self-referential-has-many-through
http://blog.hasmanythrough.com/2006/4/21/self-referential-through



class User
has_many :reading
end

class Reading
belongs_to :user
belongs_to :article
end

class Article
(後面兩個參數foreign_key, class_name 因符合rails的命名規則, 所以都可省略)
has_many :readings, :foreign_key => article_id, :class_name => Reading

(透過through => :readings, 從readings 那邊就可以取得user的 association)
has_many :users, :through => :readings

(正常像上面那樣就可以了, 但如果想要自己取有意義的association name 可以用source)
has_many :readers, :through => :readings, :source => :user

(還可以下條件)
has_many :readers, :through => :readings, :source => :user, :conditions => 'readings.rating > 4'
end

ruby shoallow copy deep copy

http://zeljkofilipin.com/2006/02/09/ruby-deep-copy-object/
http://phpbb.godfat.org/viewtopic.php?p=1118&sid=db10ef9c975a1b57323311804559ed83
http://saaridev.wordpress.com/2008/01/09/ruby-deep-copy/
http://www.dotnetspider.com/forum/ViewForum.aspx?ForumId=2239



1. # problem
2. a = [[0, 1], [10], 19]
3. b = a.dup
4. b[0][1] = 100 #=> b = [[0, 100], [10], 19] and a = [[0, 100], [10], 19]
b[0] = [3,4] #=> b =[[3,4], [10], 19] and a = [[0, 100], [10], 19]

看起來ruby的 copy 不夠 deep

5.
6. # solution
7. a = [[0, 1], [10], 19]
8. b = Marshal.load(Marshal.dump(a))
9. b[0][1] = 100 #=> b = [[0, 100], [10], 19] and a = [[0, 1], [10], 19]

2008年5月6日 星期二

jquery memo 6

http://blog.ericsk.org/archives/838
http://blog.ericsk.org/archives/839

append html
$('dictionary').load('a.html')



retrieving a javascript object
global jquery function

//empty each entry['term'] $('#dictionary').append($(html));
$.getJSON('b.json', function(data) {
$('#dictionary').empty();

$.each(data, function(entryIndex, entry) {
var html = '<div class="entry">';
html += '<h3 class="term">' + entry['term'] + '</h3>';
html += '<div class="part">' + entry['part'] + '</div>';
html += '<div class="definition">';
html += entry['definition'];

if (entry['quote']) {
html += '<div class="quote">';

$.each(entry['quote'], function(lineIndex, line) {
html += '<div class="quote-line">' + line + '</div>';
});

if (entry['author']) {
html += '<div class="quote-author">' + entry['author'] +'</div>';
}

html += '</div>';
}
html += '</div>';
html += '</div>';

$('#dictionary').append($(html));
});
});

executing a script
$.getScript('c.js')

Loading an XML Document

//find $entry.attr('term') length
$.get('d.xml', function(data) {
$('#dictionary').empty();

$(data).find('entry').each(function() {
var $entry = $(this);
var html = '<div class="entry">';
html += '<h3 class="term">' + $entry.attr('term') + '</h3>';
html += '<div class="part">' + $entry.attr('part') + '</div>';
html += '<div class="definition">'
html += $entry.find('definition').text();

var $quote = $entry.find('quote');

if ($quote.length) {
html += '<div class="quote">';
$quote.find('line').each(function() {
html += '<div class="quote-line">' + $(this).text() +'</ div>';
});

if ($quote.attr('author')) {
html += '<div class="quote-author">' + $quote.attr('author') + '</div>';
}

html += '</div>';
}

html += '</div>';
html += '</div>';

$('#dictionary').append($(html));
});
});

也支援XPath
$(data).find('entry[quote[@author]]').each(function() {



Performing a GET Request
$.get('e.php', {'term': $(this).text()}, function(data) {
$('#dictionary').html(data);
});
return false;

Performing a POST Request
$.post('e.php', {'term': $(this).text()}, function(data) {
$('#dictionary').html(data);
});

和下面一樣
$('#dictionary').load('e.php', {'term': $(this).text()});
return false;
return false;

Serializing a Form
$('#dictionary').load('f.php', {'term': $('input[@name="term"]').val()});
return false

和下面一樣
//serialize
$.get('f.php', $(this).find('input').serialize(), function(data)
{
$('#dictionary').html(data);
});
return false;

Keeping an Eye on the Request
ajaxStart ajaxStop

$(document).ready(function() {
$('#loading').ajaxStart(function() {
$(this).show();
}).ajaxStop(function() {
$(this).hide();
});
});

//利用callback function
$('#dictionary').hide().load('a.html', function() {
$(this).fadeIn();
});

Ajax and Events
下面這個會有event bubbling的問題

$(document).ready(function() {
var bindBehaviors = function() {
$('h3').click(function() {
$(this).toggleClass('highlighted');
});
};

bindBehaviors();
$('#letter-a .button').click(function() {
$('#dictionary').hide().load('a.html', function() {
bindBehaviors();
$(this).fadeIn();
});
});
});

利用scope bind住第一次呼叫的scope 這邊是document

//scope this
$(document).ready(function() {
var bindBehaviors = function(scope) {
$('h3', scope).click(function() {
$(this).toggleClass('highlighted');
});
};

bindBehaviors(this);

$('#letter-a .button').click(function() {
$('#dictionary').hide().load('a.html', function() {
bindBehaviors(this);
$(this).fadeIn();
});
});
});

直接把event bind在 body上來解決這個問題
$('body').click(function(event) {
if ($(event.target).is('h3')) {
$(event.target).toggleClass('highlighted');
}
});

2008年5月4日 星期日

jQuery memo 5

DOM Manipulation

插在element裡面, inside
append()
$("p").append( $("#foo")[0] );
<p>I would like to say: </p><b id="foo">Hello</b>
<p>I would like to say: <b id="foo">Hello</b></p>
appendTo
$("p").appendTo("#foo");
<p>I would like to say: </p><div id="foo"></div>
<div id="foo"><p>I would like to say: </p></div>

prepend
$("p").prepend( $("#foo")[0] );
<p>I would like to say: </p><b id="foo">Hello</b>
<p><b id="foo">Hello</b>I would like to say: </p>

prependTo
$("p").prepend( $("#foo")[0] );
<p>I would like to say: </p><b id="foo">Hello</b>
<p><b id="foo">Hello</b>I would like to say: </p>



插在element後面
after()
$("p").after( $("#foo")[0] );
<b id="foo">Hello</b><p>I would like to say: </p>
<p>I would like to say: </p><b id="foo">Hello</b>

insertAfter()
$("p").insertAfter("#foo");
<p>I would like to say: </p><div id="foo">Hello</div>
<div id="foo">Hello</div><p>I would like to say: </p>

before()
$("p").before( $("#foo")[0] );
<p>I would like to say: </p><b id="foo">Hello</b>
<b id="foo">Hello</b><p>I would like to say: </p>

insertBefore()
$("p").insertBefore("#foo");
<div id="foo">Hello</div><p>I would like to say: </p>
<p>I would like to say: </p><div id="foo">Hello</div>



wrap()
$("p").wrap("<div class='wrap'></div>");
<p>Test Paragraph.</p>
<div class='wrap'><p>Test Paragraph.</p></div>



html()
$("div").html("<b>new stuff</b>");
<div><input/></div>
<div><b>new stuff</b></div>

text()
$("p").text("<b>Some</b> new text.");
<p>Test Paragraph.</p>
<p>&lt;b&gt;Some&lt;/b&gt; new text.</p>

val()
$("input").val("test");
<input type="text" value="some text"/>
<input type="text" value="test"/>

attr()
$("img").attr("title", function() { return this.src });
<img src="test.jpg" />
<img src="test.jpg" title="test.jpg" />



empty()
$("p").empty()
<p>Hello, <span>Person</span> <a href="#">and person</a></p>
<p></p>

remove()
$("p").remove();
<p>Hello</p> how are <p>you?</p>
how are

$("p").remove(".hello");
<p class="hello">Hello</p> how are <p>you?</p>
how are <p>you?</p>



each attr rel

$('div.chapter a[@href*=wikipedia]').each(function(index) {
var $thisLink = $(this);
$thisLink.attr({
'rel': 'external',
'id': 'wikilink-' + index,
'title': 'learn more about ' + $thisLink.text() + ' at Wikipedia'
});
});



clone
$("b").clone().prependTo("p");
<b>Hello</b><p>, how are you?</p>
<b>Hello</b><p><b>Hello</b>, how are you?</p>

如果用clone(false) 下面的child就不會clone

一些特殊字串
http://www.trans4mind.com/personal_development/HTMLGuide/specialCharacters.htm

inline 和 block 的差在哪
http://www.webdesignfromscratch.com/css-block-and-inline.cfm

left and right
http://www.w3schools.com/css/css_reference.asp

2008年5月3日 星期六

jQuery memo 4


.css('property','value')
.css({property1: 'value1', 'property-2': 'value2'})



//parseFloat currentSize .css
var $speech = $('div.speech');
var currentSize = $speech.css('fontSize');
var num = parseFloat(currentSize, 10);
var unit = currentSize.slice(-2);

if (this.id == 'switcher-large') {
num *= 1.4;
} else if (this.id == 'switcher-small') {
num /= 1.4;
}
$speech.css('fontSize', num + unit);



Effect
hide show fadeIn fadeOut fadeTo slideDown slideUp animate

$('div.button').animate({left: 650, height: 38}, 'slow');

Positioning with CSS
position: relative absolute relative



Improving the custom animation
width() = .css('width')



Simultaneous versus Queued Effect
$('div.button')
.fadeTo('slow',0.5)
.animate({left: 650}, 'slow')
.fadeTo('slow',1.0)
.slideUp('slow');

//simultaneous, css這部份跟上面的effect是同步的
.fadeTo('slow',1.0);
.css('backgroundColor','#f00');

//如果要做到有順序有queue, 要靠callback function
.fadeTo('slow',1.0, function() {
$(this).css('backgroundColor','#f00');
});

jQuery memo 3


$(document).ready(function(){
if (this.id == 'switcher-narrow') {
$('body').addClass('narrow');
}
else if (this.id == 'switcher-large') {
$('body').addClass('large');
}
});


Compound Event
ready(), toggle(), hover()

toggle
$(document).ready(function() {
$('#switcher h3').toggle(function() {
$('#switcher .button').addClass('hidden');
}, function() {
$('#switcher .button').removeClass('hidden');
});
});

$(document).ready(function() {
$('#switcher h3').click(function() {
$('#switcher .button').toggleClass('hidden');
});
});


hover
$(document).ready(function() {
$('#switcher .button').hover(function() {
$(this).addClass('hover');
}, function() {
$(this).removeClass('hover');
});
});



The Journey of Event
event capturing
event bubbling



Preventing Event Bubbling

$(document).ready(function() {
$('#switcher').click(function(event) {
if (event.target == this) {
$('#switcher .button').toggleClass('hidden');
}
});
});

event.target 可以知道第一個觸發 event 的是哪個element

Stopping Event Propagation
event.stopPropagation()



Default Actions
.preventDefault() 阻止一些例如link 的預設行為

.preventDefault + .stopPropagation = return false



Removing an Event Handler

$(document).ready(function() {
var toggleStyleSwitcher = function() {
$('#switcher .button').toggleClass('hidden');
};

$('#switcher').click(toggleStyleSwitcher);

$('#switcher-narrow, #switcher-large').click(function() {
$('#switcher').unbind('click', toggleStyleSwitcher);
});
});

只執行一次toggle
$(document).ready(function() {
$('#switcher').one('click', toggleStyleSwitcher);
})



Simulating User Interaction
幫妳觸發 click

$(document).ready(function() {
$('#switcher').trigger('click');
});

$(document).ready(function() {
$('#switcher').click();
});

2008年5月2日 星期五

jQuery memo1,2

Allow multiple actions in one line, chaining

addClass(), removeClass()

$(document).ready(function(){
});

$(function(){
});



//not include class, element
$('#selectd-plays li:not(.horizontal)').addClass('sub-level');
$('tr:not([th]):even').addClass('even')

//attribute
$('a[@title]')

//element
$('div[ol]')



// ^
$('a[@href^="mailto:"]').addClass('mailto')

//$
$('a[@href$=".pdf"]').addClass('pdflink')

//*
&('a[@href*="mysite.com"]').addClass('mysite')



//js zero-based ; CSS one-based
$('div.horizontal:eq(1)')

$('tr:odd').addClass('odd') = $('tr').filter(':odd').addClass('odd')
$('tr:even').addClass('even')
$('td:contains("Henry")').addClass('highlight')



//contain value
$('th').parent().addClass('table-heading')
$('td:contains("Henry")').next().addClass('highlight')
$('th').siblings().addClass('table-heading')



//拿到DOM Elements
$('#my-element') => jQuery object
$('#my-element').get(0).tagName

some archives, 許多高手好文

http://ihower.idv.tw/blog/archives/1680
http://ihower.idv.tw/blog/archives/1691
http://ihower.idv.tw/blog/archives/1696
http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model


Don’t Loop Around ActiveRecord

ActiveRecord 跑迴圈的時候小心產生一筆一筆 SQL queries 啊,請愛用 :include 一次就把(子)資料讀出來,而不是一筆筆去捅資料庫。甚至直接寫點 SQL conditions,目標是讓 SQL query 一次即可。若要用 :select 請搭配 :join。


Beware of Binary Fields

若欄位有 Binary data,用 find 時請務必愛用 :select 只讀出必要欄位。另外也建議使用 with_scope method 或 scope_out plugin


Keep Your Controllers and Views Skinny

實在是 Rails 的原罪: 因為 ActiveRecord 提供很多好用的 method,所以我們習慣把 code 塞到 controller 甚至 view 裡。正確的作法應該盡量重構至 Model 中 (例如有複雜參數的 find ),有可讀性、可測試(model unit testing)跟好的MVC。請看這篇經典文章 Skinny Controller, Fat Model。這裡作者又在推薦了一次 with_scope


Don’t Store Objects in the Session

別這樣做 session[:user]=user,你的memory很快用完,而且session資料跟db資料不一致,請用 session[:user_id] = user.id。真要存 object 請裝 Memcached 吧。


Avoid Heavy Response Processing

耗用時間的操作請用 queuing system,入門方法可用 rake 跟 crob 自動執行,進階有 BackgroundRB, Amazon’s SQS 等。可以試試 acts_as_state_machine 這個 plugin 來設計自己的排程系統。


Use ActiveRecord Mailing

寄送大量郵件,介紹 ar_mailer plugin





Date Formatting

用 parse_date 把 String 變成 Date 是個非常昂貴的操作,建議你直接用字串操作(正規表示法)把 String(例如從DB撈出來的db_date) 變成你想要的格式,或是從中拆出你想要的年月日。(PDF 有 example code)


ObjectSpace.each_object

DO NOT USE IT,你不會想在 per-request 下去執行的,很貴。


Symbol.to_proc

ActiveSupport 提供的 @var.map(&:name) 語法,雖然方便,但是用 inline block 的方法 @var.map{ |a| a.name| } 執行效率比較快。


Using .nil?

如果要測試的值已知不是 Boolean,那就不需要用 .nil 多一個 method call,直接 if x 就好了而不是 if x.nil?


nil? or empty? versus blank?

ActionPack 有提供 x.blank?,不需要用 x.nil? || x.empty?


Test Most Frequent Case First

用 case 時把較常發生的放前面,若都差不多,把貴的操作的放後面。


Optimize Access to Global Constants

在 Constant 前面加上 namespace operator :: 會比較快,減少查詢時間


Caching Data in Instance Variables

例如在 controller 裡面 def captial_letters { (”A”..”Z”).to_a } end 請改用 def captial_letters { @captial_letters ||= (”A”..”Z”).to_a } end


Local Variables Are Cheap

method 中傳進來的參數若常用,可以先存成 Local Variables 再來多次使用。


Interpolated Strnges

方法一 s = “:#{a}.#{b}” 比方法二 s = “:” <<>


In-Place Updates

直接修改比複製一份快: gsub! 比 gsub 快,merge! 比 merge 快。例如這個範例 s.gsub().gsub!().gsub! 而不是 s.gsub.gsub.gsub

2008年5月1日 星期四

jQuery some example

http://jsgears.com/thread-63-1-1.html
$("div.contents p")
<div id="body">
<h2>Some Header</h2>
<div class="contents">
<p>...</p>
<p>...</p>
</div>
</div>
選取 class 為 contents 的 <div> 所包住的所有下層的 <p>


$("div > div")
<div id="body">
<h2>Some Header</h2>
<div class="contents">
<p>...</p>
<p>...</p>
</div>
</div>
解釋:選取被 <div> 包住的下一層 <div>



$("div:has(div)")
<div id="body">
<h2>Some Header</h2>
<div class="contents">
<p>...</p>
<p>...</p>
</div>
</div>
解釋:和前一個範例相反,這邊是選取至少有包住一個 <div> 的 <div>



$("a[target]").append(" (Opens in New Window)");



1. $("#body").css({
2. border: "1px solid green",
3. height: "40px"
4. });


1. $("form").submit(function() {
2. if ($("input#username").val() == "")
3. $("span.help").show();
4. });



當 user 點選 id 為 open 的連結時,顯示 id 為 menu 的區塊,並回傳 false 避免瀏覽器真的換頁。

1. $("a#open").click(function() {
2. $("#menu").show();
3. return false;
4. });



$("#menu").slideDown("fast");



1. $("div").animate({
2. width: '300px',
3. padding: '20px'
4. }, 'slow');



1. $("div").hide(500, function(){
2. // $(this) 是每一個各別的 <div>
3. $(this).show(500);
4. });



取得 sample.html 並將找出文件內所有 <div> 下一層的 <h1> 填入原本文件 id 為 body 的元素內

1. $("#body").load("sample.html div > h1");



透過 getJSON() 取得 JSON 格式的資料,並透過 callback 函數處理資料

1. $.getJSON("test.json", function(data){
2. for (var idx in data)
3. $("#menu").append("<li>" + data[idx] + "</li>");
4. });



$("div").css("color", "blue");



1. $("ul.open") // [ ul, ul, ul ]
2. .children("li") // [ li, li, li ]
3. .addClass("open") // [ li, li, li]
4. .end() // [ ul, ul, ul ]
5. .find("a") // [ a, a, a ]
6. .click(function(){
7. $(this).next().toggle();
8. return false;
9. }) // [ a, a, a ]
10. .end(); // [ ul, ul, ul ]



1. var $j = jQuery.noConflict();
2. $j(document).ready(function() {
3. $j("div").addClass("special");
4. });

jquery, select, change, inject

http://docs.jquery.com/Events/change#examples

Problem
想把select 到的item value 加到text field裡
<%= text_field_tag :email %>

<%= select :contact, :user, @me.contacts.inject([]){|a, user| a << [user.nickname, user.nickname] }, :id => 'select_user', :prompt => '通訊錄聯絡人' %>

Solution
http://jquery.com/api/
http://visualjquery.com/1.1.2.html

<script type="text/javascript">

$(document).ready(function(){
$('#contact_user').change(function(){
str = $('#contact_user option:selected').val();
contact_str = $('#email').val();
$('#email').val(contact_str+','+str);
});

</script>


$('#contact_user option:selected') 取到的是jQuery object 他是沒有value 的
要用val() 去取

$('#contact_user option:selected').get(0) 取到的才是該 element 才有 value attribute
所以也可以寫成$('#contact_user option:selected').get(0).value = "ooxx" 當然比較麻煩

append 是加在element 後, 不是value

find, sql in ; select detect partition concat gsub split

http://www.1keydata.com/sql/sqlin.html
http://www.rubyinside.com/clever-find-conditions-in-rails-without-sql-56.html
list = [1,2]
User.find(:all, :conditions => {:id => list, :staus => 'health'})
User.find(:all, :conditions => ["follows_counter =0 and id In (?)",list])

SELECT * FROM `users` WHERE (`users`.`id` IN (1,2))



http://www.ruby-doc.org/core/classes/Enumerable.html#M003154
#把參數處理成 array
emails = params[:email].gsub(/\s/, "").gsub(/;/, ",").split(/,/)

in_email_users = User.find(:all, :conditions => {:nickname => emails })
in_email = in_email_users.map(&:nickname)

#就像是兩個回圈下去跑
out_emails = emails.select { |e| !in_email.detect{|i| i == e } }

#email 的驗證 regular expression
out_emails, wrong_emails = out_emails.partition { |e|
e =~ /^([_a-z0-9-]+)(\.[_a-z0-9-]+)*@([a-z0-9-]+)(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/
}

out_emails.concat(in_email)



>> (1..20).select {|i| i % 5 == 0 }
=> [5, 10, 15, 20]
>> (1..20).detect {|i| i % 5 == 0 }
=> 5

text_field, text_field_tag, link_to, link_to_remote

http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#M000923

text_field(:session, :user, :onchange => "if $('session[user]').value == 'admin' { alert('Your login can not be admin!'); }")

# => <input type="text" id="session_user" name="session[user]" value="#{@session.user}" onchange = "if $('session[user]').value == 'admin' { alert('Your login can not be admin!'); }"/>

注意value = @session.user, id = session_user, name = session[user]
還有如何在這使用event像onchange



http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#M001038
text_field_tag 'payment_amount', '$0.00', :disabled => true

# => <input disabled="disabled" id="payment_amount" name="payment_amount" type="text" value="$0.00" />

id = name = payment_amount



<%= link_to "追蹤",{ :controller => "favorite", :action => "add", :id => @item.id }, :class => "bbt_ch", :title => "追蹤" %>

<%= link_to "", {:action => "push", :id => @item.id}, :confirm => '確定要推薦?', :method => :post, :class => "push" %>

用到些其他options 時, url部份要{} 起來


link_to_remote "Delete this post", :update => "posts", :url => { :action => "destroy", :id => post.id }

link_to_remote "Delete this post", :update => "posts", :url => post_url(@post), :method => :delete, :html => { :class => "destructive" }

<%= link_to_remote "Delete this post", {:url => user_url, :update => "post", :method => :delete}, :class => "sec"%>


url的部份要用url symbol指定, attribute的部份要用html symbol