网站: JavaEye 作者: hideto 发表时间: 2007-07-25 14:25 此文章来自于 http://www.iteye.com
声明:本文系JavaEye网站原创文章,未经JavaEye网站或者作者本人书面许可,任何其他网站严禁擅自发表本文,否则必将追究法律责任!
原文链接: http://www.iteye.com/topic/105380
Rails宝典之第二式: 动态find_by方法 忘了声明了,这个系列主要是Rails入门教学。 今天Rails宝典教大家的是动态find_by方法,我们先看一段代码:
代码
class TasksController < ApplicationController def incomplete @tasks = Task.find(:all, :conditions => ['complete = ?', false]) end end
很类似Hibernate的数据库查询hql语句,但显然我们的Rails不可能这么逊,看看改良的方法:
代码
class TasksController < ApplicationController def incomplete @tasks = Task.find_all_by_complete(false) end end
我们的Task这个Model类没有定义find_all_by_complete啊,我们为什么可以调用这个方法呢? 请看active_record/base.rb中的一段代码:
代码
def method_missing(method_id, *arguments) if match = /^find_(all_by|by)_([_a-zA-Z]\w*)$/.match(method_id.to_s) finder = determine_finder(match) attribute_names = extract_attribute_names_from_match(match) super unless all_attributes_exists?(attribute_names) attributes = construct_attributes_from_arguments(attribute_names, arguments) case extra_options = arguments[attribute_names.size] when nil options = { :conditions => attributes } set_readonly_option!(options) ActiveSupport::Deprecation.silence { send(finder, options) } when Hash finder_options = extra_options.merge(:conditions => attributes) validate_find_options(finder_options) set_readonly_option!(finder_options) if extra_options[:conditions] with_scope(:find => { :conditions => extra_options[:conditions] }) do ActiveSupport::Deprecation.silence { send(finder, finder_options) } end else ActiveSupport::Deprecation.silence { send(finder, finder_options) } end else raise ArgumentError, "Unrecognized arguments for #{method_id}: #{extra_options.inspect}" end elsif match = /^find_or_(initialize|create)_by_([_a-zA-Z]\w*)$/.match(method_id.to_s) instantiator = determine_instantiator(match) attribute_names = extract_attribute_names_from_match(match) super unless all_attributes_exists?(attribute_names) if arguments[0].is_a?(Hash) attributes = arguments[0].with_indifferent_access find_attributes = attributes.slice(*attribute_names) else find_attributes = attributes = construct_attributes_from_arguments(attribute_names, arguments) end options = { :conditions => find_attributes } set_readonly_option!(options) find_initial(options) || send(instantiator, attributes) else super end end def extract_attribute_names_from_match(match) match.captures.last.split('_and_') end
看看第一行代码:if match = /^find_(all_by|by)_([_a-zA-Z]\w*)$/.match(method_id.to_s) 这是一个正则表达式匹配: ^匹配一行的开始 $匹配一行的结束 \w匹配一个词语,可以是数字、字母、下划线 []匹配括号里面符合的一个字符 *匹配0个或多个它前面的字符或短语 则([_a-zA-Z]\w*)则匹配以下划线或任意小写字母或任意大写字母开头的一个字符串 具体参考《Programming Ruby》中的Regular Expressions一章 而extract_attribute_names_from_match方法也很有意思,match.captures返回匹配的字符串组成的数组,last返回最后一个元素,如:
代码
/^(a)_(b)_(\w*)$/.match("a_b_c_d_e_f_g").captures # => ["a", "b", "c_d_e_f_g"] /^(a)_(b)_(\w*)$/.match("a_b_c_d_e_f_g").captures.last # =>"c_d_e_f_g" /^find_(all_by|by)_([_a-zA-Z]\w*)$/.match("find_by_a_and_b_and_c").captures.last # => "a_and_b_and_c"
这样,第一行代码所匹配的方法名具体为find_by(或all_by)_aaaBBB形式 而且可以看出,我们还可以调用find_by_columnName、find_or_initialize_by_columnName、find_or_create_by_columnName等动态方法。 总结: JavaScript也是一门大家可能忽略了但又十分强大的动态语言,参考Ruby和Python,JavaScript还有很大潜力可挖。 |
《 Rails宝典之第二式: 动态find_by方法 》 的评论也很精彩,欢迎您也添加评论。查看详细 >>
推荐相关文章:
Rails宝典之第一式: 实例变量做查询缓存?
ActionController::Resources + ActiveResource = REST
JavaEye推荐
上海乐福狗信息技术有限公司:诚聘技术经理和开发工程师
免费下载IBM社区版软件--它基于开放的标准,支持广泛的开发类型,让您的开发高效自主!
京沪穗蓉四地免费注册,SOA技术高手汇聚交锋.
上海:优秀公司德比:高薪诚聘 资深Java工程师
广州:优易公司:诚聘Java工程师,开发经理
上海:尤恩斯国际集团:诚聘开发工程师
北京:优秀公司NHNChina招聘:WEB开发,系统管理,JAVA开发, DBA