Days ago, I came across a situation in which find_in_batches does not work correctly, the sample code is as below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#NOT WORKING AS EXPECTED.
namespace :studycenter do
  desc 'generate item extra items'
  task :update_extra_items => :environment do
    puts "starting at #{@time = Time.now}......"
    Item.find_in_batches(:conditions => {:content_type => "Scenario"}) do |items|
      items.each do |item|
        begin
          if item.extra_items.blank?
            item.related_lessons.each do |extra|
              @item = ItemExtraItem.create({:item_id => item.id, :extra_item_id => extra.id})
              puts "=============================================#{@item.id}"
            end
          end
          puts "finished item with ID:#{item.id}"
        rescue Exception => e
          puts "something wrong happened!! item with ID:#{item.id}"
          next
        end
      end
      puts "------------------spent #{(Time.now - @time)/60} minutes!"
    end
    puts "finished at #{Time.now}, totally, spent #{(Time.now - @time)/60} minutes!"
  end
end

Then I refactor this task, so I can migrate data which generated day by day.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#WORKING WELL
namespace :studycenter do
  desc 'generate item extra items'
  task :update_extra_items => :environment do
    puts "starting at #{@time = Time.now}......"
    (1..300).each do |n|
      items = Item.all(:conditions => ["content_type = 'Scenario' and items.created_at >= ? and items.created_at < ?",("2010-03-13".to_date - n.days), ("2010-03-13".to_date - (n-1).days) ])
      items.each do |item|
        begin
          if item.extra_items.blank?
            item.related_lessons.each do |extra|
              @item = ItemExtraItem.create({:item_id => item.id, :extra_item_id => extra.id})
              puts "=============================================#{@item.id}"
            end
          end
          puts "finished item with ID:#{item.id}"
        rescue Exception => e
          puts "something wrong happened!! item with ID:#{item.id}"
          next
        end
      end
      puts "------------------spent #{(Time.now - @time)/60} minutes!"
    end
    puts "finished at #{Time.now}, totally, spent #{(Time.now - @time)/60} minutes!"
  end
end

Do you know why find_in_batches is not working here?
PS: item.related_lessons is an item array, so the item and its related lesson are all the same class.

Answer: In find_in_batches loop, the specific Class only has a range of its instances(e.g. 1~1000), so item.related_lessons can not find the item(e.g. 1001) out of the range..

Last few days, I’ve been mainly struggling with performance issue which was sent to me on Monday. On Rails side, I didn’t add enough necessary cache before I was told about the performance issue. Then I spent two days to improve it by adding cache every where I missed to do that before.

Some shares and confusions as below:

Shares:
1> A very useful educational website about scaling Rails where there are Scaling Rails Screencast Series produced by Gregg Pollack and supported by New Relic.
2> Fragment cache.
If you add many fragment cache in view, it’s really a pain when you expire your cache, so I found there is a better way to expire your cache: if the cached block involves a model, for example, learner’s sidebar involves “User” model’s change, so I just name the cache with User model’s “updated_at”, so I don’t need to expire this cache, it will be done automatically.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  <% cache("sidebar-profile-avatar-#{current_user.id}-#{current_user.updated_at.to_i}") do -%>
    <div class="sbb_title"><%= t :my_profile %></div>
    <div class="sbb_content">
      <table border="0" cellspacing="0" cellpadding="0" class="profile_table">
        <tr>
          <td width="100" rowspan="2" align="center" valign="top">
            <img src="<%= current_user.avatar_url || "/assets/images/portrait_demo.gif" %>" width="90" height="90" />
          </td>
          <td width="110" height="24"><%= display_learner([current_user], nil) %></td>
        </tr>
        <tr>
          <td valign="top"><strong><%= t :my_goal %></strong><%= display_oral_score(current_user.try(:study_info).try(:target_score)) %></td>
        </tr>
      </table>
    <% end -%>

3> Memcached. Cache whatever you want:

1
2
3
4
5
6
7
8
9
10
11
  def related_lessons
    cache_key = "related_lessons_for_item#{self.id}"
    return Rails.cache.read(cache_key) unless Rails.cache.read(cache_key).nil?
    if content_type == "Scenario"
      lessons = unit.extra_items.all(:conditions => {:content_id => content.extra_lessons.map(&:id)})
    elsif content_type == "ExtraLesson"
      lessons = [content.scenario.try(:item)]
    end
    Rails.cache.write(cache_key, lessons)
    return lessons
  end

Confusions:
1> It takes much time to render a partial view. that’s pretty confusing to me. Some logs as below:

1
2
Cached fragment hit: views/sidebar-profile-roadmap-1268271150 (0.9ms)
Rendered shared/_sidebar_profile (109.8ms)

It seems like even the cached fragment is found, there still needs much time to render the partial..

2> From the log, I saw every request to “roadmap” index action will do the following stuff first, It’s slow. But what that?

1
<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#<ActionView::Base:0xb5a0e348>#

Any ideas on my confusions? All the involving clues are warmly welcomed.

I’ve been working on EQ portal during these days, I wanna share a useful gem which I used, it is called Formtastic. it’s a nice way to create form via formtastic, so the finial form is something like:

1
2
3
4
5
6
7
8
9
10
11
<% semantic_form_for @landing, :url=>admin_landings_path do |form| %>
  <p>
    <% form.inputs do %>
      <%= form.input :title, :label => 'Title' %>
      <%= form.input :url_slug, :label => 'Url slug' %>
      <%= form.input :meta, :label => 'Meta' %>
      <%= form.input :content, :label => 'Content' %>
    <% end %>
  </p>
  <p><%= form.buttons %></p>
<% end %>

Then it will generate HTML like this:

1
2
3
4
5
6
7
8
9
10
11
12
<form action="/admin/landings" class="formtastic landing" id="new_landing" method="post"><div style="margin:0;padding:0;display:inline"><input name="authenticity_token" type="hidden" value="EC9WF1oK80Iq6X4NegSkBfVx5gLiYWvBEd7VeNKWHio=" /></div>
  <p>
    <fieldset class="inputs"><ol>
      <li class="string required" id="landing_title_input"><label for="landing_title">Title<abbr title="required">*</abbr></label><input id="landing_title" maxlength="255" name="landing[title]" size="30" type="text" /></li>
      <li class="string required" id="landing_url_slug_input"><label for="landing_url_slug">Url slug<abbr title="required">*</abbr></label><input id="landing_url_slug" maxlength="255" name="landing[url_slug]" size="30" type="text" /></li>
      <li class="text required" id="landing_meta_input"><label for="landing_meta">Meta<abbr title="required">*</abbr></label><textarea cols="40" id="landing_meta" name="landing[meta]" rows="20"></textarea></li>
      <li class="text required" id="landing_content_input"><label for="landing_content">Content<abbr title="required">*</abbr></label><textarea cols="40" id="landing_content" name="landing[content]" rows="20"></textarea></li>

    </ol></fieldset>
  </p>
  <p><fieldset class="buttons"><ol><li class="commit"><input class="create" id="landing_submit" name="commit" type="submit" value="Create Landing" /></li></ol></fieldset></p>
</form>

Also, it can be configured well in display style(not try yet), as well as working with this validation plugin

There is a more detailed Doc at: http://rdoc.info/rdoc/justinfrench/formtastic/blob/35eadf9a0f3e30101993419c3dd3327fb2fdd0b6/Formtastic/SemanticFormBuilder.html.  And samples at: http://asciicasts.com/episodes/184-formtastic-part-1

Enjoy it.

  1. 最近读了一篇文章,里面介绍了Session和Cookie在RoR开发中的使用方法,英文还不错的同学请直接读这篇文章。我仅仅在这篇Post里面做个整理,把那些有用的资料在此备份,免得下回又的麻烦Google。上面提到的文章很全面的介绍了很多细节,目录如下:
    1. Introduction
    2. Sessions
      1. Session in rails
      2. Configure your sessions
      3. Storage options
      4. Session storage limitations
      5. Session and Security
      6. HowTo
        1. Implement session expiration
        2. Delete stale sessions
        3. Find out active users
        4. Access session data using session_id
      7. Miscellaneous
    3. Cookies
      1. Cookie on rails
      2. cookies vs. request.cookies
      3. CookieJar
      4. Miscellaneous
This post is a copy of my work stuff, but I want to archive all the links below, they are all about SEO on Rails application, as well as a useful post about jQuery on Rails.

Finally, we decided to create a Rails App for the EQV2 New Website, so I did several homework for this mission. They are:

1. SEO on Rails.
Several rules/good points for seo according to the following websites:
1> http://www.elctech.com/articles/rails-seo-starter-guide
2> http://www.tonyspencer.com/2007/01/26/seo-for-ruby-on-rails/
3> http://www.seoonrails.com/
4> http://blog.csdn.net/diehuan2008/archive/2009/02/23/3925204.aspx

2. Maybe use JQuery more in EQV2.
1> http://yehudakatz.com/2007/01/31/using-jquery-in-rails-part-i/
2> http://www.slideshare.net/wycats/jquery-presentation-to-rails-developers-110063

3. Cache Views.

MORE IDEAS?

But, first version should be structured well and make sure it’s been done before the “deadline”, so this app will be according to the recommendation but not totally implemented in the best way, in all, it still needs your suggestion.

When talking about templates in Rails, usually people mean the templates which help to re-use views, but this templates is a feature after Rails 2.3 for generating Rails application easily, so give it a try if you haven’t used it yet.

It’s helpful for me to create Rails application according to similar skeleton, a sample below was written about one year ago, but recently I want to create a new application with the same environment/configuration.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#idapted_template.rb
generate :rspec
   
environment 'config.time_zone = "Beijing"'
environment 'config.i18n.default_locale = :zh'
   
name = ask("What's app's name?")
file 'config/site_config.yml', <<-CODE
app: #{name}
domain: mydomain
CODE
   
user = ask("What's db user name?")
pwd = ask("What's db user password?")
file 'config/database.yml', <<-CODE
development:
  adapter: mysql
  encoding: utf8
  database: #{name}_development
  user: #{user}
  password: #{pwd}
  pool: 5
  timeout: 5000

test:
  adapter: mysql
  encoding: utf8
  database: #{name}_test
  user: #{user}
  password: #{pwd}
  pool: 5
  timeout: 5000

production:
  adapter: mysql
  encoding: utf8
  database: #{name}_production
  user: #{user}
  password: #{pwd}
  pool: 5
  timeout: 5000
CODE
   
rake 'db:create:all'
rake 'db:sessions:create'
rake 'db:migrate'
   
gem 'idp_helpers'
gem 'idp_core'
   
run "rm public/index.html"
   
run "rm -rf tmp log"
run "svn import . http://mydomain.com/svn/projects/applications/#{name} -m 'add new app'"
run "rm -rf *"
run "svn checkout http://mydomain.com/svn/projects/applications/#{name} ."
   
file 'ignore_list', <<-CODE
log
tmp
nbproject
CODE
run "svn propset svn:ignore -F ignore_list ."
run "rm ignore_list"
run "svn commit -m 'set svn ignore'"

There are several useful commands which help you write powerful templates, you can learn more good examples here. or watch Ryan’s Railscasts about App Templates in Rails 2.3.

Enjoy it.

© 2011 Refactoring Thoughts Suffusion theme by Sayontan Sinha
普人特福的博客cnzz&51la for wordpress,cnzz for wordpress,51la for wordpress