Retrieving Multiple Objects in Batches
find_each
User.find_each(:batch_size => 5000) do |user| NewsLetter.weekly_deliver(user) end
User.find_each(:batch_size => 5000, :start => 2000) do |user| NewsLetter.weekly_deliver(user) end
:start option allows you to configure the first ID of the sequence if the lowest is not the one you need.
find_each accepts the same options as the regularfind method. However,
:order and :limit are needed internally and hence not allowed to be passed explicitly.
Conditions
Client.where("orders_count = ?", params[:orders])
instead of
Client.where("orders_count = #{params[:orders]}")
because of SQL injection
Client.where(:created_at => (params[:start_date].to_date)..(params[:end_date].to_date))
Hash Conditions
Subset Conditions
Client.where(:orders_count => [1,3,5])
Ordering
Client.order("orders_count ASC, created_at DESC")
Selecting Specific Fields
Client.select("viewable_by, locked")
Be careful because this also means you’re initializing a model object with only the fields that you’ve selected. If you attempt to access a field that is not in the initialized record you’ll receive:
ActiveRecord::MissingAttributeError: missing attribute: <attribute>
Client.select("DISTINCT(name)")
Pessimistic Locking
Item.transaction do i = Item.lock.first i.name = 'Jones' i.save end
Item.transaction
do
i
= Item.lock(
"LOCK
IN SHARE MODE"
).find(
1
)
i.increment!(
:views
)
end
Joining Tables
Client.joins('LEFT OUTER JOIN addresses ON addresses.client_id = clients.id')
Joining a Single Association
Category.joins(:posts)
SELECT categories.* FROM categories INNER JOIN posts ON posts.category_id = categories.id
Joining Multiple Associations
Post.joins(:category, :comments)
SELECT posts.* FROM posts INNER JOIN categories ON posts.category_id = categories.id INNER JOIN comments ON comments.post_id = posts.id
Joining Nested Associations (Single Level)
Post.joins(:comments => :guest)
Joining Nested Associations (Multiple Level)
Category.joins(:posts => [{:comments => :guest}, :tags])
Specifying Conditions on the Joined Tables
time_range = (Time.now.midnight - 1.day)..Time.now.midnight Client.joins(:orders).where('orders.created_at' => time_range)
time_range = (Time.now.midnight - 1.day)..Time.now.midnight Client.joins(:orders).where(:orders => {:created_at => time_range})
Eager Loading Associations
Active Record lets you specify in advance all the associations that are going to be loaded. This is possible by specifying the includes method
of the Model.find call.
With includes,
Active Record ensures that all of the specified associations are loaded using the minimum possible number of queries.
clients = Client.includes(:address).limit(10) clients.each do |client| puts client.address.postcode end
SELECT * FROM clients LIMIT 10 SELECT addresses.* FROM addresses WHERE (addresses.client_id IN (1,2,3,4,5,6,7,8,9,10))
Eager Loading Multiple Associations
Post.includes(:category, :comments)
Category.includes(:posts => [{:comments => :guest}, :tags]).find(1)
Dynamic Finders
For every field (also known as an attribute) you define in your table, Active Record provides a finder method. If you have a field called first_name on
your Client model
for example, you getfind_by_first_name and find_all_by_first_name for
free from Active Record. If you have also have a locked field
on the Client model,
you also get find_by_locked andfind_all_by_locked
If you want to find both by name and locked, you can chain these finders together by simply typingand between
the fields for example Client.find_by_first_name_and_locked("Ryan",
true)
There’s
another set of dynamic finders that let you find or create/initialize objects if they aren’t found.
Finding by SQL
Client.find_by_sql("SELECT * FROM clients INNER JOIN orders ON clients.id = orders.client_id ORDER clients.created_at desc")
find_by_sql has
a close relative called connection#select_all. select_all will
retrieve objects from the database using custom SQL just
like find_by_sql but
will not instantiate them. Instead, you will get an array of hashes where each hash indicates a record.
Existence of Objects
Client.exists?(1)
Client.exists?(1,2,3) # or Client.exists?([1,2,3])
Client.where(:first_name => 'Ryan').exists?
Client.exists?
Calculations
If you want to be more specific and find all the clients with their age present in the database you can use Client.count(:age).
Client.average("orders_count")
minimum maximun sum