- 浏览: 2666520 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
80后的童年2:
深入浅出MongoDB应用实战开发网盘地址:https://p ...
MongoDB入门教程 -
shliujing:
楼主在不是精通java和php的前提下,请不要妄下结论。
PHP、CakePHP哪凉快哪呆着去 -
安静听歌:
希望可以一给一点点注释
MySQL存储过程之代码块、条件控制、迭代 -
qq287767957:
PHP是全宇宙最强的语言!
PHP、CakePHP哪凉快哪呆着去 -
rryymmoK:
深入浅出MongoDB应用实战开发百度网盘下载:链接:http ...
MongoDB入门教程
ActiveRecord自带了三种数据结构关系:acts_as_tree、acts_as_list、acts_as_nested_set
1,tree.rb
从上面的代码我们学习到如下几点:
1) acts_as_tree实际上定义了belongs_to :parent和has_many :children,也就是说我们可以通过@model.parent和@model.children得到父子对象
2) acts_as_tree的配置参数有:foreign_key、:order => nil和:counter_cache
3) 其中定义了roots和root这两个Class Methods
4) 其中还定义了ancestors、root、sliblings、self_and_siblings这些Instance Methods
2,list.rb
从上面的代码我们学习到,acts_as_list的配置参数有:column和:scope
1) :column默认名为position
2) :scope后的参数为symbol时,如果没有_id则加上_id后缀
这样生成的scope_condition为"todo_list_id = #{todo_list_id}"
3) :scope后的参数为string时可以进行细粒度的限制
4) 实例方法很多,简单看看即可,不一一介绍了
3,nested_set.rb
我们可以得到如下几点:
1) acts_as_nested_set和acts_as_tree很类似,但是多一个特性是可以一条语句查询出所有的children
以及高效率的计算children_count
2) acts_as_nested_set的参数为:parent_column、:left_column、:right_column和:scope
3) 这种数据结构常用在threaded post system等场景
看了上述代码,相信大家可以自己动手写acts_as_xx数据结构了
BTW:对ActiveRecord源码的研究告一段落,还有query_cache/observer/xml_serialization/timestamp/calculations/migration等留待大家自己研究
接下来看看ActionController吧
1,tree.rb
module ActiveRecord module Acts module Tree def self.included(base) base.extend(ClassMethods) end module ClassMethods def acts_as_tree(options = {}) configuration = { :foreign_key => "parent_id", :order => nil, :counter_cache => nil } configuration.update(options) if options.is_a?(Hash) belongs_to :parent, :class_name => name, :foreign_key => configuration[:foreign_key], :counter_cache => configuration[:counter_cache] has_many :children, :class_name => name, :foreign_key => configuration[:foreign_key], :order => configuration[:order], :dependent => :destroy class_eval <<-EOV include ActiveRecord::Acts::Tree::InstanceMethods def self.roots find(:all, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}}) end def self.root find(:first, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}}) end EOV end end module InstanceMethods def ancestors node, nodes = self, [] nodes << node = node.parent while node.parent nodes end def root node = self node = node.parent while node.parent node end def siblings self_and_siblings - [self] end def self_and_siblings parent ? parent.children : self.class.roots end end end end end
从上面的代码我们学习到如下几点:
1) acts_as_tree实际上定义了belongs_to :parent和has_many :children,也就是说我们可以通过@model.parent和@model.children得到父子对象
2) acts_as_tree的配置参数有:foreign_key、:order => nil和:counter_cache
3) 其中定义了roots和root这两个Class Methods
4) 其中还定义了ancestors、root、sliblings、self_and_siblings这些Instance Methods
2,list.rb
module ActiveRecord module Acts module List def self.included(base) base.extend(ClassMethods) end module ClassMethods def acts_as_list(options = {}) configuration = { :column => "position", :scope => "1 = 1" } configuration.update(options) if options.is_a?(Hash) configuration[:scope] = "#{configuration[:scope]}_id".intern if configuration[:scope].is_a?(Symbol) && configuration[:scope].to_s !~ /_id$/ if configuration[:scope].is_a?(Symbol) scope_condition_method = %( def scope_condition if #{configuration[:scope].to_s}.nil? "#{configuration[:scope].to_s} IS NULL" else "#{configuration[:scope].to_s} = \#{#{configuration[:scope].to_s}}" end end ) else scope_condition_method = "def scope_condition() \"#{configuration[:scope]}\" end" end class_eval <<-EOV include ActiveRecord::Acts::List::InstanceMethods def acts_as_list_class ::#{self.name} end def position_column '#{configuration[:column]}' end #{scope_condition_method} after_destroy :remove_from_list before_create :add_to_list_bottom EOV end end module InstanceMethods def insert_at(position = 1) insert_at_position(position) end def move_lower return unless lower_item acts_as_list_class.transaction do lower_item.decrement_position increment_position end end def move_higher return unless higher_item acts_as_list_class.transaction do higher_item.increment_position decrement_position end end def move_to_bottom return unless in_list? acts_as_list_class.transaction do decrement_positions_on_lower_items assume_bottom_position end end def move_to_top return unless in_list? acts_as_list_class.transaction do increment_positions_on_higher_items assume_top_position end end def remove_from_list decrement_positions_on_lower_items if in_list? end def increment_position return unless in_list? update_attribute position_column, self.send(position_column).to_i + 1 end def decrement_position return unless in_list? update_attribute position_column, self.send(position_column).to_i - 1 end def first? return false unless in_list? self.send(position_column) == 1 end def last? return false unless in_list? self.send(position_column) == bottom_position_in_list end def higher_item return nil unless in_list? acts_as_list_class.find(:first, :conditions => "#{scope_condition} AND #{position_column} = #{(send(position_column).to_i - 1).to_s}" ) end def lower_item return nil unless in_list? acts_as_list_class.find(:first, :conditions => "#{scope_condition} AND #{position_column} = #{(send(position_column).to_i + 1).to_s}" ) end def in_list? !send(position_column).nil? end private def add_to_list_top increment_positions_on_all_items end def add_to_list_bottom self[position_column] = bottom_position_in_list.to_i + 1 end def scope_condition() "1" end def bottom_position_in_list(except = nil) item = bottom_item(except) item ? item.send(position_column) : 0 end def bottom_item(except = nil) conditions = scope_condition conditions = "#{conditions} AND #{self.class.primary_key} != #{except.id}" if except acts_as_list_class.find(:first, :conditions => conditions, :order => "#{position_column} DESC") end def assume_bottom_position update_attribute(position_column, bottom_position_in_list(self).to_i + 1) end def assume_top_position update_attribute(position_column, 1) end def decrement_positions_on_higher_items(position) acts_as_list_class.update_all( "#{position_column} = (#{position_column} - 1)", "#{scope_condition} AND #{position_column} <= #{position}" ) end def decrement_positions_on_lower_items return unless in_list? acts_as_list_class.update_all( "#{position_column} = (#{position_column} - 1)", "#{scope_condition} AND #{position_column} > #{send(position_column).to_i}" ) end def increment_positions_on_higher_items return unless in_list? acts_as_list_class.update_all( "#{position_column} = (#{position_column} + 1)", "#{scope_condition} AND #{position_column} < #{send(position_column).to_i}" ) end def increment_positions_on_lower_items(position) acts_as_list_class.update_all( "#{position_column} = (#{position_column} + 1)", "#{scope_condition} AND #{position_column} >= #{position}" ) end def increment_positions_on_all_items acts_as_list_class.update_all( "#{position_column} = (#{position_column} + 1)", "#{scope_condition}" ) end def insert_at_position(position) remove_from_list increment_positions_on_lower_items(position) self.update_attribute(position_column, position) end end end end end
从上面的代码我们学习到,acts_as_list的配置参数有:column和:scope
1) :column默认名为position
2) :scope后的参数为symbol时,如果没有_id则加上_id后缀
class TodoList < ActiveRecord::Base has_many :todo_items, :order => "position" end class TodoItem < ActiveRecord::Base belongs_to :todo_list acts_as_list :scope => :todo_list end
这样生成的scope_condition为"todo_list_id = #{todo_list_id}"
3) :scope后的参数为string时可以进行细粒度的限制
class TodoList < ActiveRecord::Base has_many :todo_items, :order => "position" end class TodoItem < ActiveRecord::Base belongs_to :todo_list acts_as_list :scope => 'todo_list_id = #{todo_list_id} AND completed = 0' end
4) 实例方法很多,简单看看即可,不一一介绍了
3,nested_set.rb
module ActiveRecord module Acts module NestedSet def self.included(base) base.extend(ClassMethods) end module ClassMethods def acts_as_nested_set(options = {}) configuration = { :parent_column => "parent_id", :left_column => "lft", :right_column => "rgt", :scope => "1 = 1" } configuration.update(options) if options.is_a?(Hash) configuration[:scope] = "#{configuration[:scope]}_id".intern if configuration[:scope].is_a?(Symbol) && configuration[:scope].to_s !~ /_id$/ if configuration[:scope].is_a?(Symbol) scope_condition_method = %( def scope_condition if #{configuration[:scope].to_s}.nil? "#{configuration[:scope].to_s} IS NULL" else "#{configuration[:scope].to_s} = \#{#{configuration[:scope].to_s}}" end end ) else scope_condition_method = "def scope_condition() \"#{configuration[:scope]}\" end" end class_eval <<-EOV include ActiveRecord::Acts::NestedSet::InstanceMethods #{scope_condition_method} def left_col_name() "#{configuration[:left_column]}" end def right_col_name() "#{configuration[:right_column]}" end def parent_column() "#{configuration[:parent_column]}" end EOV end end module InstanceMethods def root? parent_id = self[parent_column] (parent_id == 0 || parent_id.nil?) && (self[left_col_name] == 1) && (self[right_col_name] > self[left_col_name]) end def child? parent_id = self[parent_column] !(parent_id == 0 || parent_id.nil?) && (self[left_col_name] > 1) && (self[right_col_name] > self[left_col_name]) end def unknown? !root? && !child? end def add_child( child ) self.reload child.reload if child.root? raise "Adding sub-tree isn\'t currently supported" else if ( (self[left_col_name] == nil) || (self[right_col_name] == nil) ) self[left_col_name] = 1 self[right_col_name] = 4 return nil unless self.save child[parent_column] = self.id child[left_col_name] = 2 child[right_col_name]= 3 return child.save else child[parent_column] = self.id right_bound = self[right_col_name] child[left_col_name] = right_bound child[right_col_name] = right_bound + 1 self[right_col_name] += 2 self.class.base_class.transaction { self.class.base_class.update_all( "#{left_col_name} = (#{left_col_name} + 2)", "#{scope_condition} AND #{left_col_name} >= #{right_bound}" ) self.class.base_class.update_all( "#{right_col_name} = (#{right_col_name} + 2)", "#{scope_condition} AND #{right_col_name} >= #{right_bound}" ) self.save child.save } end end end def children_count return (self[right_col_name] - self[left_col_name] - 1)/2 end def full_set self.class.base_class.find(:all, :conditions => "#{scope_condition} AND (#{left_col_name} BETWEEN #{self[left_col_name]} and #{self[right_col_name]})" ) end def all_children self.class.base_class.find(:all, :conditions => "#{scope_condition} AND (#{left_col_name} > #{self[left_col_name]}) and (#{right_col_name} < #{self[right_col_name]})" ) end def direct_children self.class.base_class.find(:all, :conditions => "#{scope_condition} and #{parent_column} = #{self.id}") end def before_destroy return if self[right_col_name].nil? || self[left_col_name].nil? dif = self[right_col_name] - self[left_col_name] + 1 self.class.base_class.transaction { self.class.base_class.delete_all( "#{scope_condition} and #{left_col_name} > #{self[left_col_name]} and #{right_col_name} < #{self[right_col_name]}" ) self.class.base_class.update_all( "#{left_col_name} = (#{left_col_name} - #{dif})", "#{scope_condition} AND #{left_col_name} >= #{self[right_col_name]}" ) self.class.base_class.update_all( "#{right_col_name} = (#{right_col_name} - #{dif} )", "#{scope_condition} AND #{right_col_name} >= #{self[right_col_name]}" ) } end end end end end
我们可以得到如下几点:
1) acts_as_nested_set和acts_as_tree很类似,但是多一个特性是可以一条语句查询出所有的children
def all_children self.class.base_class.find(:all, :conditions => "#{scope_condition} AND (#{left_col_name} > #{self[left_col_name]}) and (#{right_col_name} < #{self[right_col_name]})" ) end
以及高效率的计算children_count
def children_count return (self[right_col_name] - self[left_col_name] - 1)/2 end
2) acts_as_nested_set的参数为:parent_column、:left_column、:right_column和:scope
3) 这种数据结构常用在threaded post system等场景
看了上述代码,相信大家可以自己动手写acts_as_xx数据结构了
BTW:对ActiveRecord源码的研究告一段落,还有query_cache/observer/xml_serialization/timestamp/calculations/migration等留待大家自己研究
接下来看看ActionController吧
评论
4 楼
blackanger
2007-06-24
rails2.0什么时候发布呢?有说日期吗?
3 楼
hideto
2007-06-24
migration的核心方法:
DHH在RailsConf2007上介绍Rails 2.0的Speech中的形容的是“Sexy Migrations”:
或者更cool的
再也不用
def migrate(direction) return unless respond_to?(direction) case direction when :up then announce "migrating" when :down then announce "reverting" end result = nil time = Benchmark.measure { result = send("real_#{direction}") } case direction when :up then announce "migrated (%.4fs)" % time.real; write when :down then announce "reverted (%.4fs)" % time.real; write end result end
DHH在RailsConf2007上介绍Rails 2.0的Speech中的形容的是“Sexy Migrations”:
create_table :people do |t| t.account_id :type => :integer end
或者更cool的
create_table :people do |t| t.integer :account_id end
再也不用
create_table :people do |t| t.column :account_id, :integer end
2 楼
netfishx
2007-06-23
migration还是很有意思的
1 楼
hideto
2007-06-22
javaeye的表情替代符号真是让人伤心
发表评论
-
用了TextMate才知道什么叫神级Editor
2011-03-09 04:51 57909一直用Eclipse作为开发Ruby和Java项目的IDE,但 ... -
Ruby使用OAuth登录新浪微博和豆瓣
2011-01-09 12:49 4344首先需要安装oauth这个gem包 gem install ... -
使用Passenger+nginx部署Rails
2010-12-28 15:12 49701. Install Passender gem instal ... -
markItUp+rdiscount搭建Rails下可视化Markdown编辑器
2010-12-21 17:48 5404markItUp是基于jQuery的可视化编辑器,支持Html ... -
Rails3 and MongoDB Quick Guide
2010-12-10 14:13 2743Install MongoDB Download: http: ... -
基于ruby-protobuf的rpc示例
2009-08-11 11:51 41351, 安装ruby-protobuf gem instal ... -
Ruby导出xls和csv的utf-8问题的解决
2009-02-04 15:05 6774数据库数据为utf-8格式,包括中文和拉丁文等等 导出文件xl ... -
URL/HTML/JavaScript的encode/escape
2009-01-04 13:03 9268最近经常被URL、HTML、JavaScript的encode ... -
各种排序的Ruby实现
2008-11-27 14:51 3983Θ(n^2) 1, Bubble sort def bu ... -
12月5日北京RoR活动!
2008-11-26 18:38 3008又是一年过去了,Rails在国内的发展势态良好,很多使用RoR ... -
Rails程序开发的最大问题是代码规范
2008-08-28 11:56 5352使用Rails开发大型复杂B2B应用一年了,这个项目目前开发人 ... -
Web开发大全:ROR版——推荐序
2008-07-09 00:39 2404来自http://www.beyondrails.com/bl ... -
深入ActionMailer,使用Sendmail发邮件
2008-07-03 11:41 3390来自: http://www.beyondrails.com/ ... -
Rails里如何结合ExceptionNotification配置gmail账户发邮件
2008-06-19 19:56 30431,安装ExceptionNotification rub ... -
使用coderay和railscasts样式进行代码高亮
2008-06-17 00:16 2384CodeRay是一个语法高亮的Ruby库,效率很不错。 Cod ... -
Capistrano试用
2008-06-16 19:05 19441,客户端机器安装Capistrano gem insta ... -
lighttpd真垃圾啊
2008-06-04 18:38 2483使用lighttpd+fcgi跑Rails程序,文件上传会si ... -
将gem变成plugin
2008-06-04 11:27 1787有什么样的需求就有什么样的对策 当vhost上的帐号没有ge ... -
在Rails里使用ReCaptcha添加验证码
2008-06-03 15:51 42481,去http://recaptcha.net/sign up ... -
Rails里给文件上传添加progress_bar
2008-05-27 17:00 2073文件上传很慢时,UI没有什么用户提示,这样让人很费解,所以我们 ...
相关推荐
RailsAsyncMigrations ActiveRecord::Migration扩展程序以一种简单直接的方式使您的迁移异步。动机创建该库的目的是为了帮助在技术水平上难以扩展的小型公司。 小型项目不需要异步迁移队列,大公司在遇到扩展问题时...
Rails::API 是 Rails 的精简版本,针对不需要使用完整 Rails 功能的开发者。 Rails::API 移除了 ActionView 和其他一些渲染功能,不关心Web前端的开发者可更容易、快速地开发应用程序,因此运行速度比正常的 Rails ...
userstamp, 这个 Rails 插件扩展ActiveRecord Userstamp插件( v-2.0 )概述Userstamp插件扩展了 ActiveRecord::Base,以添加对'创建者','更新程序'和'deleter'属性的自动更新。 它是基于 ActiveRecord::Timesta
rails generate acts_as_aliased:install rake db:migrate 这将创建一个新表aliases 。 用法 假设您有一个需要别名的模型Company ,因为公司名称有不同的版本。 使用acts_as_aliased在模型中启用别名: model ...
数组元素支持对象:ActiveRecord,Mongid,哈希。 在您的Gemfile中: gem 'to_xls-rails' # Last officially released gem # gem "to_xls-rails", :git => "git://github....
Rails::Rack::Logger ActionDispatch::ShowExceptions ActionDispatch::DebugExceptions ActionDispatch::RemoteIp ActionDispatch::Reloader ActionDispatch::Callbacks ActiveRecord::ConnectionAdapters::...
在Ruby on Rails框架中,ActiveRecord是一个至关重要的组件,它负责模型(Model)与数据库之间的交互。本实例将深入探讨ActiveRecord的基本用法,帮助理解如何在实际开发中有效地运用这个强大的工具。 首先,让我们...
现在我们将这个插件从Rails2.x的版本升级到了3.x版本,并且抽取成了一个通用插件,开始应用于新的Rails3.2的项目之上。有志于AR对象缓存优化的ruby程序员不容错过。 使用方法: class User < ActiveRecord::Base ...
#ActsAsCategory acts_as_category (Version 2.0 beta)acts_as_category,是acts_as插件在acts_as_tree风格的Ruby on Rails的ActiveRecord的模式,但有一些额外的功能,以及多种便捷视图助手。例子(有关实例方法和...
没有Rails的ActiveRecord 只是在没有Rails的情况下使用ActiveRecord迁移的简单示例您可以执行的任务: rake db:create rake db:migrate rake db:dropRails 5+的注意事项请注意,即使使用Rails 5,您也需要rake db:...
stateful_enum是建立在ActiveRecord的内置ActiveRecord :: Enum之上的状态机gem。 安装 将此行添加到您的Rails应用程序的Gemfile中: gem 'stateful_enum' 和捆绑。 动机 您不需要抽象 stateful_enum取决于...
Rails 5.2+用法基本: class User extend Enumerize enumerize :sex , in : [ :male , :female ]end 请注意,枚举值仅是标识符,因此,如果要使用多字等值,则应使用I18n功能。 ActiveRecord: class CreateUsers &...
### Ruby on Rails中的ActiveRecord编程指南 #### 一、引言 在Ruby on Rails框架中,ActiveRecord是一种用于实现数据库抽象层的对象关系映射(ORM)工具。它为开发人员提供了一种简单而强大的方式来处理数据库记录...
安装将此行添加到您的应用程序的Gemfile中: gem 'emotions' 然后执行: $ bundle 运行迁移以添加emotions表和Emotion模型: $ rails generate emotions:install用法配置允许的情绪。 Emotions . configure do | ...
这个Rails项目提供了学习和研究Web开发的机会,特别是对于Ruby on Rails新手,可以通过阅读和理解源代码来提升技能,了解实际应用中Rails的用法。同时,对于有经验的开发者,这个项目也可以作为一个起点,进行二次...
Rails 4 定义了ActiveRecord::Base#destroy! 所以Paranoid2 gem 使用force: true arg 来强制销毁。 安装 将此行添加到应用程序的 Gemfile 中: gem 'paranoid2' 然后执行: $ bundle 用法 将deleted_at: ...
在要启用哈希值的ActiveRecord模型中包括Hashid Rails。 class Model < ActiveRecord :: Base include Hashid :: Rails end 继续使用Model#find输入hashid或常规的'ol id。 @person = Person . find ( params...
$ rails generate acts_as_liked 并且不要忘记迁移您的数据库 $ rake db:migrate 用法 可爱的模特 将acts_as_likeable添加到任何模型,它的实例可以被其他模型喜欢。 class Post < ActiveRecord :: Base ...
《Rails Exporter 源码解析》 Rails Exporter 是一个用于 Rails 应用程序的开源工具,主要用于数据导出功能。源码分析将帮助我们深入理解其内部工作原理,以便更好地利用它来优化我们的应用。 一、Rails 框架基础 ...
工作流库的 ActiveRecord/Rails 集成 工作流活动记录的主要+次要版本基于最旧的兼容 ActiveRecord API。 要在 Rails/ActiveRecord 4.1、4.2、5.0、5.1、5.2、6.0、6.1 中使用 ,请使用: gem 'workflow-...