Archive

Posts Tagged ‘rails’

把AJAX操作 从controller中移到helper

September 3rd, 2010 yakjuly 2 comments

rails中的ajax操作结合prototype,非常方便。方法也挺简单。

我平常操作ajax的代码喜欢在controller中使用 render :update {|page| … }

但是这样的代码在controller写多了 会显得非常肮脏 难读。并且,我要对页面进行某个操作,需要在controller中写页面中的dom元素的id等。

例如:

render :update do |page|
  page.replace_html("xxxx", :partial => "xxx")
end

render :update do |page|
   #use alert
   page.alert(@object.errors.full_messages.join(","))
   #or replace notice area
   page.replace_html("error_div", @object.errors.full_messages.join(","))
end

当一次ajax访问需要 对页面调用多个动作时,代码就显得乱了。利用rails的helper,我们可以将render:update的block中的内容放到helper中,这为我们复用和重构提供了一个有效的工具。 例如:

module ApplicationHelper

  def update_time
    page.alert 'hello'
  end

  def spike
    render(:update){|page| page.alert_hello}
  end
end

另外,把代码移到helper中也可以让这些ajax操作在controller中 显得更有意义。

controller:

class User::CommentsController < User::BaseController
  before_filter :prepare_comment

  def index

  end

  def new

    respond_to do |type|
      type.js {
        render :update do |page|
          page.create_comment_form
        end
      }
    end
  end

  def create
    success = @comment.save

    respond_to do |type|
      type.js {
        render :update do |page|
          if success
            page.clear_comment_form
            refresh_comment_list(page)
          else
            page.show_error_messages(@comment)
          end
        end
      }
    end
  end

  def edit
    respond_to do |type|
      type.js {
        render :update do |page|
          page.create_comment_form
        end
      }
    end
  end

  def update
    success = @comment.save
    respond_to do |type|
      type.js {
        render :update do |page|
          if success
            page.clear_comment_form
            refresh_comment_list(page)
          else
            page.show_error_messages(@comment)
          end
        end
      }
    end
  end

  def destroy
    @comment.destroy
    render :nothing => true
  end

  private

  def prepare_comment
    case action_name
    when "new", "create"
      @comment = @user.comments.build(params[:comment])
    when "edit", "update", "destroy"
      @comment = @user.comments.find(params[:id])
      @comment.attributes=(params[:comment])
    when "index"
      @comments = @user.comments
    end
  end

end

接下来 helper

module User::CommentHelper
  def refresh_comment_list(page)
    @comments = @user.comments
    page.replace_html("comment_list", :partial => "list")
  end

  def clear_comment_form
    page.replace_html("edit_comment", "")
  end

  def create_comment_form
    page.replace_html("edit_comment", :partial => "form")
  end

  def comment_form_head
    case params[:action]
    when "new", "create"
      [@comment, {:url => user_comments_path}]
    when "edit", "update"
      [@comment, {:url => user_comment_path(@user, @comment), :html => {:method => :put}}]
    end
  end
end

这里有个缺憾 就是 refresh_comment_list方法 不能直接写成page.refresh_comment_list

因为在javascript generator中不能读到 @user 这个实例变量。因此只有写成refresh_comment_list(page). 并且helper方法中包含了数据库查询语句。

虽然美中不足,但代码看起来还是舒服多了。

view中还可以重用helper中的部分方法

<% remote_form_for *comment_form_head do |f| %>
<div class="order" style="clear:left">
  <table>
    ........
    <tr><th></th><td><%= submit_tag(t(:submit)) %> <%= link_to_function(t(:cancel), update_page{|page| page.clear_comment_form}) %></td></tr>
  </table>
</div>
<% end %>

经过这样改写后,controller中不用关注 dom对象如何变化,helper与页面中的dom对象关系更加紧密。

Categories: rails, ruby Tags: ,

rails中的select和include查询

August 2nd, 2010 yakjuly No comments

Rails中ActiveRecord finders不允许我们在include预加载关联对象时使用select。

例如这样的情况:

class Student < ActiveRecord::Base
   has_many :calls
   has_one :call
end

class Call < ActiveRecord::Base
   belongs_to :student
end

希望在显示student时,显示它的最近更新的call的日期。

改善前:

@students = Student.all(:include => [:call])

改善后:

#include eql left outer join
@students = Student.all(:select => "students.id, students.login, students.called_times,
calls.updated_at as last_called_at", :joins => "left outer join calls on students.id = calls.student_id")
Categories: rails, ruby Tags: ,

rails3 !!! Missing the mysql gem. Add it to your Gemfile: gem ‘mysql’, ’2.8.1′

July 16th, 2010 yakjuly No comments

Rails3中 rake db:create 或 rake db:migrate 时出错

rake aborted!
!!! Missing the mysql gem. Add it to your Gemfile: gem 'mysql', '2.8.1'
/usr/lib/ruby/gems/1.8/gems/activerecord-3.0.0.beta4/lib/active_record/connection_adapters/mysql_adapter.rb:22:in `mysql_connection'

原因:rails3中使用bundler 管理gem,尽管system中包含gem mysql 仍然报错。

解决:找到rails_app_path下 的 GemFile。添加 gem ‘mysql’

更多:Rails3:使用bundler管理gems

Categories: rails, ruby Tags: ,

rails检测方法执行效率

July 12th, 2010 yakjuly No comments

当我们发现某个页面打开非常慢的时候,可以从development日志中查看sql查询消耗的时间。

对于巨慢的 render :partial 却找不到问题所在。

如果我们想知道某个方法或某句代码所花费的时间,可以通过rails的脚本script/profiler 与 script/benchmarker来查看,

例子:

module InPlaceEditingPlus
  class << self
    def reset_collection(collection=nil)
      #change order of item to [value, text]
      return [] if collection.nil?      
      collection.map{|t| [t].flatten.map(&:class) == [String, Fixnum] ? [t.last, t.first] : t}
    end
  end
en

检测这段代码的执行效率

创建任意一个class app

class App

  def self.test_reset_collection
     c = 50.times.map{|i| ["andy", 1]}
     InPlaceEditingPlus.reset_collection(c)
  end

end

运行 ruby script/performance/profiler “App.test_reset_collection”

生成报告如下:

  %   cumulative   self              self     total
 time   seconds   seconds    calls  ms/call  ms/call  name
 25.81     0.08      0.08       53     1.51     1.70  Array#map
 25.81     0.16      0.08       22     3.64     3.64  Class#read_inheritable_attribute
 22.58     0.23      0.07        1    70.00    70.00  ActiveSupport::Dependencies.search_for_file
  6.45     0.25      0.02       33     0.61     1.21  Array#each
  3.23     0.26      0.01       24     0.42     0.42  String#to_sym
  3.23     0.27      0.01        2     5.00     5.00  Array#select
  3.23     0.28      0.01      128     0.08     0.08  String#gsub!
  3.23     0.29      0.01       24     0.42     0.42  File#expand_path
  3.23     0.30      0.01       66     0.15     0.15  Array#last
  3.23     0.31      0.01       15     0.67     0.67  ActiveSupport::Callbacks::CallbackChain#build
  0.00     0.31      0.00        2     0.00     0.00  Module#ancestors
  0.00     0.31      0.00        4     0.00     0.00  Kernel.singleton_method_added
  0.00     0.31      0.00        1     0.00     0.00  ActiveRecord::NamedScope::ClassMethods.scopes
  0.00     0.31      0.00        1     0.00     0.00  ActiveRecord::Base#after_save
  0.00     0.31      0.00       15     0.00     0.00  ActiveSupport::Callbacks::Callback#initialize
  0.00     0.31      0.00        2     0.00     0.00  ActiveRecord::Associations::ClassMethods.belongs_to
  0.00     0.31      0.00        2     0.00     0.00  ActiveSupport::Dependencies.load_paths
  0.00     0.31      0.00        1     0.00     0.00  ActiveRecord::Associations::ClassMethods.valid_keys_for_has_one_association
  0.00     0.31      0.00        2     0.00     0.00  ActiveRecord::Associations::ClassMethods.create_belongs_to_reflection
  0.00     0.31      0.00        3     0.00     0.00  ActiveSupport::Inflector.constantize
  0.00     0.31      0.00        1     0.00     0.00  String#tr
  0.00     0.31      0.00        1     0.00     0.00  Kernel.instance_eval
  0.00     0.31      0.00       38     0.00     0.00  Module#blank_slate_method_added
  0.00     0.31      0.00        1     0.00     0.00  ActiveSupport::Dependencies.load?
  0.00     0.31      0.00        2     0.00     0.00  String#size
  0.00     0.31      0.00        5     0.00     0.00  Hash#keys
  0.00     0.31      0.00        3     0.00     0.00  Module#===
  0.00     0.31      0.00       12     0.00     0.00  Module#const_defined?
  0.00     0.31      0.00        2     0.00     0.00  NilClass#nil?
  0.00     0.31      0.00       10     0.00     0.00  String#split
  0.00     0.31      0.00        1     0.00     0.00  Enumerable::Enumerator#each
  0.00     0.31      0.00       29     0.00     0.00  Kernel.is_a?
  0.00     0.31      0.00        1     0.00     0.00  ActiveSupport::Dependencies.warnings_on_first_load
  0.00     0.31      0.00        8     0.00     0.00  Kernel.dup
  0.00     0.31      0.00        1     0.00     0.00  ActiveRecord::Observing::ClassMethods.inherited
  0.00     0.31      0.00        1     0.00     0.00  ActiveSupport::Inflector.underscore
  0.00     0.31      0.00        1     0.00     0.00  ActiveRecord::Base#default_scoping
  0.00     0.31      0.00        8     0.00     0.00  ActiveSupport::Inflector.inflections_without_route_reloading
  0.00     0.31      0.00        2     0.00     0.00  ActiveRecord::Associations::ClassMethods.configure_dependency_for_belongs_to
  0.00     0.31      0.00        3     0.00     0.00  ActiveSupport::Dependencies.loaded
  0.00     0.31      0.00        1     0.00     0.00  Array#compact
  0.00     0.31      0.00        1     0.00     0.00  ActiveSupport::Dependencies.qualified_name_for
  0.00     0.31      0.00        1     0.00     0.00  ActiveRecord::Base#inherited
  0.00     0.31      0.00       50     0.00     0.00  Array#==
  0.00     0.31      0.00        3     0.00     0.00  ActiveSupport::Dependencies.constant_watch_stack
  0.00     0.31      0.00        6     0.00     0.00  Hash#update
  0.00     0.31      0.00       15     0.00     0.00  Array#map!
  0.00     0.31      0.00        2     0.00     0.00  Array#initialize_copy
  0.00     0.31      0.00        6     0.00     0.00  Array#-
  0.00     0.31      0.00        5     0.00     0.00  Module#name
  0.00     0.31      0.00       79     0.00     0.00  Hash#[]
  0.00     0.31      0.00        1     0.00     0.00  ActiveRecord::Associations::ClassMethods.has_one
  0.00     0.31      0.00        1     0.00     0.00  ActiveRecord::Associations::ClassMethods.create_has_one_reflection
  0.00     0.31      0.00        7     0.00     0.00  ActiveSupport::Dependencies.qualified_const_defined?
  0.00     0.31      0.00        1     0.00   230.00  ActiveSupport::Dependencies::ModuleConstMissing.const_missing
  0.00     0.31      0.00        2     0.00    15.00  ActiveRecord::Associations::ClassMethods.has_many
  0.00     0.31      0.00        1     0.00     0.00  String#ends_with?
  0.00     0.31      0.00        2     0.00     0.00  Symbol#to_sym
  0.00     0.31      0.00        5     0.00     0.00  String#downcase
  0.00     0.31      0.00        5     0.00     0.00  Kernel.nil?
  0.00     0.31      0.00       50     0.00     0.00  Symbol#to_proc
  0.00     0.31      0.00       15     0.00     0.00  Array#flatten!
  0.00     0.31      0.00       23     0.00     0.00  Hash#[]=
  0.00     0.31      0.00        1     0.00     0.00  ActiveRecord::DynamicScopeMatch#match
  0.00     0.31      0.00        8     0.00     0.00  ActiveRecord::Reflection::MacroReflection#macro
  0.00     0.31      0.00        2     0.00     0.00  ActiveRecord::Associations::ClassMethods.valid_keys_for_belongs_to_association
  0.00     0.31      0.00        1     0.00     0.00  ActiveSupport::CoreExtensions::String::Inflections.underscore
  0.00     0.31      0.00        1     0.00     0.00  Class#inherited
  0.00     0.31      0.00        9     0.00     0.00  Array#empty?
  0.00     0.31      0.00        1     0.00   150.00  ActiveSupport::Dependencies.require_or_load
  0.00     0.31      0.00        1     0.00     0.00  Array#uniq!
  0.00     0.31      0.00        2     0.00     0.00  ActiveSupport::Dependencies.autoloaded_constants
  0.00     0.31      0.00        1     0.00     0.00  ActiveRecord::Base#default_scope
  0.00     0.31      0.00        3     0.00     0.00  Array#<<
  0.00     0.31      0.00       10     0.00     0.00  String#empty?
  0.00     0.31      0.00        1     0.00     0.00  ActiveSupport::Dependencies.loadable_constants_for_path
  0.00     0.31      0.00        1     0.00    80.00  App#test_reset_collection
  0.00     0.31      0.00        3     0.00     0.00  ActiveRecord::Associations::ClassMethods.association_accessor_methods
  0.00     0.31      0.00        1     0.00     0.00  TrueClass#duplicable?
  0.00     0.31      0.00        3     0.00     0.00  Mutex#synchronize
  0.00     0.31      0.00        8     0.00     0.00  Enumerable.inject
  0.00     0.31      0.00        1     0.00     0.00  ActiveSupport::Dependencies.history
  0.00     0.31      0.00        1     0.00     0.00  ActiveSupport::Dependencies.load_once_paths
  0.00     0.31      0.00        1     0.00     0.00  Array#blank?
  0.00     0.31      0.00        2     0.00     0.00  ActiveRecord::Base#after_update
  0.00     0.31      0.00        5     0.00     0.00  ActiveRecord::Reflection::ClassMethods.create_reflection
  0.00     0.31      0.00       13     0.00     0.00  Module#const_get
  0.00     0.31      0.00       45     0.00     0.00  Hash#default
  0.00     0.31      0.00        1     0.00     0.00  Hash#each
  0.00     0.31      0.00        6     0.00     0.00  String#[]
  0.00     0.31      0.00        3     0.00     0.00  ActiveSupport::CoreExtensions::String::Inflections.constantize
  0.00     0.31      0.00       60     0.00     0.00  Array#first
  0.00     0.31      0.00        1     0.00     0.00  NameError#initialize
  0.00     0.31      0.00        9     0.00     0.00  ActiveRecord::Reflection::MacroReflection#options
  0.00     0.31      0.00        2     0.00     0.00  ActiveSupport::CoreExtensions::String::Inflections.camelize
  0.00     0.31      0.00        1     0.00    10.00  ActiveSupport::Dependencies.load_once_path?
  0.00     0.31      0.00        2     0.00     0.00  Array#*
  0.00     0.31      0.00        2     0.00     0.00  ActiveRecord::Associations::ClassMethods.valid_keys_for_has_many_association
  0.00     0.31      0.00      537     0.00     0.00  Hash#key?
  0.00     0.31      0.00        1     0.00     0.00  Exception#initialize
  0.00     0.31      0.00        1     0.00     0.00  Array#uniq
  0.00     0.31      0.00        2     0.00     0.00  ActiveRecord::Base#after_create
  0.00     0.31      0.00       50     0.00     0.00  Symbol#to_s
  0.00     0.31      0.00       18     0.00     0.00  Array#concat
  0.00     0.31      0.00       14     0.00     0.00  Class#write_inheritable_attribute
  0.00     0.31      0.00       52     0.00     0.00  Class#inheritable_attributes
  0.00     0.31      0.00        1     0.00     0.00  ActiveSupport::Dependencies.mechanism
  0.00     0.31      0.00        1     0.00     0.00  Observable.changed
  0.00     0.31      0.00       10     0.00     8.00  ActiveRecord::Reflection::ClassMethods.reflections
  0.00     0.31      0.00        7     0.00     0.00  String#gsub
  0.00     0.31      0.00        1     0.00     0.00  Kernel.respond_to?
  0.00     0.31      0.00        2     0.00     0.00  ActiveRecord::Associations::ClassMethods.configure_dependency_for_has_many
  0.00     0.31      0.00      550     0.00     0.00  String#to_s
  0.00     0.31      0.00        2     0.00     0.00  Kernel.hash
  0.00     0.31      0.00        1     0.00     0.00  Kernel.instance_variable_set
  0.00     0.31      0.00        2     0.00     0.00  Set#include?
  0.00     0.31      0.00       36     0.00     0.00  String#==
  0.00     0.31      0.00       13     0.00     0.00  String#starts_with?
  0.00     0.31      0.00        2     0.00     0.00  ActiveRecord::Associations::ClassMethods.create_extension_modules
  0.00     0.31      0.00        2     0.00     0.00  NilClass#to_a
  0.00     0.31      0.00        3     0.00     0.00  String#upcase
  0.00     0.31      0.00        5     0.00     0.00  ActiveRecord::Reflection::MacroReflection#initialize
  0.00     0.31      0.00        4     0.00     0.00  Regexp#===
  0.00     0.31      0.00        7     0.00     0.00  ActiveSupport::Dependencies.logger
  0.00     0.31      0.00        1     0.00   230.00  ActiveSupport::Dependencies::ClassConstMissing.const_missing
  0.00     0.31      0.00        1     0.00   150.00  ActiveSupport::Dependencies.load_file
  0.00     0.31      0.00        2     0.00     0.00  ActiveRecord::Associations::ClassMethods.create_has_many_reflection
  0.00     0.31      0.00       16     0.00     0.00  ActiveSupport::CoreExtensions::Array::ExtractOptions.extract_options!
  0.00     0.31      0.00        1     0.00     0.00  WillPaginate::Finder::ClassMethods.respond_to?
  0.00     0.31      0.00        5     0.00     0.00  Hash#merge
  0.00     0.31      0.00        1     0.00    10.00  Enumerable.any?
  0.00     0.31      0.00        1     0.00     0.00  ActiveRecord::Validations::ClassMethods.validates_presence_of
  0.00     0.31      0.00        1     0.00     0.00  ActiveRecord::NamedScope::ClassMethods.named_scope
  0.00     0.31      0.00        4     0.00     5.00  ActiveSupport::CoreExtensions::String::Inflections.singularize
  0.00     0.31      0.00        8     0.00     0.00  ActiveSupport::Inflector.inflections
  0.00     0.31      0.00        4     0.00     0.00  String#blank?
  0.00     0.31      0.00        1     0.00     0.00  ActiveRecord::DynamicFinderMatch#initialize
  0.00     0.31      0.00       27     0.00     0.00  Symbol#===
  0.00     0.31      0.00        7     0.00     0.00  Hash#initialize_copy
  0.00     0.31      0.00        1     0.00     0.00  ActiveRecord::Base#respond_to?
  0.00     0.31      0.00        1     0.00    80.00  InPlaceEditingPlus.reset_collection
  0.00     0.31      0.00        1     0.00     0.00  ActiveRecord::Associations::ClassMethods.configure_dependency_for_has_one
  0.00     0.31      0.00        2     0.00     0.00  Kernel.Array
  0.00     0.31      0.00       14     0.00     0.00  Module#constants
  0.00     0.31      0.00        2     0.00     5.00  ActiveSupport::CoreExtensions::Module.local_constants
  0.00     0.31      0.00       21     0.00     0.00  Regexp#escape
  0.00     0.31      0.00        3     0.00     0.00  File#join
  0.00     0.31      0.00        1     0.00     0.00  ActiveRecord::AutosaveAssociation::ClassMethods.has_one
  0.00     0.31      0.00        4     0.00     5.00  ActiveSupport::Inflector.singularize
  0.00     0.31      0.00        8     0.00     0.00  Hash#has_key?
  0.00     0.31      0.00        6     0.00     1.67  ActiveRecord::Base#validate
  0.00     0.31      0.00       37     0.00     0.00  Module#define_method
  0.00     0.31      0.00        3     0.00     0.00  ActiveSupport::Dependencies.log
  0.00     0.31      0.00        7     0.00     0.00  ActiveSupport::Dependencies.log_activity
  0.00     0.31      0.00        1     0.00     0.00  Kernel.==
  0.00     0.31      0.00        1     0.00     0.00  Kernel.send
  0.00     0.31      0.00        1     0.00     0.00  Array#pop
  0.00     0.31      0.00        2     0.00    55.00  ActiveRecord::AutosaveAssociation::ClassMethods.has_many
  0.00     0.31      0.00        1     0.00   120.00  Kernel.load_without_new_constant_marking
  0.00     0.31      0.00        4     0.00     0.00  String#initialize_copy
  0.00     0.31      0.00       15     0.00     0.00  ActiveSupport::Callbacks::CallbackChain#extract_options
  0.00     0.31      0.00        6     0.00     0.00  ActiveRecord::Associations::ClassMethods.association_constructor_method
  0.00     0.31      0.00        1     0.00     0.00  String#+
  0.00     0.31      0.00        9     0.00     0.00  ActiveSupport::Dependencies.uninherited_const_defined?
  0.00     0.31      0.00        1     0.00   230.00  ActiveSupport::Dependencies.load_missing_constant
  0.00     0.31      0.00        1     0.00   140.00  ActiveSupport::Dependencies.new_constants_in
  0.00     0.31      0.00       38     0.00     0.00  Object#method_added
  0.00     0.31      0.00       38     0.00     0.00  ActiveRecord::Reflection::MacroReflection#name
  0.00     0.31      0.00        1     0.00     0.00  Observable.notify_observers
  0.00     0.31      0.00        1     0.00     0.00  Enumerable.map
  0.00     0.31      0.00        4     0.00     0.00  ActiveRecord::Base#before_save
  0.00     0.31      0.00        3     0.00     0.00  File#file?
  0.00     0.31      0.00        2     0.00     0.00  Set#<<
  0.00     0.31      0.00        3     0.00     0.00  ActiveSupport::Dependencies.constant_watch_stack_mutex
  0.00     0.31      0.00       15     0.00     0.00  Kernel.equal?
  0.00     0.31      0.00        2     0.00     0.00  Kernel.lambda
  0.00     0.31      0.00        2     0.00     5.00  ActiveRecord::Associations::ClassMethods.collection_reader_method
  0.00     0.31      0.00        2     0.00     5.00  ActiveRecord::AutosaveAssociation::ClassMethods.belongs_to
  0.00     0.31      0.00        4     0.00     0.00  Object#duplicable?
  0.00     0.31      0.00       57     0.00     0.00  Array#flatten
  0.00     0.31      0.00       53     0.00     0.00  Module#==
  0.00     0.31      0.00       43     0.00     0.00  Class#new
  0.00     0.31      0.00        1     0.00     0.00  ActiveRecord::Validations::ClassMethods.validation_method
  0.00     0.31      0.00        1     0.00     0.00  ActiveSupport::Dependencies.to_constant_name
  0.00     0.31      0.00      100     0.00     0.00  Kernel.class
  0.00     0.31      0.00        2     0.00     0.00  Integer#times
  0.00     0.31      0.00        8     0.00     0.00  Object#returning
  0.00     0.31      0.00        5     0.00     2.00  ActiveRecord::AutosaveAssociation::ClassMethods.add_autosave_association_callbacks
  0.00     0.31      0.00       31     0.00     0.00  Kernel.block_given?
  0.00     0.31      0.00        1     0.00     0.00  ActiveRecord::DynamicFinderMatch#match
  0.00     0.31      0.00        6     0.00     3.33  Array#collect
  0.00     0.31      0.00        4     0.00     0.00  ActiveSupport::Dependencies.log_call
  0.00     0.31      0.00        1     0.00     0.00  Array#delete_if
  0.00     0.31      0.00        6     0.00     0.00  Fixnum#==
  0.00     0.31      0.00        1     0.00     0.00  String#sub
  0.00     0.31      0.00        2     0.00    10.00  ActiveSupport::CoreExtensions::Module.local_constant_names
  0.00     0.31      0.00        7     0.00     0.00  Hash#include?
  0.00     0.31      0.00        1     0.00   310.00  Object#profile_me
  0.00     0.31      0.00        8     0.00     0.00  ActiveSupport::Inflector::Inflections#instance
  0.00     0.31      0.00        2     0.00     5.00  ActiveRecord::Associations::ClassMethods.add_association_callbacks
  0.00     0.31      0.00        5     0.00    16.00  ActiveRecord::Reflection::ClassMethods.reflect_on_association
  0.00     0.31      0.00        5     0.00     0.00  Class#write_inheritable_hash
  0.00     0.31      0.00       10     0.00     0.00  Kernel.object_id
  0.00     0.31      0.00        5     0.00     0.00  ActiveSupport::CoreExtensions::Hash::Keys.assert_valid_keys
  0.00     0.31      0.00        2     0.00    10.00  ActiveRecord::Associations::ClassMethods.collection_accessor_methods
  0.00     0.31      0.00       20     0.00     0.00  Array#initialize
  0.00     0.31      0.00        8     0.00     0.00  Array#include?
  0.00     0.31      0.00        1     0.00     0.00  ActiveRecord::DynamicScopeMatch#initialize
  0.00     0.31      0.00        2     0.00     0.00  ActiveSupport::Inflector.camelize
  0.00     0.31      0.00        1     0.00   310.00  #toplevel

数据含义 根据第一行 head 自行理解。

首先 找到App#test_reset_collection 因为这是我们检测方法的入口。可以发现

0.00     0.31      0.00        1     0.00    80.00  App#test_reset_collection

执行了一次,花了80ms。而这80ms花在哪了呢?

我的方法只执行了两句,第一句是map创建数组

25.81     0.08      0.08       53     1.51     1.70  Array#map

0.00     0.31      0.00        1     0.00     0.00  Enumerable.map

可以看出 执行50次 map的时间是非常少的。几乎可以忽略不计。

第二局是重新排列数组。

0.00     0.31      0.00        1     0.00    80.00  InPlaceEditingPlus.reset_collection

显示 花了80ms。整个函数的时间都花在这了。 如果执行一次需要80ms的话 如果遍历20次 则是1600ms也就是1.6秒,这个速度慢的可以。

下一步: 优化

def reset_collection(collection=nil)
  return [] if collection.nil?
  if collection.first.to_a.flatten.map(&:class) == [String, Fixnum]
    collection.map{|t| t.reverse}
  else
    collection
  end
end

根据数组的第一个元素就判断 数组是否需要反转。这样减少了很多遍历时间。

再次执行 ruby script/performance/profiler “App.test_reset_collection”
结果:

%   cumulative   self              self     total
 time   seconds   seconds    calls  ms/call  ms/call  name
 30.77     0.08      0.08        1    80.00   260.00  ActiveSupport::Dependencies.load_missing_constant
 26.92     0.15      0.07       38     1.84     1.84  ActiveRecord::Reflection::MacroReflection#name
  7.69     0.17      0.02       33     0.61     0.61  Array#each
  7.69     0.19      0.02        2    10.00    10.00  Array#select
  3.85     0.20      0.01       15     0.67     0.67  ActiveSupport::Callbacks::CallbackChain#extract_options
  3.85     0.21      0.01        1    10.00   180.00  ActiveSupport::Dependencies.require_or_load
  3.85     0.22      0.01        8     1.25     1.25  ActiveRecord::Reflection::MacroReflection#macro
  3.85     0.23      0.01        4     2.50     5.00  Array#map
  3.85     0.24      0.01        8     1.25     1.25  Object#returning
  3.85     0.25      0.01        7     1.43     2.86  ActiveSupport::Dependencies.qualified_const_defined?
  3.85     0.26      0.01      550     0.02     0.02  String#to_s
  0.00     0.26      0.00        9     0.00     0.00  Array#empty?
  0.00     0.26      0.00        1     0.00     0.00  ActiveRecord::Associations::ClassMethods.create_has_one_reflection
  0.00     0.26      0.00        5     0.00     0.00  ActiveSupport::CoreExtensions::Hash::Keys.assert_valid_keys
  0.00     0.26      0.00        8     0.00     0.00  ActiveSupport::Inflector::Inflections#instance
  0.00     0.26      0.00        5     0.00     0.00  String#downcase
  0.00     0.26      0.00        1     0.00     0.00  Enumerable::Enumerator#each
  0.00     0.26      0.00        1     0.00     0.00  Array#delete_if
  0.00     0.26      0.00        2     0.00     5.00  ActiveRecord::Associations::ClassMethods.add_association_callbacks
  0.00     0.26      0.00        2     0.00     0.00  ActiveRecord::Associations::ClassMethods.belongs_to
  0.00     0.26      0.00        3     0.00     0.00  Array#<<
  0.00     0.26      0.00        1     0.00     0.00  ActiveSupport::Inflector.underscore
  0.00     0.26      0.00        5     0.00     0.00  Hash#keys
  0.00     0.26      0.00       38     0.00     0.00  Object#method_added
  0.00     0.26      0.00        7     0.00     0.00  Hash#include?
  0.00     0.26      0.00        1     0.00     0.00  TrueClass#duplicable?
  0.00     0.26      0.00        1     0.00   260.00  Object#profile_me
  0.00     0.26      0.00       16     0.00     0.00  ActiveSupport::CoreExtensions::Array::ExtractOptions.extract_options!
  0.00     0.26      0.00        2     0.00     0.00  ActiveRecord::Associations::ClassMethods.configure_dependency_for_belongs_to
  0.00     0.26      0.00       15     0.00     0.00  Kernel.equal?
  0.00     0.26      0.00        6     0.00     0.00  Hash#update
  0.00     0.26      0.00        1     0.00     0.00  Symbol#to_proc
  0.00     0.26      0.00        1     0.00     0.00  Array#pop
  0.00     0.26      0.00        2     0.00     0.00  Kernel.lambda
  0.00     0.26      0.00       31     0.00     0.00  Kernel.block_given?
  0.00     0.26      0.00        5     0.00     0.00  Class#write_inheritable_hash
  0.00     0.26      0.00        1     0.00     0.00  Observable.changed
  0.00     0.26      0.00        9     0.00     0.00  ActiveSupport::Dependencies.uninherited_const_defined?
  0.00     0.26      0.00        1     0.00     0.00  ActiveSupport::Dependencies.warnings_on_first_load
  0.00     0.26      0.00        2     0.00     0.00  Kernel.class
  0.00     0.26      0.00        1     0.00     0.00  Array#blank?
  0.00     0.26      0.00       38     0.00     0.00  Module#blank_slate_method_added
  0.00     0.26      0.00        3     0.00     0.00  Module#===
  0.00     0.26      0.00        1     0.00     0.00  ActiveSupport::Dependencies.search_for_file
  0.00     0.26      0.00        1     0.00     0.00  Array#compact
  0.00     0.26      0.00        4     0.00     0.00  Object#duplicable?
  0.00     0.26      0.00       50     0.00     0.00  Array#reverse
  0.00     0.26      0.00        1     0.00     0.00  ActiveRecord::Associations::ClassMethods.valid_keys_for_has_one_association
  0.00     0.26      0.00        4     0.00     0.00  ActiveRecord::Base#before_save
  0.00     0.26      0.00        3     0.00     0.00  ActiveSupport::Dependencies.constant_watch_stack_mutex
  0.00     0.26      0.00        1     0.00     0.00  Observable.notify_observers
  0.00     0.26      0.00       15     0.00     0.00  Array#map!
  0.00     0.26      0.00        2     0.00     0.00  ActiveRecord::Associations::ClassMethods.valid_keys_for_belongs_to_association
  0.00     0.26      0.00        1     0.00     0.00  ActiveSupport::Dependencies.to_constant_name
  0.00     0.26      0.00        1     0.00     0.00  ActiveRecord::Observing::ClassMethods.inherited
  0.00     0.26      0.00        1     0.00   260.00  ActiveSupport::Dependencies::ClassConstMissing.const_missing
  0.00     0.26      0.00        1     0.00     0.00  Array#==
  0.00     0.26      0.00        1     0.00     0.00  ActiveRecord::Validations::ClassMethods.validates_presence_of
  0.00     0.26      0.00        1     0.00     0.00  ActiveRecord::Base#after_save
  0.00     0.26      0.00        2     0.00     0.00  String#size
  0.00     0.26      0.00       10     0.00     0.00  String#split
  0.00     0.26      0.00       50     0.00     0.00  Symbol#to_s
  0.00     0.26      0.00        3     0.00     0.00  ActiveSupport::Dependencies.constant_watch_stack
  0.00     0.26      0.00        1     0.00     0.00  Kernel.respond_to?
  0.00     0.26      0.00        2     0.00     0.00  Array#initialize_copy
  0.00     0.26      0.00        8     0.00     0.00  Array#flatten
  0.00     0.26      0.00       14     0.00     0.00  Module#constants
  0.00     0.26      0.00       79     0.00     0.00  Hash#[]
  0.00     0.26      0.00        3     0.00     0.00  ActiveSupport::Dependencies.log
  0.00     0.26      0.00        2     0.00     0.00  Kernel.hash
  0.00     0.26      0.00        1     0.00     0.00  String#tr
  0.00     0.26      0.00        3     0.00     0.00  Mutex#synchronize
  0.00     0.26      0.00       45     0.00     0.00  Hash#default
  0.00     0.26      0.00        1     0.00   170.00  ActiveSupport::Dependencies.load_file
  0.00     0.26      0.00       13     0.00     0.00  Module#const_get
  0.00     0.26      0.00        1     0.00     0.00  ActiveRecord::Base#respond_to?
  0.00     0.26      0.00        1     0.00     0.00  ActiveSupport::Dependencies.qualified_name_for
  0.00     0.26      0.00        1     0.00     0.00  Kernel.instance_variable_set
  0.00     0.26      0.00        3     0.00     0.00  ActiveSupport::Dependencies.loaded
  0.00     0.26      0.00        1     0.00     0.00  ActiveRecord::DynamicScopeMatch#initialize
  0.00     0.26      0.00        1     0.00     0.00  Array#to_a
  0.00     0.26      0.00       24     0.00     0.00  String#to_sym
  0.00     0.26      0.00        2     0.00     0.00  NilClass#to_a
  0.00     0.26      0.00        1     0.00     0.00  NameError#initialize
  0.00     0.26      0.00        2     0.00     0.00  ActiveSupport::CoreExtensions::String::Inflections.camelize
  0.00     0.26      0.00        4     0.00     0.00  Regexp#===
  0.00     0.26      0.00        1     0.00     0.00  String#+
  0.00     0.26      0.00        2     0.00    10.00  ActiveRecord::Associations::ClassMethods.has_many
  0.00     0.26      0.00        8     0.00     1.25  ActiveSupport::Inflector.inflections
  0.00     0.26      0.00        5     0.00     0.00  Kernel.nil?
  0.00     0.26      0.00        3     0.00     0.00  ActiveRecord::Associations::ClassMethods.association_accessor_methods
  0.00     0.26      0.00        4     0.00     0.00  String#blank?
  0.00     0.26      0.00        2     0.00    20.00  ActiveSupport::CoreExtensions::Module.local_constant_names
  0.00     0.26      0.00        1     0.00     0.00  ActiveRecord::Associations::ClassMethods.configure_dependency_for_has_one
  0.00     0.26      0.00        4     0.00     2.50  ActiveSupport::CoreExtensions::String::Inflections.singularize
  0.00     0.26      0.00        2     0.00     0.00  ActiveRecord::Associations::ClassMethods.configure_dependency_for_has_many
  0.00     0.26      0.00       21     0.00     0.00  Regexp#escape
  0.00     0.26      0.00       18     0.00     0.00  Array#concat
  0.00     0.26      0.00       10     0.00     0.00  String#empty?
  0.00     0.26      0.00        1     0.00   170.00  ActiveSupport::Dependencies.new_constants_in
  0.00     0.26      0.00        1     0.00     0.00  ActiveRecord::Associations::ClassMethods.has_one
  0.00     0.26      0.00        2     0.00     0.00  Module#ancestors
  0.00     0.26      0.00        5     0.00     0.00  Module#name
  0.00     0.26      0.00        1     0.00     0.00  ActiveRecord::DynamicFinderMatch#initialize
  0.00     0.26      0.00        1     0.00     0.00  Exception#initialize
  0.00     0.26      0.00        1     0.00     0.00  Enumerable.map
  0.00     0.26      0.00        1     0.00     0.00  String#sub
  0.00     0.26      0.00        3     0.00     0.00  ActiveSupport::Inflector.constantize
  0.00     0.26      0.00       29     0.00     0.00  Kernel.is_a?
  0.00     0.26      0.00        2     0.00     0.00  Array#*
  0.00     0.26      0.00        4     0.00     0.00  Kernel.singleton_method_added
  0.00     0.26      0.00        1     0.00     0.00  ActiveRecord::Base#default_scope
  0.00     0.26      0.00       23     0.00     0.00  Hash#[]=
  0.00     0.26      0.00        2     0.00     0.00  Symbol#to_sym
  0.00     0.26      0.00        3     0.00     0.00  File#file?
  0.00     0.26      0.00        2     0.00     0.00  ActiveSupport::Dependencies.autoloaded_constants
  0.00     0.26      0.00        1     0.00     0.00  Enumerable.any?
  0.00     0.26      0.00       13     0.00     0.00  String#starts_with?
  0.00     0.26      0.00       15     0.00     0.00  Array#flatten!
  0.00     0.26      0.00       10     0.00     0.00  Kernel.object_id
  0.00     0.26      0.00        1     0.00     0.00  InPlaceEditingPlus.reset_collection
  0.00     0.26      0.00        2     0.00     0.00  ActiveRecord::Base#after_update
  0.00     0.26      0.00       20     0.00     0.00  Array#initialize
  0.00     0.26      0.00        5     0.00     0.00  ActiveRecord::Reflection::ClassMethods.reflect_on_association
  0.00     0.26      0.00        1     0.00     0.00  ActiveRecord::DynamicScopeMatch#match
  0.00     0.26      0.00        7     0.00     0.00  Hash#initialize_copy
  0.00     0.26      0.00       14     0.00     0.00  Class#write_inheritable_attribute
  0.00     0.26      0.00        6     0.00    10.00  Array#collect
  0.00     0.26      0.00       24     0.00     0.00  File#expand_path
  0.00     0.26      0.00        1     0.00     0.00  ActiveSupport::Dependencies.history
  0.00     0.26      0.00        1     0.00     0.00  Array#uniq!
  0.00     0.26      0.00        1     0.00     0.00  ActiveSupport::Dependencies.load_once_path?
  0.00     0.26      0.00        1     0.00     0.00  ActiveRecord::Validations::ClassMethods.validation_method
  0.00     0.26      0.00        1     0.00     0.00  ActiveRecord::NamedScope::ClassMethods.named_scope
  0.00     0.26      0.00        6     0.00     1.67  ActiveRecord::Base#validate
  0.00     0.26      0.00        2     0.00    10.00  ActiveSupport::CoreExtensions::Module.local_constants
  0.00     0.26      0.00        1     0.00     0.00  Kernel.==
  0.00     0.26      0.00        6     0.00     0.00  Array#-
  0.00     0.26      0.00        8     0.00     0.00  Hash#has_key?
  0.00     0.26      0.00        4     0.00     0.00  ActiveSupport::Dependencies.log_call
  0.00     0.26      0.00       52     0.00     0.00  Class#inheritable_attributes
  0.00     0.26      0.00        8     0.00     0.00  Array#include?
  0.00     0.26      0.00        5     0.00    18.00  ActiveRecord::AutosaveAssociation::ClassMethods.add_autosave_association_callbacks
  0.00     0.26      0.00        1     0.00     0.00  Kernel.instance_eval
  0.00     0.26      0.00        1     0.00   260.00  ActiveSupport::Dependencies::ModuleConstMissing.const_missing
  0.00     0.26      0.00        1     0.00     0.00  ActiveSupport::Dependencies.load_once_paths
  0.00     0.26      0.00        5     0.00     0.00  ActiveRecord::Reflection::MacroReflection#initialize
  0.00     0.26      0.00       12     0.00     0.00  Module#const_defined?
  0.00     0.26      0.00       11     0.00     0.00  Array#first
  0.00     0.26      0.00        1     0.00     0.00  Class#inherited
  0.00     0.26      0.00        2     0.00     0.00  Integer#times
  0.00     0.26      0.00        2     0.00    45.00  ActiveRecord::AutosaveAssociation::ClassMethods.has_many
  0.00     0.26      0.00        2     0.00     0.00  Kernel.Array
  0.00     0.26      0.00       37     0.00     0.00  Module#define_method
  0.00     0.26      0.00        7     0.00     0.00  ActiveSupport::Dependencies.logger
  0.00     0.26      0.00        6     0.00     0.00  String#[]
  0.00     0.26      0.00        3     0.00     0.00  File#join
  0.00     0.26      0.00        2     0.00     0.00  ActiveRecord::Associations::ClassMethods.create_has_many_reflection
  0.00     0.26      0.00       10     0.00     0.00  ActiveRecord::Reflection::ClassMethods.reflections
  0.00     0.26      0.00        6     0.00     0.00  ActiveRecord::Associations::ClassMethods.association_constructor_method
  0.00     0.26      0.00        3     0.00     0.00  String#upcase
  0.00     0.26      0.00        1     0.00     0.00  WillPaginate::Finder::ClassMethods.respond_to?
  0.00     0.26      0.00        2     0.00     0.00  Set#include?
  0.00     0.26      0.00        6     0.00     0.00  Fixnum#==
  0.00     0.26      0.00        1     0.00     0.00  ActiveRecord::NamedScope::ClassMethods.scopes
  0.00     0.26      0.00        1     0.00    10.00  ActiveRecord::AutosaveAssociation::ClassMethods.has_one
  0.00     0.26      0.00        2     0.00     5.00  ActiveRecord::Associations::ClassMethods.collection_accessor_methods
  0.00     0.26      0.00        2     0.00     5.00  ActiveRecord::AutosaveAssociation::ClassMethods.belongs_to
  0.00     0.26      0.00        2     0.00     0.00  ActiveRecord::Associations::ClassMethods.create_belongs_to_reflection
  0.00     0.26      0.00       36     0.00     0.00  String#==
  0.00     0.26      0.00      128     0.00     0.00  String#gsub!
  0.00     0.26      0.00       15     0.00     0.67  ActiveSupport::Callbacks::CallbackChain#build
  0.00     0.26      0.00       15     0.00     0.00  ActiveSupport::Callbacks::Callback#initialize
  0.00     0.26      0.00        1     0.00     0.00  ActiveSupport::Dependencies.loadable_constants_for_path
  0.00     0.26      0.00        1     0.00     0.00  Hash#each
  0.00     0.26      0.00        3     0.00     0.00  ActiveSupport::CoreExtensions::String::Inflections.constantize
  0.00     0.26      0.00        8     0.00     1.25  Enumerable.inject
  0.00     0.26      0.00        7     0.00     0.00  String#gsub
  0.00     0.26      0.00        2     0.00     0.00  Set#<<
  0.00     0.26      0.00      537     0.00     0.00  Hash#key?
  0.00     0.26      0.00        5     0.00     0.00  Hash#merge
  0.00     0.26      0.00        1     0.00   110.00  Kernel.load_without_new_constant_marking
  0.00     0.26      0.00        9     0.00     0.00  ActiveRecord::Reflection::MacroReflection#options
  0.00     0.26      0.00        1     0.00     0.00  Kernel.send
  0.00     0.26      0.00        2     0.00     0.00  ActiveSupport::Inflector.camelize
  0.00     0.26      0.00        1     0.00     0.00  ActiveSupport::Dependencies.load?
  0.00     0.26      0.00        1     0.00     0.00  ActiveSupport::CoreExtensions::String::Inflections.underscore
  0.00     0.26      0.00        4     0.00     0.00  String#initialize_copy
  0.00     0.26      0.00        1     0.00     0.00  ActiveRecord::DynamicFinderMatch#match
  0.00     0.26      0.00        1     0.00     0.00  String#ends_with?
  0.00     0.26      0.00        8     0.00     0.00  Kernel.dup
  0.00     0.26      0.00       22     0.00     0.00  Class#read_inheritable_attribute
  0.00     0.26      0.00        2     0.00     0.00  ActiveRecord::Associations::ClassMethods.create_extension_modules
  0.00     0.26      0.00        2     0.00     0.00  ActiveRecord::Associations::ClassMethods.valid_keys_for_has_many_association
  0.00     0.26      0.00        7     0.00     0.00  ActiveSupport::Dependencies.log_activity
  0.00     0.26      0.00        1     0.00     0.00  App#test_reset_collection
  0.00     0.26      0.00        2     0.00     0.00  ActiveRecord::Base#after_create
  0.00     0.26      0.00        8     0.00     0.00  ActiveSupport::Inflector.inflections_without_route_reloading
  0.00     0.26      0.00        1     0.00     0.00  Array#uniq
  0.00     0.26      0.00        5     0.00     0.00  ActiveRecord::Reflection::ClassMethods.create_reflection
  0.00     0.26      0.00        2     0.00     0.00  ActiveRecord::Associations::ClassMethods.collection_reader_method
  0.00     0.26      0.00        2     0.00     0.00  ActiveSupport::Dependencies.load_paths
  0.00     0.26      0.00        1     0.00     0.00  ActiveSupport::Dependencies.mechanism
  0.00     0.26      0.00        1     0.00     0.00  ActiveRecord::Base#default_scoping
  0.00     0.26      0.00        4     0.00     2.50  ActiveSupport::Inflector.singularize
  0.00     0.26      0.00        2     0.00     0.00  NilClass#nil?
  0.00     0.26      0.00       43     0.00     0.00  Class#new
  0.00     0.26      0.00       53     0.00     0.00  Module#==
  0.00     0.26      0.00       16     0.00     0.00  Array#last
  0.00     0.26      0.00        1     0.00     0.00  ActiveRecord::Base#inherited
  0.00     0.26      0.00       27     0.00     0.00  Symbol#===
  0.00     0.26      0.00        1     0.00   260.00  #toplevel

可以看出方法执行了0秒,就是几乎不花时间,我们这个方法中如果元素排列正确的话 就直接返回结果 如果排列不正确呢?没有测。因此需要改下测试数据将 c = 50.times.map{|i| ["andy", 1]} 改成 c = 50.times.map{|i| [1, "andy"]}。测试结果仍然是 0,优化成功。

你也可以通过 ruby script/performance/benchmarker 100 “App.test_reset_collection” 来检测方法执行速度,但是结果没有profiler详细。

user     system      total        real
#1      0.080000   0.000000   0.080000 (  0.078968)

但是有个好处 就是 benchmarker 可以将两个方法的执行效率进行比,结果非常直。

ruby script/performance/benchmarker “App.test_reset_collection” “App.test_in_place”

user     system      total        real
#1      0.000000   0.000000   0.000000 (  0.000142)
#2      0.000000   0.000000   0.000000 (  0.000569)
Categories: rails Tags:

cache and sweeper in rails

July 8th, 2010 yakjuly No comments

以关键字来分组显示列表,往往因为查询的数据量大,导致页面打开慢。使用cache action可以大大提高速度。

需要通过sweeper监控model的增删改动作,定时清理缓存。

models:

class TagPage < Page
  has_one :extra, :class_name => "TagPageExtra", :autosave => true
end

class TagPageExtra < ActiveRecord::Base
  belongs_to :tag_page
end

TagPage是扩展了以前的代码,对于新增的属性,通过TagPageExtra来处理。

controller:

class TagPagesController < ApplicationController
  caches_action :list

  def list
    @pages = TagPage.all(:select => "pages.id, pages.title, pages.description", :include => [:extra],
: order => "tag_page_extras.position")
  end

end

sweeper:

#文件放在 app/sweepers文件夹下
#并在environment中添加 文件路径
config.load_paths += %W( #{RAILS_ROOT}/app/sweepers )

class TagPageSweeper < ActionController::Caching::Sweeper
  observe TagPage

   def after_create(obj)
    expire_cache_for(obj)
  end

  def after_destroy(obj)
    expire_cache_for(obj)
  end

  def after_update(obj)
    expire_cache_for(obj)
  end

  private
  def expire_cache_for(obj)
    expire_action(list_tag_pages_path)
  end
end

#注意要在application controller中声明 才会起作用
class ApplicationController < ActionController::Base
  cache_sweeper :tag_page_sweeper
end

view:

<%= t("records_not_found")  if @pages.blank? %>
<dl>
  <% @pages.group_by(&:description).each do |description, pages| %>
  <dt><%= link_to description.nil? ? "<b>null</b>" : "<b>#{description}</b>", tag_pages_path(:tag => description) %></dt>
  <dd>
    <ul>
    <% pages.each do |page| %>
      <li class="tag"><%= link_to page.title, edit_tag_page_path(page) %></li>
    <% end %>
    </ul>
  </dd>
  <% end %>
</dl>

结果:
ProcessingTagPagesController#list (for xxx.xxx.xxx.xxx at 2010-07-08 09:24:03) [GET]
Filter chain halted as [#<ActionController::Filters::AroundFilter:0xb60d27d8 @identifier=nil,
@kind=:filter, @method=#<Proc:0xb79b6ba0@/usr/lib/ruby/gems/1.8/gems/actionpack-2.3.4/lib/action_controller/caching/actions.rb:64>,
@options={:only=>#<Set: {"list"}>, :if=>nil, :unless=>nil}>] did_not_yield.
Completed in 8ms (View: 0, DB: 0) | 200 OK [http://www.xxxx.com/tag_pages/list]
这次直接读取了缓存 DB查询为0.

item_list

Categories: rails Tags: