Upload
-
View
125
Download
1
Embed Size (px)
Citation preview
ActiveRecord
module ActiveRecord #:nodoc: class << self # Class methods delegate :find, :first, :first!, :last, :last!, :all, :exists?, :any?, :many?, :to => :scoped delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, :to => :scoped delegate :find_each, :find_in_batches, :to => :scoped delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :where, :preload, :eager_load, :includes, :from, :lock, :readonly, :having, :create_with, :to => :scoped delegate :count, :average, :minimum, :maximum, :sum, :calculate, :to => :scoped endend
Scoped
def scoped(options = nil) if options scoped.apply_finder_options(options) else if current_scope current_scope.clone else scope = relation.clone scope.default_scoped = true scope end end end
Finder methods
• where
• having
• select
• order
• limit
• offset
All finder methods work through AR::Relation
• joins
• includes
• lock
• readonly
• from
Example. Where
def where(opts, *rest) return self if opts.blank?
relation = clone relation.where_values += build_where(opts, rest) relationend
ActiveRecord::Relation
def to_a @records = if @readonly_value.nil? && [email protected]_enabled? eager_loading? ? find_with_associations : @klass.find_by_sql(arel.to_sql, @bind_values) else IdentityMap.without do eager_loading? ? find_with_associations : @klass.find_by_sql(arel.to_sql, @bind_values) end endend
Real quering from the AR::Relation
AR::Relation problems
• merging default_scope’s with labmda (solved):
default_scope where(:name => "qwerty")default_scope lambda { order("id DESC") }
• except (I’ve wrote a patch):
scope :xxx, order("id DESC")scope :yyy, except(:order).order("id ASC")
@surveys = Survey.xxx.yyy
Survey Load (0.1ms) SELECT "surveys".* FROM "surveys" ORDER BY id DESC, id ASC
Without IdentityMap
user1 = User.find(1) # => #<User id: 1, name: "Josh">user2 = User.find(1) # => #<User id: 1, name: "Josh">
user1 == user2 # => true, b/c AR::Base recognizes that # they have the same primary key
user1.object_id == user2.object_id # => false, b/c these are two # different in-memory objects
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
Code example from: http://edgerails.info/articles/what-s-new-in-edge-rails/2011/04/21/activerecord-identity-map/index.html
With IdentityMap
user1 = User.find(1) # => #<User id: 1, name: "Josh">user2 = User.find(1) # => #<User id: 1, name: "Josh">
user1 == user2 # => true
user1.object_id == user2.object_id # => true, b/c these really are # the same in-memory objects
User Load (2.2ms) SELECT "users".* FROM "users" LIMIT 1User with ID = 1 loaded from Identity Map
Code example from: http://edgerails.info/articles/what-s-new-in-edge-rails/2011/04/21/activerecord-identity-map/index.html
Even more...
post = Post.find(1)
same_post = post.comments.first.post
post.object_id == same_post.object_id # => true
Code example from: http://miloops.com/post/3391477665/identity-map-and-active-record
Thread safe
• Creates for each request
• Uses Thread.current
def repository Thread.current[:identity_map] ||= Hash.new { |h,k| h[k] = {} }end
Interesting...def update @survey = Survey.find(params[:id]) @surveys = Survey.all
if @survey.update_attributes(params[:survey]) redirect_to(@survey, :notice => 'Survey was successfully updated.') else render :action => "edit" end end
def update @survey = Survey.find(params[:id])
if @survey.update_attributes(params[:survey]) redirect_to(@survey, :notice => 'Survey was successfully updated.') else @surveys = Survey.all
render :action => "edit" endend
How to use IdentityMap
• It will be in Rails 3.1
• To enable write in your application.rb:
config.active_record.identity_map = true