You are currently browsing the tag archive for the ‘ActiveRecord’ tag.

When fetching all associations with includes they are not cached, but could be, since they are still the same records(unlike with :select/:conditions etc)

user = User.first
user.comments.length # hits db
user.comments.length # cached

user = User.first
user.commens.all(:include=>:comenter).length  # hits db
user.commens.all(:include=>:comenter).length  # hits db
user.comments.length # hits db

Cached find all with includes
This can save requests when performing repetitive calls to the same record.

user = User.first
user.comments.load_target_with_includes([:commenter, :tags]).length # hits db
user.comments.load_target_with_includes([:commenter, :tags]).length # cached
user.comments.length # cached

Code

# do not load an association twice, when all we need are includes
# all(:include=>xxx) would always reload the target
class ActiveRecord::Associations::AssociationCollection
  def load_target_with_includes(includes)
    raise if @owner.new_record?

    if loaded?
      @target
    else
      @loaded = true
      @target = all(:include => includes)
    end
  end
end

Sometimes big updates that affect millions of rows kill our database (all queries hang/are blocked).
Therefore we built a simple solution:

class ActiveRecord::Base
  def self.slow_update_all(set, where, options={})
    ids_to_update = find_values(:select => :id, :conditions => where)
    ids_to_update.each_slice(10_000) do |slice|
      update_all(set, :id => slice)
      sleep options[:sleep] if options[:sleep]
    end
    ids_to_update.size
  end
end


This needs ActiveRecord find_values extension

A simple and readable alternative to update_all({:x=>y}, :id=>id)

Usage

User.update_one(id, :name=>'Pete')

Code

clas ActiveRecord::Base
  def self.update_one(id, attributes)
    update_all(attributes, :id => id)
  end
end

ActiveRecord`s validate_uniqueness_of produces evil SQL that will not use your existing index!

Before:
SELECT `users`.id FROM `users` WHERE `users`.`email` = BINARY ‘my@email.com’ AND `users`.id 1234) LIMIT 1; –> 0.80s

After:
SELECT `users`.id FROM `users` WHERE `users`.`email` = ‘my@email.com’ AND `users`.id 1234) LIMIT 1; –> 0.00s

Hack to make AR use faster queries on the cost that no case-sensitive queries can be made anymore.

# validates_uniqueness_of produces "column = BINARY 'text'" queries
# which will not use existing indices, so we add this
# EVIL HACK to make
# ALL validates_uniqueness_of in-case-sensitive
class ActiveRecord::ConnectionAdapters::MysqlAdapter
  def case_sensitive_equality_operator
    "="
  end
end

When updating to 2.3.4 I noticed that touch is
no longer a simple ‘update :updated_at’, but a save!,
which caused some code to break
(e.g. touch`ing in after_save == loop)

Usage

User.first.touch_without_callbacks
User.touch_without_callbacks([User.first.id, User.last.id])

Install
Paste somewhere…

# Provide .touch as it was in 2.3.2, simply update the :updated_at field.
class ActiveRecord::Base
  def touch_without_callbacks
    now = Time.now.utc
    self.class.touch(id, now)
    self.updated_at = now
  end

  def self.touch_without_callbacks(ids, time=Time.now.utc)
    update_all({:updated_at=>time}, :id=>ids)
  end
end
Follow

Get every new post delivered to your Inbox.

Join 63 other followers