论坛首页 编程语言技术论坛

修改auto_complete插件,支持虚拟属性

浏览 1752 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-12-03   最后修改:2010-01-23
   今天用auto_complete插件实现自动补全,但是中间遇到些问题.
   按照网上的方法在view里添加代码:
  
   <%= text_field_with_auto_complete :material, :material_number %>
   

   在controller里添加代码:
  
   auto_complete_for :material, :material_number
   

   开始跑一遍.试下,结果如何.
   页面上没有发生变化,打开log,提示如下信息
  
     Parameters: {"material"=>{"material_number"=>"cp"}}
  Material Load (0.0ms)   Mysql::Error: Unknown column 'material_number' in 'where clause': SELECT * FROM `materials` WHERE (LOWER(material_number) LIKE '%cp%') ORDER BY material_number ASC LIMIT 10
    

    因为material_number是material表里的虚拟属性,所以上面sql语句出错.
    这条sql语句应该是在auto_complete插件中实现的一个方法.
    找到auto_complete的源码
   
  module ClassMethods
    def auto_complete_for(object, method, options = {})
      define_method("auto_complete_for_#{object}_#{method}") do
        find_options = { 
          :conditions => [ "LOWER(#{method}) LIKE ?", '%' + params[object][method].downcase + '%' ], 
          :order => "#{method} ASC",
          :limit => 10 }.merge!(options)
        
        @items = object.to_s.camelize.constantize.find(:all, find_options)

        render :inline => "<%= auto_complete_result @items, '#{method}' %>"
      end
    end
  end
    

    原来如此,看来要自己要写一个方法了.cotroller里的代码
   
  #自动补全
  def auto_complete_for_material_material_number
    @items = Material.auto_complete_material_number(params[:material][:material_number],:order => 'first_number ASC',:limit => 10)
    render :inline => "<%= auto_complete_result @items, 'material_number' %>"
  end
     

     model里的代码
    
  #material_number自动补全重写
  def self.auto_complete_material_number(full_number,options = {})
    find_options = {:conditions => [ "first_number LIKE ? or last_number LIKE ?",
        '%' + full_number.downcase + '%' , '%' + full_number.downcase + '%' ]}.merge!(options)
 #   with_scope :find => options do
      Material.find(:all,find_options)
  #  end
  end
     

     关于material_number虚拟属性的读方法也贴出来,便于理解
    
      def material_number
        [self.first_number,self.last_number].join('-')
      end
     

     再试下,看有问题没,没有提示,看log
  Parameters: {"material"=>{"material_number"=>"c"}}
  Material Load (0.2ms)   SELECT * FROM `materials` WHERE (first_number LIKE '%c%' or last_number LIKE '%c%') ORDER BY first_number ASC LIMIT 10
Completed in 19ms (View: 1, DB: 0) | 200 OK [http://localhost/production/production_plans/auto_complete_for_material_material_number]

    然后在mysql中运行上述sql语句,有结果,但是为什么没有传到前台页面呢?
应该是controller中这句代码,一步一步的分析吧.
render :inline => "<%= auto_complete_result @items, 'material_number' %>"

的原因.这个auto_complete_result是什么呢?
    还是要回到源码中寻找答案.
  def auto_complete_result(entries, field, phrase = nil)
    return unless entries
    items = entries.map { |entry| content_tag("li", phrase ? highlight(entry[field], phrase) : h(entry[field])) }
    content_tag("ul", items.uniq)
  end

    猜想是不是这里"entry[field]",打开console,
>> material[:material_number]
=> nil
>> material.send(:material_number)
=> "cp-sj-nokia-2330"

   应该是这里的问题了.
   在help里增加方法
  #重写自动补全
  def auto_complete_result(entries, field, phrase = nil)
    return unless entries
    items = entries.map { |entry| content_tag("li", phrase ? highlight(entry.send(field), phrase) : h(entry.send(field))) }
    content_tag("ul", items.uniq)
  end

    再试下,好了,ok.






    
   
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics