Ruby on Rails Pitfall

Post on 10-Apr-2015

903 views 0 download

description

This is a presentation by IN-SRC.com at Ruby Conference China 2009.8 interesting pitfalls we met during our development by using ruby on rails. Either mistakes we made or something you should be aware of.

Transcript of Ruby on Rails Pitfall

Ruby on Rails PitfallOr just stupid mistakes we made

Robin LuIN-SRC Studio

robinlu@in-src.comRubyConfChina2009

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