Created
September 13, 2012 14:59
-
-
Save sw17ch/3714877 to your computer and use it in GitHub Desktop.
Use ActiveRecord to select records where a field is equal to the greatest value found for that field when limited by a set of columns.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# A file demonstrating how I use ActiveRecord to perform "All records where N | |
# is greatest N" queries. | |
# | |
# This script contains the schema, the models, and the example code. Normally | |
# these pieces would be broken out into separate files. | |
# | |
# The example demonstrates the use by producing a set of relationships between | |
# users, services, and "logins" of those users to the services. Then, we | |
# perform some queries that relate to the longest session time when stratified | |
# different ways. | |
require 'active_record' | |
### Database Connection and Creation ### | |
def connect_database | |
ActiveRecord::Base.establish_connection( | |
adapter: "sqlite3", | |
database: "a_database.sqlite3" | |
) | |
end | |
def create_database | |
create_tables | |
end | |
def create_tables | |
ActiveRecord::Schema.define do | |
create_table(:users, force: true) do |t| | |
t.column :name, :string | |
end | |
create_table(:services, force: true) do |t| | |
t.column :name, :string | |
end | |
create_table(:logins, force: true) do |t| | |
t.column :session_length, :integer | |
t.column :service_id, :integer | |
t.column :user_id, :integer | |
end | |
end | |
end | |
### Model Creation ### | |
class User < ActiveRecord::Base | |
has_many :logins, dependent: :destroy | |
def to_s; name end | |
end | |
class Service < ActiveRecord::Base | |
has_many :logins | |
def to_s; name end | |
end | |
class Login < ActiveRecord::Base | |
belongs_to :user | |
belongs_to :service | |
# Fetch the row(s) from `logins` where no other row exists with the same | |
# `columns` value(s) and a greater `session_length`. | |
scope :longest_session_for, lambda { |*columns| | |
selectors = columns.map {|c| | |
"logins.\"#{c}\" = ls.\"#{c}\"" | |
}.join (" AND ") | |
joins(%Q{ | |
LEFT OUTER JOIN logins ls ON | |
( | |
logins.session_length < ls.session_length AND | |
#{selectors} | |
) | |
}).where("ls.id IS NULL") | |
} | |
def to_s | |
"LOGIN ID %02d: [ %5s ] to [ %5s ] for [ %02d ]" % [id, user, service, session_length] | |
end | |
end | |
def insert_data | |
john = User.create!(name: "John") | |
alex = User.create!(name: "Alex") | |
mail = Service.create!(name: "Mail") | |
chat = Service.create!(name: "Chat") | |
pony = Service.create!(name: "Pony") | |
Login.create!(service: mail, user: john, session_length: 2) | |
Login.create!(service: mail, user: alex, session_length: 2) | |
Login.create!(service: pony, user: john, session_length: 3) | |
Login.create!(service: chat, user: john, session_length: 4) | |
Login.create!(service: chat, user: alex, session_length: 5) | |
Login.create!(service: mail, user: john, session_length: 5) | |
Login.create!(service: mail, user: alex, session_length: 6) | |
Login.create!(service: pony, user: john, session_length: 7) | |
Login.create!(service: pony, user: john, session_length: 8) | |
Login.create!(service: mail, user: john, session_length: 9) | |
Login.create!(service: mail, user: john, session_length: 9) | |
end | |
def header(title) | |
"===== #{title} =====" | |
end | |
def print_data | |
puts header("All Logins") | |
puts Login.all | |
puts header("Longest Sessions for Each User") | |
puts Login.longest_session_for(:user_id) | |
puts header("Longest Sessions for Each Service") | |
puts Login.longest_session_for(:service_id) | |
puts header("Longest Sessions for Each User on Each Service") | |
puts Login.longest_session_for(:user_id, :service_id) | |
end | |
connect_database() | |
create_database() | |
insert_data() | |
print_data() | |
# The output of this script will look something like this: | |
# ===== All Logins ===== | |
# LOGIN ID 01: [ John ] to [ Mail ] for [ 02 ] | |
# LOGIN ID 02: [ Alex ] to [ Mail ] for [ 02 ] | |
# LOGIN ID 03: [ John ] to [ Pony ] for [ 03 ] | |
# LOGIN ID 04: [ John ] to [ Chat ] for [ 04 ] | |
# LOGIN ID 05: [ Alex ] to [ Chat ] for [ 05 ] | |
# LOGIN ID 06: [ John ] to [ Mail ] for [ 05 ] | |
# LOGIN ID 07: [ Alex ] to [ Mail ] for [ 06 ] | |
# LOGIN ID 08: [ John ] to [ Pony ] for [ 07 ] | |
# LOGIN ID 09: [ John ] to [ Pony ] for [ 08 ] | |
# LOGIN ID 10: [ John ] to [ Mail ] for [ 09 ] | |
# LOGIN ID 11: [ John ] to [ Mail ] for [ 09 ] | |
# ===== Longest Sessions for Each User ===== | |
# LOGIN ID 07: [ Alex ] to [ Mail ] for [ 06 ] | |
# LOGIN ID 10: [ John ] to [ Mail ] for [ 09 ] | |
# LOGIN ID 11: [ John ] to [ Mail ] for [ 09 ] | |
# ===== Longest Sessions for Each Service ===== | |
# LOGIN ID 05: [ Alex ] to [ Chat ] for [ 05 ] | |
# LOGIN ID 09: [ John ] to [ Pony ] for [ 08 ] | |
# LOGIN ID 10: [ John ] to [ Mail ] for [ 09 ] | |
# LOGIN ID 11: [ John ] to [ Mail ] for [ 09 ] | |
# ===== Longest Sessions for Each User on Each Service ===== | |
# LOGIN ID 04: [ John ] to [ Chat ] for [ 04 ] | |
# LOGIN ID 05: [ Alex ] to [ Chat ] for [ 05 ] | |
# LOGIN ID 07: [ Alex ] to [ Mail ] for [ 06 ] | |
# LOGIN ID 09: [ John ] to [ Pony ] for [ 08 ] | |
# LOGIN ID 10: [ John ] to [ Mail ] for [ 09 ] | |
# LOGIN ID 11: [ John ] to [ Mail ] for [ 09 ] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment