提交 f033833f 编写于 作者: D David Heinemeier Hansson

Improving documentation...

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@191 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
上级 6860db61
......@@ -166,12 +166,8 @@
* Added option to establish_connection where you'll be able to leave out the parameter to have it use the RAILS_ENV environment variable
* Added ADO-based SQLServerAdapter (only works on Windows) [Joey Gibson]
* Fixed problems with primary keys and postgresql sequences (#230) [Tim Bates]
* Fixed problems with nested transactions (#231) [Tim Bates]
* Added reloading for associations under cached environments like FastCGI and mod_ruby. This makes it possible to use those environments for development.
This is turned on by default, but can be turned off with ActiveRecord::Base.reload_dependencies = false in production environments.
......
module ActiveRecord
# Mixins are a way of decorating existing Active Record models with additional behavior. If you for example
# want to keep a number of Documents in order, you can include Mixins::List, and all of the sudden be able to
# call <tt>document.move_to_bottom</tt>.
module Acts
# This mixin provides the capabilities for sorting and reordering a number of objects in list.
# The class that has this mixin included needs to have a "position" column defined as an integer on
# the mapped database table. Further more, you need to implement the <tt>scope_condition</tt> if you want
# to separate one list from another.
#
# Todo list example:
#
# class TodoList < ActiveRecord::Base
# has_many :todo_items, :order => "position"
# end
#
# class TodoItem < ActiveRecord::Base
# include ActiveRecord::Mixins::List
# belongs_to :todo_list
#
# private
# def scope_condition
# "todo_list_id = #{todo_list_id}"
# end
# end
#
# todo_list.first.move_to_bottom
# todo_list.last.move_higher
module List
module Acts #:nodoc:
module List #:nodoc:
def self.append_features(base)
super
base.extend(ClassMethods)
end
# This act provides the capabilities for sorting and reordering a number of objects in list.
# The class that has this specified needs to have a "position" column defined as an integer on
# the mapped database table.
#
# Todo list example:
#
# 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
#
# todo_list.first.move_to_bottom
# todo_list.last.move_higher
module ClassMethods
# Configuration options are:
#
# * +column+ - specifies the column name to use for keeping the position integer (default: position)
# * +scope+ - restricts what is to be considered a list. Given a symbol, it'll attach "_id" (if that hasn't been already) and use that
# as the foreign key restriction. It's also possible to give it an entire string that is interpolated if you need a tighter scope than
# just a foreign key. Example: <tt>acts_as_list :scope => 'todo_list_id = #{todo_list_id} AND completed = 0'</tt>
def acts_as_list(options = {})
configuration = { :column => "position", :scope => "1" }
configuration.update(options) if options.is_a?(Hash)
......@@ -40,7 +37,7 @@ def acts_as_list(options = {})
configuration[:scope] = "#{configuration[:scope]}_id".intern if configuration[:scope].is_a?(Symbol) && configuration[:scope].to_s !~ /_id$/
class_eval <<-EOV
include InstanceMethods
include ActiveRecord::Acts::List::InstanceMethods
def position_column
'#{configuration[:column]}'
......@@ -54,132 +51,127 @@ def scope_condition
after_create :add_to_list_bottom
EOV
end
end
module InstanceMethods
def move_lower
return unless lower_item
self.class.transaction do
lower_item.decrement_position
increment_position
end
# All the methods available to a record that has had <tt>acts_as_list</tt> specified.
module InstanceMethods
def move_lower
return unless lower_item
self.class.transaction do
lower_item.decrement_position
increment_position
end
end
def move_higher
return unless higher_item
def move_higher
return unless higher_item
self.class.transaction do
higher_item.increment_position
decrement_position
end
self.class.transaction do
higher_item.increment_position
decrement_position
end
def move_to_bottom
self.class.transaction do
decrement_positions_on_lower_items
assume_bottom_position
end
end
def move_to_bottom
self.class.transaction do
decrement_positions_on_lower_items
assume_bottom_position
end
end
def move_to_top
self.class.transaction do
increment_positions_on_higher_items
assume_top_position
end
def move_to_top
self.class.transaction do
increment_positions_on_higher_items
assume_top_position
end
end
# Entering or existing the list
def add_to_list_top
increment_positions_on_all_items
end
def add_to_list_top
increment_positions_on_all_items
end
def add_to_list_bottom
assume_bottom_position
end
def add_to_list_bottom
assume_bottom_position
end
def remove_from_list
decrement_positions_on_lower_items
end
def remove_from_list
decrement_positions_on_lower_items
end
# Changing the position
def increment_position
update_attribute position_column, self.send(position_column).to_i + 1
end
def decrement_position
update_attribute position_column, self.send(position_column).to_i - 1
end
def first?
self.send(position_column) == 1
end
def last?
self.send(position_column) == bottom_position_in_list
end
def increment_position
update_attribute position_column, self.send(position_column).to_i + 1
private
# Overwrite this method to define the scope of the list changes
def scope_condition() "1" end
def higher_item
self.class.find_first(
"#{scope_condition} AND #{position_column} = #{(send(position_column).to_i - 1).to_s}"
)
end
def decrement_position
update_attribute position_column, self.send(position_column).to_i - 1
def lower_item
self.class.find_first(
"#{scope_condition} AND #{position_column} = #{(send(position_column).to_i + 1).to_s}"
)
end
# Querying the position
def first?
self.send(position_column) == 1
def bottom_position_in_list
item = bottom_item
item ? item.send(position_column) : 0
end
def last?
self.send(position_column) == bottom_position_in_list
def bottom_item
self.class.find_first(
"#{scope_condition} ",
"#{position_column} DESC"
)
end
private
# Overwrite this method to define the scope of the list changes
def scope_condition() "1" end
def higher_item
self.class.find_first(
"#{scope_condition} AND #{position_column} = #{(send(position_column).to_i - 1).to_s}"
)
end
def assume_bottom_position
update_attribute position_column, bottom_position_in_list.to_i + 1
end
def lower_item
self.class.find_first(
"#{scope_condition} AND #{position_column} = #{(send(position_column).to_i + 1).to_s}"
)
end
def assume_top_position
update_attribute position_column, 1
end
def bottom_position_in_list
item = bottom_item
item ? item.send(position_column) : 0
end
def decrement_positions_on_lower_items
self.class.update_all(
"#{position_column} = (#{position_column} - 1)", "#{scope_condition} AND #{position_column} > #{send(position_column).to_i}"
)
end
def bottom_item
self.class.find_first(
"#{scope_condition} ",
"#{position_column} DESC"
)
end
def assume_bottom_position
update_attribute position_column, bottom_position_in_list.to_i + 1
end
def assume_top_position
update_attribute position_column, 1
end
def decrement_positions_on_lower_items
self.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
self.class.update_all(
"#{position_column} = (#{position_column} + 1)", "#{scope_condition} AND #{position_column} < #{send(position_column)}"
)
end
def increment_positions_on_higher_items
self.class.update_all(
"#{position_column} = (#{position_column} + 1)", "#{scope_condition} AND #{position_column} < #{send(position_column)}"
)
end
def increment_positions_on_all_items
self.class.update_all(
"#{position_column} = (#{position_column} + 1)", "#{scope_condition}"
)
end
end
end
def increment_positions_on_all_items
self.class.update_all(
"#{position_column} = (#{position_column} + 1)", "#{scope_condition}"
)
end
end
end
end
end
\ No newline at end of file
module ActiveRecord
module Mixins
# Including this mixins will record when objects of the class are created in a datetime column called "created_at"
# and when its updated in another datetime column called "updated_at".
#
# class Bill < ActiveRecord::Base
# include ActiveRecord::Mixins::Touch
# end
#
# bill = Bill.create("amount" => 100)
# bill.created_at # => Time.now at the moment of Bill.create
# bill.updated_at # => Time.now at the moment of Bill.create
#
# bill.update_attribute("amount", 150)
# bill.created_at # => Time.now at the moment of Bill.create
# bill.updated_at # => Time.now at the moment of bill.update_attribute
module Touch
def self.append_features(base)
super
base.before_create :touch_on_create
base.before_update :touch_on_update
end
def touch_on_create
self.updated_at = (self.created_at ||= Time.now)
end
def touch_on_update
self.updated_at = Time.now
end
end
end
end
\ No newline at end of file
module ActiveRecord
module Acts
# Including this mixin if you want to model a tree structure by providing a parent association and an children
# association. This mixin assumes that you have a column called parent_id
#
# class Category < ActiveRecord::Base
# include ActiveRecord::Mixins::Tree
# end
#
# Example :
# root
# \_ child1
# \_ sub-child1
#
# root = Category.create("name" => "root")
# child1 = root.children.create("name" => "child1")
# subchild1 = child1.children.create("name" => "subchild1")
#
# root.parent # => nil
# child1.parent # => root
# root.children # => [child1]
# root.children.first.children.first # => subchild1
module Tree
module Acts #:nodoc:
module Tree #:nodoc:
def self.append_features(base)
super
base.extend(ClassMethods)
end
end
module ClassMethods
def acts_as_tree(options = {})
configuration = { :foreign_key => "parent_id", :order => nil }
configuration.update(options) if options.is_a?(Hash)
belongs_to :parent, :class_name => name, :foreign_key => configuration[:foreign_key]
has_many :children, :class_name => name, :foreign_key => configuration[:foreign_key], :order => configuration[:order], :dependent => true
# Specify this act if you want to model a tree structure by providing a parent association and an children
# association. This act assumes that requires that you have a foreign key column, which by default is called parent_id.
#
# class Category < ActiveRecord::Base
# acts_as_tree :order => "name"
# end
#
# Example :
# root
# \_ child1
# \_ sub-child1
#
# root = Category.create("name" => "root")
# child1 = root.children.create("name" => "child1")
# subchild1 = child1.children.create("name" => "subchild1")
#
# root.parent # => nil
# child1.parent # => root
# root.children # => [child1]
# root.children.first.children.first # => subchild1
module ClassMethods
# Configuration options are:
#
# * <tt>foreign_key</tt> - specifies the column name to use for track of the tree (default: parent_id)
# * <tt>order</tt> - makes it possible to sort the children according to this SQL snippet.
def acts_as_tree(options = {})
configuration = { :foreign_key => "parent_id", :order => nil }
configuration.update(options) if options.is_a?(Hash)
belongs_to :parent, :class_name => name, :foreign_key => configuration[:foreign_key]
has_many :children, :class_name => name, :foreign_key => configuration[:foreign_key], :order => configuration[:order], :dependent => true
end
end
end
end
......
......@@ -130,6 +130,9 @@ class PreparedStatementInvalid < ActiveRecordError #:nodoc:
# When you do Firm.create("name" => "37signals"), this record with be saved in the companies table with type = "Firm". You can then
# fetch this row again using Company.find_first "name = '37signals'" and it will return a Firm object.
#
# If you don't have a type column defined in your table, single-table inheritance won't be triggered. In that case, it'll work just
# like normal subclasses with no special magic for differentiating between them or reloading the right type with find.
#
# Note, all the attributes for all the cases are kept in the same table. Read more:
# http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
#
......
......@@ -92,7 +92,7 @@ def attributes_with_quotes
end
module ConnectionAdapters
class ColumnWithIdentity < Column
class ColumnWithIdentity < Column# :nodoc:
attr_reader :identity
def initialize(name, default, sql_type = nil, is_identity = false)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册