DEPRECATED: It's been 8 years now, plase don't use code inspired by this repository in production. Be aware that I was a junior developer when I wrote this :)
This Example App allows its users to subscribe to their advanced searches to receive new search results via email.
Users of this example app can perform and save advanced Searches
on Products
. Than they can subscribe to their preferred (saved) searches in order to receive an email notification when new search results are available for that particular search (like on Yahoo answers).
The basic idea behind user-preferred searches new results is that the Search
model has also the following attributes:
saved:boolean
to save the search to prevent its deletion (since advanced searches are models backed by the DB, theSearch#clear_unsaved
recurring process takes care of deleting the old unsaved ones)notify:boolean
to switch on/off email notification of new resultsnotified_at:timestamp
with the time of its last notification, so thefind_new_results
private method can filter products based on whether they were created or updated after the last notification. SeeSearch#new_results
;new_results_presence:boolean
is a flag set to true whenever new results are found for the Search, only searches with this flag set to true are processed for mail notification purposesnew_results_checked_at:timestamp
holds the time reference of when the new results where found.
And then Search
has also the following class methods:
Search.check_new_results_presence
checks new results presence to be notified only for searches withnotify: true
andnew_results_presence: false
Search.notify_new_results_by_mail
fetches users with searches with new_results to be notified and then, for each of them, it calls the notification mailer (UserMailer#new_search_results_for(user)
)Search.clear_unsaved
deletes unsaved searches from database
Each one of these tree class methods are run periodically by Whenever (see schedule.rb) in background jobs handled by Delayed_job.
Last but not least UserMailer#new_search_results_for(user)
mailer fetches all new search results for every search of the passed user, collect them in a @new_result_sets
hash (in which the searches are the keys and the related new results are the values) and then touches the notified_at
attribute for every search in it. The email template will then use @new_result_sets
to generate the email body.
The most important pieces of code were BDD, so you can get a glance of what they do also reading the following specs:
$ bundle install
$ rails generate delayed_job:active_record
$ rake db:migrate
$ cp config/application.example.yml config/application.yml
$ cp config/database.example.yml config/database.yml
To trigger a new results email notification you must first save a search for a user, then activate the notification for that search and then create or update a matching product.
$ whenever
This will simply show you your schedule.rb
file converted to cron syntax. It does not read or write your crontab file. Run whenever --help
for a complete list of options.
- Run whenever in development mode
$ whenever --set environment=development -w
- See crontab
$ crontab -l
- Clear crontab in development mode
$ whenever --set environment=development -c
- Start background jobs
$ rake jobs:work
- There are no navigation links yet, so you should navigate through resources using the address bar and RESTful actions, see routes.rb
- Searches#index shows only the searches of the current user (this isn't ideal but was the simplest solution)
- There is no authorization logic because isn't needed in an example app
- It relies on PostgreSQL for full-text search.
- This example app is.. well, just an example app, still in development (see DevLog.md), for a real production app you should consider a lot of performance optimization and be ready to scale to a solution based, for instance, on Resque Scheduler which has Redis as an external dependency.
- Furthermore you should consider all the issues related to mass emailing, for instance Gmail is good for up to 200 emails/day (this is the reason for the
max_daily_emails: 200
inapplication.example.yml
). If you need to scale, possible alternatives to Gmail are mailjet, sendgrid, and mailchimp.
- Users development is based on Rails Tutorial by Michael Hartl
- User remember me and reset password based on Railscast #275
- Advanced Searches based on Railscast #111
- Newsletter about new results in user-preferred searches by Duccio Armenise :-).
- Ryan Bates for replying with useful hints to my email and, of course, for running Railscasts.com.
- Leo Correa for his answer on Stackoverflow.