twilio-rails 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +0 -0
- data/LICENSE +21 -0
- data/README.md +413 -0
- data/Rakefile +8 -0
- data/app/assets/config/twilio_rails_manifest.js +1 -0
- data/app/assets/stylesheets/twilio/rails/application.css +15 -0
- data/app/controllers/twilio/rails/application_controller.rb +6 -0
- data/app/controllers/twilio/rails/phone_controller.rb +112 -0
- data/app/controllers/twilio/rails/sms_controller.rb +64 -0
- data/app/helpers/twilio/rails/application_helper.rb +6 -0
- data/app/jobs/twilio/rails/application_job.rb +6 -0
- data/app/jobs/twilio/rails/phone/attach_recording_job.rb +15 -0
- data/app/jobs/twilio/rails/phone/finished_call_job.rb +15 -0
- data/app/jobs/twilio/rails/phone/unanswered_call_job.rb +15 -0
- data/app/mailers/twilio/rails/application_mailer.rb +8 -0
- data/app/models/twilio/rails/application_record.rb +7 -0
- data/app/operations/twilio/rails/application_operation.rb +21 -0
- data/app/operations/twilio/rails/find_or_create_phone_caller_operation.rb +29 -0
- data/app/operations/twilio/rails/phone/attach_recording_operation.rb +31 -0
- data/app/operations/twilio/rails/phone/base_operation.rb +21 -0
- data/app/operations/twilio/rails/phone/create_operation.rb +49 -0
- data/app/operations/twilio/rails/phone/find_operation.rb +14 -0
- data/app/operations/twilio/rails/phone/finished_call_operation.rb +17 -0
- data/app/operations/twilio/rails/phone/receive_recording_operation.rb +35 -0
- data/app/operations/twilio/rails/phone/start_call_operation.rb +53 -0
- data/app/operations/twilio/rails/phone/twiml/after_operation.rb +37 -0
- data/app/operations/twilio/rails/phone/twiml/base_operation.rb +50 -0
- data/app/operations/twilio/rails/phone/twiml/error_operation.rb +22 -0
- data/app/operations/twilio/rails/phone/twiml/greeting_operation.rb +22 -0
- data/app/operations/twilio/rails/phone/twiml/prompt_operation.rb +109 -0
- data/app/operations/twilio/rails/phone/twiml/prompt_response_operation.rb +29 -0
- data/app/operations/twilio/rails/phone/twiml/request_validation_failure_operation.rb +16 -0
- data/app/operations/twilio/rails/phone/twiml/timeout_operation.rb +48 -0
- data/app/operations/twilio/rails/phone/unanswered_call_operation.rb +22 -0
- data/app/operations/twilio/rails/phone/update_operation.rb +26 -0
- data/app/operations/twilio/rails/phone/update_response_operation.rb +38 -0
- data/app/operations/twilio/rails/sms/base_operation.rb +17 -0
- data/app/operations/twilio/rails/sms/create_operation.rb +23 -0
- data/app/operations/twilio/rails/sms/find_message_operation.rb +15 -0
- data/app/operations/twilio/rails/sms/find_operation.rb +15 -0
- data/app/operations/twilio/rails/sms/send_operation.rb +102 -0
- data/app/operations/twilio/rails/sms/twiml/base_operation.rb +11 -0
- data/app/operations/twilio/rails/sms/twiml/error_operation.rb +15 -0
- data/app/operations/twilio/rails/sms/twiml/message_operation.rb +49 -0
- data/app/operations/twilio/rails/sms/update_message_operation.rb +27 -0
- data/app/views/layouts/twilio/rails/application.html.erb +15 -0
- data/config/routes.rb +16 -0
- data/lib/generators/twilio/rails/install/USAGE +15 -0
- data/lib/generators/twilio/rails/install/install_generator.rb +34 -0
- data/lib/generators/twilio/rails/install/templates/initializer.rb +83 -0
- data/lib/generators/twilio/rails/install/templates/message.rb +4 -0
- data/lib/generators/twilio/rails/install/templates/migration.rb +89 -0
- data/lib/generators/twilio/rails/install/templates/phone_call.rb +4 -0
- data/lib/generators/twilio/rails/install/templates/phone_caller.rb +4 -0
- data/lib/generators/twilio/rails/install/templates/recording.rb +4 -0
- data/lib/generators/twilio/rails/install/templates/response.rb +4 -0
- data/lib/generators/twilio/rails/install/templates/sms_conversation.rb +4 -0
- data/lib/generators/twilio/rails/phone_tree/USAGE +8 -0
- data/lib/generators/twilio/rails/phone_tree/phone_tree_generator.rb +12 -0
- data/lib/generators/twilio/rails/phone_tree/templates/tree.rb.erb +13 -0
- data/lib/generators/twilio/rails/sms_responder/USAGE +8 -0
- data/lib/generators/twilio/rails/sms_responder/sms_responder_generator.rb +12 -0
- data/lib/generators/twilio/rails/sms_responder/templates/responder.rb.erb +10 -0
- data/lib/tasks/rails_tasks.rake +45 -0
- data/lib/twilio/rails/client.rb +75 -0
- data/lib/twilio/rails/concerns/has_direction.rb +25 -0
- data/lib/twilio/rails/concerns/has_phone_number.rb +27 -0
- data/lib/twilio/rails/concerns/has_time_scopes.rb +19 -0
- data/lib/twilio/rails/configuration.rb +380 -0
- data/lib/twilio/rails/engine.rb +11 -0
- data/lib/twilio/rails/formatter.rb +93 -0
- data/lib/twilio/rails/models/message.rb +21 -0
- data/lib/twilio/rails/models/phone_call.rb +132 -0
- data/lib/twilio/rails/models/phone_caller.rb +100 -0
- data/lib/twilio/rails/models/recording.rb +27 -0
- data/lib/twilio/rails/models/response.rb +153 -0
- data/lib/twilio/rails/models/sms_conversation.rb +29 -0
- data/lib/twilio/rails/phone/base_tree.rb +229 -0
- data/lib/twilio/rails/phone/tree.rb +229 -0
- data/lib/twilio/rails/phone/tree_macros.rb +147 -0
- data/lib/twilio/rails/phone.rb +12 -0
- data/lib/twilio/rails/phone_number.rb +29 -0
- data/lib/twilio/rails/railtie.rb +17 -0
- data/lib/twilio/rails/sms/delegated_responder.rb +97 -0
- data/lib/twilio/rails/sms/responder.rb +33 -0
- data/lib/twilio/rails/sms.rb +12 -0
- data/lib/twilio/rails/version.rb +5 -0
- data/lib/twilio/rails.rb +89 -0
- metadata +289 -0
@@ -0,0 +1,89 @@
|
|
1
|
+
class InstallTwilioRails < ActiveRecord::Migration[7.0]
|
2
|
+
def change
|
3
|
+
create_table "messages", force: :cascade do |t|
|
4
|
+
t.bigint "sms_conversation_id", null: false
|
5
|
+
t.string "sid"
|
6
|
+
t.text "body"
|
7
|
+
t.string "status"
|
8
|
+
t.string "direction"
|
9
|
+
t.datetime "created_at", null: false
|
10
|
+
t.datetime "updated_at", null: false
|
11
|
+
t.index ["created_at"], name: "index_messages_on_created_at"
|
12
|
+
t.index ["direction"], name: "index_messages_on_direction"
|
13
|
+
t.index ["sms_conversation_id"], name: "index_messages_on_sms_conversation_id"
|
14
|
+
end
|
15
|
+
|
16
|
+
create_table "phone_callers", force: :cascade do |t|
|
17
|
+
t.string "phone_number"
|
18
|
+
t.datetime "created_at", null: false
|
19
|
+
t.datetime "updated_at", null: false
|
20
|
+
t.index ["phone_number"], name: "index_phone_callers_on_phone_number"
|
21
|
+
end
|
22
|
+
|
23
|
+
create_table "phone_calls", force: :cascade do |t|
|
24
|
+
t.integer "phone_caller_id"
|
25
|
+
t.string "sid"
|
26
|
+
t.string "number"
|
27
|
+
t.string "from_number"
|
28
|
+
t.string "from_city"
|
29
|
+
t.string "from_province"
|
30
|
+
t.string "from_country"
|
31
|
+
t.string "tree_name"
|
32
|
+
t.string "direction"
|
33
|
+
t.string "answered_by"
|
34
|
+
t.boolean "unanswered", default: false
|
35
|
+
t.boolean "finished", default: false
|
36
|
+
t.string "call_status"
|
37
|
+
t.integer "length_seconds"
|
38
|
+
t.datetime "created_at", null: false
|
39
|
+
t.datetime "updated_at", null: false
|
40
|
+
t.index ["created_at"], name: "index_phone_calls_on_created_at"
|
41
|
+
t.index ["direction"], name: "index_phone_calls_on_direction"
|
42
|
+
t.index ["phone_caller_id"], name: "index_phone_calls_on_phone_caller_id"
|
43
|
+
t.index ["sid"], name: "index_calls_on_sid"
|
44
|
+
t.index ["tree_name"], name: "index_phone_calls_on_tree_name"
|
45
|
+
end
|
46
|
+
|
47
|
+
create_table "recordings", force: :cascade do |t|
|
48
|
+
t.bigint "phone_call_id", null: false
|
49
|
+
t.string "recording_sid"
|
50
|
+
t.string "duration"
|
51
|
+
t.string "url"
|
52
|
+
t.datetime "created_at", null: false
|
53
|
+
t.datetime "updated_at", null: false
|
54
|
+
t.index ["phone_call_id"], name: "index_recordings_on_call_id"
|
55
|
+
end
|
56
|
+
|
57
|
+
create_table "responses", force: :cascade do |t|
|
58
|
+
t.bigint "phone_call_id"
|
59
|
+
t.bigint "recording_id"
|
60
|
+
t.string "prompt_handle"
|
61
|
+
t.string "digits"
|
62
|
+
t.text "transcription"
|
63
|
+
t.boolean "transcribed", default: false
|
64
|
+
t.boolean "timeout", default: false
|
65
|
+
t.datetime "created_at", null: false
|
66
|
+
t.datetime "updated_at", null: false
|
67
|
+
t.index ["created_at"], name: "index_responses_on_created_at"
|
68
|
+
t.index ["digits"], name: "index_responses_on_digits"
|
69
|
+
t.index ["phone_call_id", "prompt_handle"], name: "index_responses_on_phone_call_id_and_prompt_handle"
|
70
|
+
t.index ["prompt_handle"], name: "index_responses_on_prompt_handle"
|
71
|
+
t.index ["recording_id"], name: "index_responses_on_recording_id"
|
72
|
+
t.index ["timeout"], name: "index_responses_on_timeout"
|
73
|
+
t.index ["transcribed"], name: "index_responses_on_transcribed"
|
74
|
+
end
|
75
|
+
|
76
|
+
create_table "sms_conversations", force: :cascade do |t|
|
77
|
+
t.string "number"
|
78
|
+
t.string "from_number"
|
79
|
+
t.string "from_city"
|
80
|
+
t.string "from_province"
|
81
|
+
t.string "from_country"
|
82
|
+
t.datetime "created_at", null: false
|
83
|
+
t.datetime "updated_at", null: false
|
84
|
+
t.index ["created_at"], name: "index_sms_conversations_on_created_at"
|
85
|
+
t.index ["from_number"], name: "index_sms_conversations_on_from_number"
|
86
|
+
t.index ["number"], name: "index_sms_conversations_on_number"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class Twilio::Rails::PhoneTreeGenerator < Rails::Generators::NamedBase
|
3
|
+
source_root File.expand_path("templates", __dir__)
|
4
|
+
|
5
|
+
def copy_template_tree
|
6
|
+
template "tree.rb.erb", "app/phone_trees/#{file_name}_tree.rb"
|
7
|
+
end
|
8
|
+
|
9
|
+
def register_tree
|
10
|
+
insert_into_file "config/initializers/twilio_rails.rb", "\n config.phone_trees.register { #{class_name}Tree }", before: "\nend\n"
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class <%= class_name %>Tree < Twilio::Rails::Phone::BaseTree
|
3
|
+
# voice "male"
|
4
|
+
# final_timeout_message("Goodbye.")
|
5
|
+
# invalid_phone_number("Sorry, we cannot accept your call.")
|
6
|
+
|
7
|
+
greeting message: "Hello!",
|
8
|
+
prompt: :thanks_and_hangup
|
9
|
+
|
10
|
+
prompt :thanks_and_hangup,
|
11
|
+
message: "Thank you for calling!",
|
12
|
+
after: { hangup: true }
|
13
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class Twilio::Rails::SmsResponderGenerator < Rails::Generators::NamedBase
|
3
|
+
source_root File.expand_path("templates", __dir__)
|
4
|
+
|
5
|
+
def copy_template_responder
|
6
|
+
template "responder.rb.erb", "app/sms_responders/#{file_name}_responder.rb"
|
7
|
+
end
|
8
|
+
|
9
|
+
def register_responder
|
10
|
+
insert_into_file "config/initializers/twilio_rails.rb", "\n config.sms_responders.register { #{class_name}Responder }", before: "\nend\n"
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class <%= class_name %>Responder < Twilio::Rails::SMS::DelegatedResponder
|
3
|
+
def handle?
|
4
|
+
raise NotImplementedError, "Implement #{ self.class }#handle?"
|
5
|
+
end
|
6
|
+
|
7
|
+
def reply
|
8
|
+
raise NotImplementedError, "Implement #{ self.class }#reply"
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
namespace :twilio do
|
3
|
+
namespace :rails do
|
4
|
+
desc "Show the available values to config in Twilio"
|
5
|
+
task config: :environment do
|
6
|
+
if Twilio::Rails.config.host.blank?
|
7
|
+
puts "Twilio::Rails.config.host is not set. Set it in the `config/initializers/twilio_rails.rb` file."
|
8
|
+
elsif Twilio::Rails.config.host == "https://example.com"
|
9
|
+
puts "Twilio::Rails.config.host is set to a test value. Set it in the `config/initializers/twilio_rails.rb` file."
|
10
|
+
else
|
11
|
+
http_methods = if Twilio::Rails.config.controller_http_methods.length == 1
|
12
|
+
"HTTP #{ Twilio::Rails.config.controller_http_methods.first.to_s.upcase }"
|
13
|
+
else
|
14
|
+
"HTTP POST or HTTP GET"
|
15
|
+
end
|
16
|
+
|
17
|
+
puts "Log into the Twilio web console: https://console.twilio.com"
|
18
|
+
puts "Navigate to Phone Numbers -> Manage -> Active Numbers and find the phone number #{Twilio::Rails.config.default_outgoing_phone_number}."
|
19
|
+
puts ""
|
20
|
+
|
21
|
+
if Twilio::Rails.config.phone_trees.all.length == 0
|
22
|
+
puts "You cannot yet configure `Voice & Fax' because There are no phone trees registered in this application."
|
23
|
+
puts "Register them in the `config/initializers/twilio_rails.rb` file if you want to handle phone calls, and run this task again to help configure Twilio."
|
24
|
+
else
|
25
|
+
puts "Under 'Voice & Fax' set 'A CALL COMES IN' to 'Webhook' with #{ http_methods } and one of the following URLs:"
|
26
|
+
Twilio::Rails.config.phone_trees.all.each do |name, tree|
|
27
|
+
puts " #{tree.inbound_url}"
|
28
|
+
end
|
29
|
+
puts ""
|
30
|
+
puts "Under 'Voice & Fax' set 'CALL STATUS CHANGES' to following URL:"
|
31
|
+
puts " #{ ::Twilio::Rails.config.host }#{ ::Twilio::Rails::Engine.routes.url_helpers.phone_status_path(format: :xml) }"
|
32
|
+
end
|
33
|
+
|
34
|
+
puts ""
|
35
|
+
puts "Under 'Messaging' set 'A MESSAGE COMES IN' to 'Webhook' with #{ http_methods } and the following URL:"
|
36
|
+
puts " #{ ::Twilio::Rails.config.host }#{ ::Twilio::Rails::Engine.routes.url_helpers.sms_message_path(format: :xml) }"
|
37
|
+
|
38
|
+
if Twilio::Rails.config.sms_responders.all.length == 0
|
39
|
+
puts "There are no SMS responders registered so they will not be handled."
|
40
|
+
puts "Register them in the `config/initializers/twilio_rails.rb` file if you want to handle SMS messages."
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Twilio
|
3
|
+
module Rails
|
4
|
+
# An abstraction over top of the `Twilio::REST` API client. Used to send SMS messages and start calls, as well as
|
5
|
+
# return an initialized client if needed.
|
6
|
+
module Client
|
7
|
+
extend self
|
8
|
+
|
9
|
+
# @return [Twilio::REST::Client] Twilio client initialized with `account_sid` and `auth_token` from the config.
|
10
|
+
def client
|
11
|
+
@twilio_client ||= Twilio::REST::Client.new(
|
12
|
+
Twilio::Rails.config.account_sid,
|
13
|
+
Twilio::Rails.config.auth_token,
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Do not call this directly, instead see {Twilio::Rails::SMS::SendOperation}. Send an SMS message to and from the
|
18
|
+
# given phone numbers using the Twilio REST API directly. This does not store or manage any interactions in the
|
19
|
+
# database.
|
20
|
+
#
|
21
|
+
# @param message [String] the message to send.
|
22
|
+
# @param to [String] the phone number to send the message to.
|
23
|
+
# @param from [String] the phone number to send the message from.
|
24
|
+
# @return [String] the SID returned from Twilio for the sent SMS message.
|
25
|
+
def send_message(message:, to:, from:)
|
26
|
+
Twilio::Rails.config.logger.tagged(self) { |l| l.info("[send_message] to=#{ to } from=#{ from } body='#{ message }'") }
|
27
|
+
client.messages.create(
|
28
|
+
from: from,
|
29
|
+
to: to,
|
30
|
+
body: message,
|
31
|
+
status_callback: "#{ Twilio::Rails.config.host }#{ ::Twilio::Rails::Engine.routes.url_helpers.sms_status_path(format: :xml) }",
|
32
|
+
).sid
|
33
|
+
end
|
34
|
+
|
35
|
+
# Do not call this directly, instead see {Twilio::Rails::SMS::SendOperation}. Sends multiple SMS messages to and
|
36
|
+
# from the given phone numbers using the Twilio REST API directly. This does not store or manage any interactions
|
37
|
+
# in the database. If a message is blank it will be ignored.
|
38
|
+
#
|
39
|
+
# @param messages [Array<String>] the messages to send.
|
40
|
+
# @param to [String] the phone number to send the messages to.
|
41
|
+
# @param from [String] the phone number to send the messages from.
|
42
|
+
# @return [Array<String>] the SIDs returned from Twilio for the sent SMS messages.
|
43
|
+
def send_messages(messages:, to:, from:)
|
44
|
+
Twilio::Rails.config.logger.tagged(self) { |l| l.info("[send_messages] to blank messages") } if messages.blank?
|
45
|
+
messages.map { |m| send_message(message: m, to: to, from: from) }
|
46
|
+
end
|
47
|
+
|
48
|
+
# Do not call this directly, instead see {Twilio::Rails::Phone::StartCallOperation}. Starts a phone call to and
|
49
|
+
# from the given phone numbers using the Twilio REST API directly. This does not store or manage any interactions
|
50
|
+
# in the database. The URL should come from the {Twilio::Rails::Phone::Tree} that is being used to start the call.
|
51
|
+
#
|
52
|
+
# @param url [String] the URL to use for the Twilio REST API call, probably from the {Twilio::Rails::Phone::Tree}.
|
53
|
+
# @param to [String] the phone number to make the call to.
|
54
|
+
# @param from [String] the phone number to make the call from.
|
55
|
+
# @param answering_machine_detection [true, false] whether or not to enable answering machine detection.
|
56
|
+
# @return [String] the SID returned from Twilio for the started call.
|
57
|
+
def start_call(url:, to:, from:, answering_machine_detection: true)
|
58
|
+
Twilio::Rails.config.logger.tagged(self) { |l| l.info("[start_call] to=#{ to } from=#{ from } url=#{ url } answering_machine_detection=#{ !!answering_machine_detection }") }
|
59
|
+
client.calls.create(
|
60
|
+
from: from,
|
61
|
+
to: to,
|
62
|
+
url: url,
|
63
|
+
machine_detection: ( answering_machine_detection ? "Enable" : "Disable" ),
|
64
|
+
async_amd: true,
|
65
|
+
async_amd_status_callback: "#{ Twilio::Rails.config.host }#{ ::Twilio::Rails::Engine.routes.url_helpers.phone_status_path(format: :xml, async_amd: "true") }",
|
66
|
+
async_amd_status_callback_method: "POST",
|
67
|
+
status_callback: "#{ Twilio::Rails.config.host }#{ ::Twilio::Rails::Engine.routes.url_helpers.phone_status_path(format: :xml) }",
|
68
|
+
status_callback_method: "POST",
|
69
|
+
status_callback_event: ["completed", "no-answer"],
|
70
|
+
# timeout: 30,
|
71
|
+
).sid
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Twilio
|
3
|
+
module Rails
|
4
|
+
# Provides scopes, validations, and convenience methods for a model that has an attribute `direction` with
|
5
|
+
# values "inbound" or "outbound".
|
6
|
+
module HasDirection
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
validates :direction, inclusion: { in: ["outbound", "inbound"] }
|
11
|
+
|
12
|
+
scope :outbound, -> { where(direction: "outbound") }
|
13
|
+
scope :inbound, -> { where(direction: "inbound") }
|
14
|
+
end
|
15
|
+
|
16
|
+
def inbound?
|
17
|
+
direction == "inbound"
|
18
|
+
end
|
19
|
+
|
20
|
+
def outbound?
|
21
|
+
direction == "outbound"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Twilio
|
3
|
+
module Rails
|
4
|
+
# Provides validations and reformatting on validation for a model that has an attribute `phone_number` that is
|
5
|
+
# that is unique and that matches {Twilio::Rails::Formatter.coerce_to_valid_phone_number}.
|
6
|
+
module HasPhoneNumber
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
validates :phone_number, uniqueness: { allow_blank: true, message: "already exists" }
|
11
|
+
|
12
|
+
before_validation :reformat_phone_number
|
13
|
+
end
|
14
|
+
|
15
|
+
def reformat_phone_number
|
16
|
+
current = Twilio::Rails::Formatter.coerce_to_valid_phone_number(phone_number)
|
17
|
+
self.phone_number = current if current
|
18
|
+
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
def valid_north_american_phone_number?
|
23
|
+
Twilio::Rails::Formatter.valid_north_american_phone_number?(phone_number)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Twilio
|
3
|
+
module Rails
|
4
|
+
# Provides convenience scopes for a model that has a `created_at` attribute.
|
5
|
+
module HasTimeScopes
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
scope :in_last, ->(time) { where(created_at: (Time.now - time)..(Time.now)) }
|
10
|
+
scope :in_previous, ->(time) { where(created_at: (Time.now - time - time)..(Time.now - time)) }
|
11
|
+
|
12
|
+
scope :in_last_24_hours, -> { in_last(1.day) }
|
13
|
+
scope :in_last_2_days, -> { in_last(2.days) }
|
14
|
+
scope :in_last_4_hours, -> { in_last(4.hours) }
|
15
|
+
scope :in_previous_24_hours, -> { in_previous(1.day) }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|