Ruby on Rails Pitfall Or just stupid mistakes we made Robin Lu IN-SRC Studio
[email protected] RubyConfChina2009
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 When text = ‘
the page becomes:
Friday, May 22, 2009
strip_tags strip_tags is not safe by itself h strip_tags(text)
Friday, May 22, 2009
cache class Blog1Controller < ApplicationController def list unless read_fragment(:action => 'list') @articles = Article.find_recent end end end <% cache do %>
<% for article in @articles -%> <%= h(article.body) %>
<% end -%>
<% end %> Friday, May 22, 2009
Controller
list.html.erb
cache Result: sometime got crash due to uninitialized @articles
Friday, May 22, 2009
cache article list
Friday, May 22, 2009
cache article list check cache
Friday, May 22, 2009
cache article list check cache
Friday, May 22, 2009
list
cache article list check cache render
Friday, May 22, 2009
list
cache article new
article list check cache render
Friday, May 22, 2009
list
cache article new
article list check cache render
Friday, May 22, 2009
list
expire cache
cache article new
article list check cache render
Friday, May 22, 2009
list
expire cache
cache article new
article list check cache render check cache
Friday, May 22, 2009
list
expire cache
cache article new
article list check cache render check cache crashed by non-init @articles Friday, May 22, 2009
list
expire cache
cache Solutions?
• defensive: handle the exception • postpone init of @articles • update caches instead of expiring them 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 id config.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_of Process A Process B
Friday, May 22, 2009
validate_uniqueness_of Process A Process B unique?
Friday, May 22, 2009
validate_uniqueness_of Process A Process B unique?
Friday, May 22, 2009
select ....
validate_uniqueness_of Process A Process B unique?
select .... unique?
Friday, May 22, 2009
validate_uniqueness_of Process A Process B unique?
select .... unique?
Insert
Friday, May 22, 2009
validate_uniqueness_of Process A Process B unique?
select .... unique?
Insert Insert
Friday, May 22, 2009
validate_uniqueness_of Process 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
conditions What 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
conditions When 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
Friday, May 22, 2009
begin ... ... commit all the steps between this should be transactional
after_create What are non-transactional actions?
• send a mail • delete a file • expire a cache
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