Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a weekly Newsletter for the latest open Bounties #19 #36

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 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
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ gem "pg", "~> 1.1"
# Use the Puma web server [https://github.com/puma/puma]
gem "puma", "~> 5.0"

gem 'whenever', require: false

# Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]
gem "importmap-rails"

Expand Down Expand Up @@ -60,6 +62,8 @@ group :development do
# Use console on exceptions pages [https://github.com/rails/web-console]
gem "web-console"

gem "letter_opener"

# Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler]
# gem "rack-mini-profiler"

Expand Down
10 changes: 10 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ GEM
rack-test (>= 0.6.3)
regexp_parser (>= 1.5, < 3.0)
xpath (~> 3.2)
chronic (0.10.2)
concurrent-ruby (1.2.2)
crass (1.0.6)
date (3.3.3)
Expand All @@ -107,6 +108,10 @@ GEM
jbuilder (2.11.5)
actionview (>= 5.0.0)
activesupport (>= 5.0.0)
launchy (2.5.2)
addressable (~> 2.8)
letter_opener (1.8.1)
launchy (>= 2.2, < 3)
loofah (2.19.1)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
Expand Down Expand Up @@ -228,12 +233,15 @@ GEM
websocket-driver (0.7.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
whenever (1.0.0)
chronic (>= 0.6.3)
xpath (3.2.0)
nokogiri (~> 1.8)
zeitwerk (2.6.7)

PLATFORMS
arm64-darwin-21
x86_64-darwin-19
x86_64-darwin-22
x86_64-linux

Expand All @@ -245,6 +253,7 @@ DEPENDENCIES
image_processing (~> 1.2)
importmap-rails
jbuilder
letter_opener
name_of_person (~> 1.1)
pagy (~> 6.0)
pg (~> 1.1)
Expand All @@ -259,6 +268,7 @@ DEPENDENCIES
tzinfo-data
web-console
webdrivers
whenever

RUBY VERSION
ruby 3.2.1p31
Expand Down
2 changes: 1 addition & 1 deletion app/mailers/application_mailer.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class ApplicationMailer < ActionMailer::Base
default from: "from@example.com"
default from: "no-reply@beginnerbounties.com"
layout "mailer"
end
7 changes: 7 additions & 0 deletions app/mailers/bounty_mailer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class BountyMailer < ApplicationMailer
def open_bounty
@user = params[:user]
@bounties = params[:bounties]
mail(to: @user.email, subject: "Here are the latest open bounties")
end
end
1 change: 1 addition & 0 deletions app/models/bounty.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class Bounty < ApplicationRecord
has_rich_text :description

scope :sorted, -> { in_order_of(:status, STATUSES).order(created_at: :desc) }
scope :open, -> { where(status: "open") }

validates :amount, presence: true, numericality: {greater_than: 0, only_integer: true}
validates :description, presence: true
Expand Down
6 changes: 6 additions & 0 deletions app/views/bounty_mailer/open_bounty.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<p><strong>The open bounties for this week:</strong></p>
<% @bounties.each do |bounty| %>
<h3><%= bounty.title %></h3>
<p>Amount: <%= bounty.amount %>$</p>
<p><%= link_to "View the source code", bounty.url %></p>
<% end %>
6 changes: 6 additions & 0 deletions config/environments/development.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,13 @@
# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = false


config.action_mailer.delivery_method = :letter_opener
config.action_mailer.default_url_options = { host: 'localhost', port: 3000}
config.action_mailer.perform_caching = false
config.action_mailer.perform_deliveries = true

#config.action_mailer.default_options = {from: '[email protected]'}

# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
Expand Down
3 changes: 3 additions & 0 deletions config/schedule.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
every :sunday, at: '17:00 pm' do
rake "send_bounty_email"
end
10 changes: 10 additions & 0 deletions lib/tasks/bounty_tasks.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
desc 'send open bounties email'
task send_bounty_email: :environment do
@bounties = Bounty.open.last(15)
if @bounties.any?
@users = User.all
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @clair13,
I feel this is performance intensive task (although it is rake task but still) as it will load the entire table into memory, instantiating all the rows; then iterate through the instances.

We can use find_each, as it does this in batches, which is more efficient in terms of memory usage.

something like below

User.find_each do |user|
  BountyMailer.with(user: user, bounties: @bounties).open_bounty.deliver_later
end

References
Retrieving Multiple Objects in Batches
ActiveRecord::Batches

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the suggestion,I fixed it based on your suggestion.

@users.each do |user|
BountyMailer.with(user: user, bounties: @bounties).open_bounty.deliver_later
end
end
end
20 changes: 9 additions & 11 deletions test/fixtures/bounties.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html

one:
user: one
title: MyString
url: MyString
amount: MyString
status: MyString
title: First Bounty
url: http://www.google.com/
amount: 10
status: open

two:
user: two
title: MyString
url: MyString
amount: MyString
status: MyString
user: one
title: Second Bounty
url: http://www.firefox.com/
amount: 32
status: assigned
20 changes: 10 additions & 10 deletions test/fixtures/users.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
one:
email: [email protected]
first_name: first
last_name: Last
encrypted_password: foobar

# This model initially had no columns defined. If you add columns to the
# model remove the "{}" from the fixture names and add the columns immediately
# below each fixture, per the syntax in the comments below
#
one: {}
# column: value
#
two: {}
# column: value
two:
email: [email protected]
first_name: second
last_name: Doe
encrypted_password: foo
17 changes: 17 additions & 0 deletions test/mailers/bounty_mailer_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
require "test_helper"

class BountyMailerTest < ActionMailer::TestCase
def setup
@user = users(:one)
@bounties = [bounties(:one)]
end

test "bounty email" do
mail = BountyMailer.with(user: @user, bounties: @bounties).open_bounty
assert_equal "[email protected]", @user.email
assert_equal "Here are the latest open bounties", mail.subject
assert_equal ["[email protected]"], mail.to
assert_equal ["[email protected]"], mail.from
assert_match bounties.first.title, mail.body.encoded
end
end
7 changes: 7 additions & 0 deletions test/mailers/previews/bounty_mailer_preview.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Preview all emails at http://localhost:3000/rails/mailers/bounty_mailer
class BountyMailerPreview < ActionMailer::Preview
def open_bounty
BountyMailer.with(user: User.first,
bounties: Bounty.where(status: "open").last(15)).open_bounty
end
end