Ruby on Rails PitfallOr just stupid mistakes we made
Robin LuIN-SRC Studio
Friday, May 22, 2009
IN-SRC Studio
• http://www.in-src.com
• Team behind Caibangzi.com
• Full stack Ruby On Rails Development
• Projects from Pepboys, Vitality, Healthwise...
Friday, May 22, 2009
‘and’ or ‘&&’
What does this mean?
result = func(arg) and render(:text => result)
Friday, May 22, 2009
‘and’ or ‘&&’
What does this mean?
result = func(arg) and render(:text => result)
Why not this?
result = func(arg) && render(:text => result)
Friday, May 22, 2009
‘and’ or ‘&&’
What does this mean?
result = func(arg) and render(:text => result)
Why not this?
result = func(arg) && render(:text => result)
Be aware of the operator precedence
Friday, May 22, 2009
strip_tags
Display user input text without tags
What we did:
Friday, May 22, 2009
strip_tags
Whentext = ‘<img title="http://example.com/x.js?" src="#"’
the page becomes:
<p> <img title="http://example.com/x.js?" src="#" </p>
Friday, May 22, 2009
strip_tags
strip_tags is not safe by itself
h strip_tags(text)
Friday, May 22, 2009
cache
Controller
class Blog1Controller < ApplicationControllerdef list
unless read_fragment(:action => 'list') @articles = Article.find_recent
end end
end
<% cache do %> <ul> <% for article in @articles -%>
<li><p><%= h(article.body) %></p></li> <% end -%> </ul>
<% end %>
list.html.erb
Friday, May 22, 2009
cache
Result:
sometime got crash due to uninitialized @articles
Friday, May 22, 2009
cachearticle list
Friday, May 22, 2009
cache
check cache
article list
Friday, May 22, 2009
cache
check cache list
article list
Friday, May 22, 2009
cache
check cache list
article list
render
Friday, May 22, 2009
cache
check cache list
article list
render
article new
Friday, May 22, 2009
cache
check cache list
article list
expire cache
render
article new
Friday, May 22, 2009
cache
check cache list
article list
expire cache
render
article new
Friday, May 22, 2009
cache
check cache list
article list
expire cache
render
check cache
article new
Friday, May 22, 2009
cache
check cache list
article list
expire cache
render
check cache
crashed by non-init @articles
article new
Friday, May 22, 2009
cache
• defensive: handle the exception
• postpone init of @articles
• update caches instead of expiring them
Solutions?
none of them is perfect
Friday, May 22, 2009
object id
Friday, May 22, 2009
object id
Check nil? everywhere?
Friday, May 22, 2009
object idconfig.whiny_nil = true
Friday, May 22, 2009
validate_uniqueness_of
Friday, May 22, 2009
validate_uniqueness_of
We always get errors like this:
A ActiveRecord::StatementInvalid occurred in fund#add_watch_fund:
Mysql::Error: Duplicate entry '1234-271' for key 2: INSERT INTO `watch_funds` (`account_id`, `position`, `fund_id`, `created_at`) VALUES(1234, 19, 271, '2009-05-06 19:13:50')
Friday, May 22, 2009
validate_uniqueness_ofProcess A
Process B
Friday, May 22, 2009
validate_uniqueness_ofProcess A
Process B
unique?
Friday, May 22, 2009
validate_uniqueness_ofProcess A
Process B
unique? select ....
Friday, May 22, 2009
validate_uniqueness_ofProcess A
Process B
unique? select ....unique?
Friday, May 22, 2009
validate_uniqueness_ofProcess A
Process B
unique? select ....unique?
Insert
Friday, May 22, 2009
validate_uniqueness_ofProcess A
Process B
unique? select ....unique?
Insert
Insert
Friday, May 22, 2009
validate_uniqueness_ofProcess A
Process B
unique? select ....unique?
Insert
Insert
crash!
Friday, May 22, 2009
validate_uniqueness_of
validate_uniqueness_of may not guarantee the uniqueness
use your own lock if the uniqueness is critical to you.
Friday, May 22, 2009
conditions
Background:
• category has many subcategories
• subcategory has many posts
• post belongs to subcategory
we need to select all posts in a category.
Friday, May 22, 2009
conditionsWhat we did:
named_scope :in_category, lambda { |cat| conditions = [cat.subcategories.map {|subcat| 'posts.subcategory_id = ?' }.join(" OR ")] cat.subcategories.each {|subcat| conditions << subcat.id } {:conditions => conditions}}
Friday, May 22, 2009
conditions
Result:
we get all posts when a category has no subcategories
Friday, May 22, 2009
conditionsWhen category has no subcategory
named_scope :in_category, lambda { |cat| conditions = [cat.subcategories.map {|subcat| 'posts.subcategory_id = ?' }.join(" OR ")] cat.subcategories.each {|subcat| conditions << subcat.id } {:conditions => conditions}}
Friday, May 22, 2009
conditions
When you compose conditions, be aware that sometime nothing to
compose means
the conditions should match nothing,
not the conditions should be empty.
Friday, May 22, 2009
before_create
set a flag if the author of the post is an admin
What we did:
Friday, May 22, 2009
before_create
Result:
Only post by admin can be saved
Friday, May 22, 2009
before_create
All these callbacks are Filters
Be careful not to break the filter chain by what you return from the filters!
Friday, May 22, 2009
after_create
send a mail whenever a new record is created
What we did:
Friday, May 22, 2009
after_create
Result:
sometime the record save failed but we still get mail notification
Friday, May 22, 2009
after_create
before_create
create
after_create
all in one transaction
begin......commit
all the steps between this should be transactional
Friday, May 22, 2009
after_create
• send a mail
• delete a file
• expire a cache
What are non-transactional actions?
Friday, May 22, 2009
after_create
• try not put non-transaction actions into transactions.
• after_commit
• in controller
Friday, May 22, 2009
Thanks!
Friday, May 22, 2009