Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions app/models/event.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class Event < ApplicationRecord
scope :upcoming, -> { where(starts_at: Time.current..).order(:starts_at) }
scope :past, -> { where(starts_at: ...Time.current).order(starts_at: :desc) }

validates :title, presence: true
validates :starts_at, presence: true
validate :ends_after_start

private

def ends_after_start
return if ends_at.blank? || starts_at.blank?

errors.add(:ends_at, "must be after the start time") if ends_at <= starts_at
end
end
15 changes: 15 additions & 0 deletions db/migrate/20261013214731_create_events.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class CreateEvents < ActiveRecord::Migration[8.1]
def change
create_table :events do |t|
t.string :title, null: false
t.text :description
t.datetime :starts_at, null: false
t.datetime :ends_at
t.string :location
t.boolean :virtual, null: false, default: false

t.timestamps
end
add_index :events, :starts_at
end
end
14 changes: 13 additions & 1 deletion db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 37 additions & 0 deletions db/seeds.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,40 @@
# ["Action", "Comedy", "Drama", "Horror"].each do |genre_name|
# MovieGenre.find_or_create_by!(name: genre_name)
# end

# Sample events, relative to today so there are always some upcoming ones.
# Named "Event 1", "Event 2", ... and keyed by title so re-running the seeds doesn't create duplicates.
today = Time.current.beginning_of_day

[
{ days: 3, hour: 18, length: 2, location: "Online", virtual: true,
description: "Weekly session working through the Rails guides together. Bring questions." },
{ days: 5, hour: 19, length: 3, location: "The Draughts Café, London", virtual: false,
description: "Casual games night. Beginners welcome, plenty of games provided." },
{ days: 8, hour: 17, length: 1, location: "Online", virtual: true,
description: "A short talk on Turbo and Stimulus, followed by Q&A." },
{ days: 10, hour: 9, length: 1, location: "Hyde Park, London", virtual: false,
description: "5k at your own pace, coffee afterwards." },
{ days: 14, hour: 18, length: 2, location: "Online", virtual: true,
description: "Share something you're working on and get friendly feedback." },
{ days: 21, hour: 10, length: 8, location: "Imperial College, London", virtual: false,
description: "Build something in a weekend. Teams of up to four." },
{ days: 28, hour: 14, length: 3, location: "South Bank, London", virtual: false,
description: "Explore the river with other photographers. Any camera is fine." },
{ days: 35, hour: 11, length: 5, location: "Online", virtual: true,
description: "Pick an issue and make your first contribution, with mentors on hand." },
{ days: -7, hour: 19, length: 2, location: "Student Union Bar", virtual: false,
description: "Kick-off social for new members." },
{ days: -3, hour: 17, length: 2, location: "Online", virtual: true,
description: "Branches, commits and pull requests from scratch." }
].each.with_index(1) do |attrs, i|
starts_at = today + attrs[:days].days + attrs[:hour].hours

Event.find_or_create_by!(title: "Event #{i}") do |event|
event.description = attrs[:description]
event.starts_at = starts_at
event.ends_at = starts_at + attrs[:length].hours
event.location = attrs[:location]
event.virtual = attrs[:virtual]
end
end
23 changes: 23 additions & 0 deletions test/fixtures/events.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html

upcoming_soon:
title: Upcoming soon
description: Starts tomorrow.
starts_at: <%= 1.day.from_now %>
ends_at: <%= 1.day.from_now + 2.hours %>
location: London
virtual: false

upcoming_later:
title: Upcoming later
description: Starts next week.
starts_at: <%= 1.week.from_now %>
virtual: true

past:
title: Already happened
description: Was last week.
starts_at: <%= 1.week.ago %>
ends_at: <%= 1.week.ago + 1.hour %>
location: Manchester
virtual: false
33 changes: 33 additions & 0 deletions test/models/event_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
require "test_helper"

class EventTest < ActiveSupport::TestCase
test "valid with title and starts_at" do
assert Event.new(title: "Meetup", starts_at: 1.day.from_now).valid?
end

test "requires title and starts_at" do
event = Event.new
assert_not event.valid?
assert event.errors.of_kind?(:title, :blank)
assert event.errors.of_kind?(:starts_at, :blank)
end

test "ends_at must be after starts_at" do
start = 1.day.from_now
assert_not Event.new(title: "Meetup", starts_at: start, ends_at: start).valid?
assert_not Event.new(title: "Meetup", starts_at: start, ends_at: start - 1.hour).valid?
assert Event.new(title: "Meetup", starts_at: start, ends_at: start + 1.hour).valid?
end

test "virtual defaults to false" do
assert_equal false, Event.new.virtual
end

test "upcoming returns future events soonest first" do
assert_equal [ events(:upcoming_soon), events(:upcoming_later) ], Event.upcoming.to_a
end

test "past returns past events most recent first" do
assert_equal [ events(:past) ], Event.past.to_a
end
end
Loading