working on recipient_schedule relationships

pull/1/head
Jared Cosulich 9 years ago
parent b0e65da944
commit 64996c422a

1
.gitignore vendored

@ -19,3 +19,4 @@
# Ignore Byebug command history file. # Ignore Byebug command history file.
.byebug_history .byebug_history
config/local_env.yml

@ -7,7 +7,6 @@ class Attempt < ApplicationRecord
belongs_to :recipient_schedule belongs_to :recipient_schedule
belongs_to :question belongs_to :question
def send_message def send_message
twilio_number = ENV['TWILIO_NUMBER'] twilio_number = ENV['TWILIO_NUMBER']
client = Twilio::REST::Client.new ENV['TWILIO_ACCOUNT_SID'], ENV['TWILIO_AUTH_TOKEN'] client = Twilio::REST::Client.new ENV['TWILIO_ACCOUNT_SID'], ENV['TWILIO_AUTH_TOKEN']

@ -1,6 +1,7 @@
class RecipientList < ApplicationRecord class RecipientList < ApplicationRecord
belongs_to :school belongs_to :school
validates_associated :school
validates :name, presence: true validates :name, presence: true
validates :recipient_ids, presence: true validates :recipient_ids, presence: true

@ -4,7 +4,11 @@ class RecipientSchedule < ApplicationRecord
belongs_to :schedule belongs_to :schedule
has_many :attempts has_many :attempts
validates_associated :recipient
validates_associated :schedule
scope :ready, -> { where('next_attempt_at <= ?', Time.new) } scope :ready, -> { where('next_attempt_at <= ?', Time.new) }
scope :for, -> (recipient) { where(recipient_id: recipient.id) }
def next_question def next_question
upcoming = upcoming_question_ids.split(/,/) upcoming = upcoming_question_ids.split(/,/)
@ -19,8 +23,9 @@ class RecipientSchedule < ApplicationRecord
) )
if attempt.send_message if attempt.send_message
return if upcoming_question_ids.blank?
upcoming = upcoming_question_ids.split(/,/)[1..-1].join(',') upcoming = upcoming_question_ids.split(/,/)[1..-1].join(',')
attempted = (attempted_question_ids.split(/,/) + [question.id]).join(',') attempted = ((attempted_question_ids.try(:split, /,/) || []) + [question.id]).join(',')
update_attributes( update_attributes(
upcoming_question_ids: upcoming, upcoming_question_ids: upcoming,
attempted_question_ids: attempted, attempted_question_ids: attempted,

@ -8,6 +8,22 @@ class Schedule < ApplicationRecord
validates :recipient_list, presence: true validates :recipient_list, presence: true
validates :question_list, presence: true validates :question_list, presence: true
after_create :create_recipient_schedules
scope :active, -> { where(active: true).where("start_date <= ? and end_date > ?", Date.today, Date.today) } scope :active, -> { where(active: true).where("start_date <= ? and end_date > ?", Date.today, Date.today) }
private
def create_recipient_schedules
recipient_list.recipients.each do |recipient|
question_ids = question_list.question_ids.split(/,/)
question_ids = question_ids.shuffle if random
recipient_schedules.create(
recipient: recipient,
upcoming_question_ids: question_ids.join(','),
next_attempt_at: Time.new
)
end
end
end end

@ -7,10 +7,10 @@
%ul %ul
- question_list.errors.full_messages.each do |message| - question_list.errors.full_messages.each do |message|
%li= message %li= message
.field .form-group
= f.label :name = f.label :name
= f.text_field :name, class: 'form-control' = f.text_field :name, class: 'form-control'
.field .form-group
= f.label :description = f.label :description
= f.text_area :description, class: 'form-control' = f.text_area :description, class: 'form-control'
.form-group .form-group

@ -1,4 +1,12 @@
Rails.application.configure do Rails.application.configure do
config.before_configuration do
env_file = File.join(Rails.root, 'config', 'local_env.yml')
YAML.load(File.open(env_file)).each do |key, value|
ENV[key.to_s] = value
end if File.exists?(env_file)
end
# Settings specified here will take precedence over those in config/application.rb. # Settings specified here will take precedence over those in config/application.rb.
# In the development environment your application's code is reloaded on # In the development environment your application's code is reloaded on

@ -20,9 +20,17 @@ require 'rails_helper'
RSpec.describe SchedulesController, type: :controller do RSpec.describe SchedulesController, type: :controller do
let(:school) { School.create!(name: 'School') } let!(:school) { School.create!(name: 'School') }
let(:recipient_list) { RecipientList.create!(name: 'Parents', recipient_id_array: [1, 2, 3]) }
let(:question_list) { QuestionList.create!(name: 'Parents Questions', question_id_array: [1, 2, 3]) } let!(:recipients) { create_recipients(school, 3) }
let!(:recipient_list) do
school.recipient_lists.create!(name: 'Parents', recipient_ids: recipients.map(&:id).join(','))
end
let!(:questions) { create_questions(3) }
let!(:question_list) do
QuestionList.create!(name: 'Parent Questions', question_ids: questions.map(&:id).join(','))
end
# This should return the minimal set of attributes required to create a valid # This should return the minimal set of attributes required to create a valid
# Schedule. As you add validations to Schedule, be sure to # Schedule. As you add validations to Schedule, be sure to

@ -3,7 +3,7 @@ require 'rails_helper'
describe "survey:attempt_qustions" do describe "survey:attempt_qustions" do
include_context "rake" include_context "rake"
let(:ready_recipient_schedule) { double('ready recipient schedule', attempt_question: nil) } let(:ready_recipient_schedule) { double('ready recipient schedule', attempt_question: nil) }
let(:recipient_schedules) { double("recipient schedules", ready: [ready_recipient_schedule]) } let(:recipient_schedules) { double("recipient schedules", ready: [ready_recipient_schedule]) }
let(:active_schedule) { double("active schedule", recipient_schedules: recipient_schedules) } let(:active_schedule) { double("active schedule", recipient_schedules: recipient_schedules) }

@ -2,11 +2,17 @@ require 'rails_helper'
RSpec.describe Attempt, type: :model do RSpec.describe Attempt, type: :model do
let(:question) { Question.create!(text: 'What is the question?', option1: 'A', option2: 'B', option3: 'C', option4: 'D', option5: 'E')} let!(:school) { School.create!(name: 'School') }
let(:question_list) { QuestionList.create(name: 'Parent Questions', question_ids: "#{question.id},2,3")}
let(:recipient) { Recipient.create!(name: 'Parent', phone: '1112223333') } let!(:recipient) { create_recipients(school, 1).first }
let(:recipient_list) { RecipientList.create(name: 'Parent List', recipient_ids: recipient.id.to_s)} let!(:recipient_list) do
school.recipient_lists.create!(name: 'Parents', recipient_ids: "#{recipient.id}")
end
let!(:question) { create_questions(1).first }
let!(:question_list) do
QuestionList.create!(name: 'Parent Questions', question_ids: "#{question.id}")
end
let(:schedule) { Schedule.create!(name: 'Parent Schedule', recipient_list_id: recipient_list.id, question_list: question_list) } let(:schedule) { Schedule.create!(name: 'Parent Schedule', recipient_list_id: recipient_list.id, question_list: question_list) }

@ -1,8 +1,7 @@
require 'rails_helper' require 'rails_helper'
describe Recipient do describe RecipientList do
describe "Save" do describe "Save" do
it "should convert the recipient_id_array into the recipient_ids attribute" do it "should convert the recipient_id_array into the recipient_ids attribute" do
recipient_list = RecipientList.create(name: 'Name', recipient_id_array: ['', '1', '2', '3']) recipient_list = RecipientList.create(name: 'Name', recipient_id_array: ['', '1', '2', '3'])
expect(recipient_list).to be_a(RecipientList) expect(recipient_list).to be_a(RecipientList)
@ -12,6 +11,11 @@ describe Recipient do
recipient_list.update(recipient_id_array: ['3', '', '4', '5', '6']) recipient_list.update(recipient_id_array: ['3', '', '4', '5', '6'])
expect(recipient_list.reload.recipient_ids).to eq('3,4,5,6') expect(recipient_list.reload.recipient_ids).to eq('3,4,5,6')
end end
end
describe "when edited" do
it 'should delete recipient_schedules if a recipient is removed'
it 'should create recipient_schedules if a recipient is added'
end end
end end

@ -2,37 +2,34 @@ require 'rails_helper'
RSpec.describe RecipientSchedule, type: :model do RSpec.describe RecipientSchedule, type: :model do
let(:question) { Question.create!(text: 'What is the question?', option1: 'A', option2: 'B', option3: 'C', option4: 'D', option5: 'E')} let!(:school) { School.create!(name: 'School') }
let(:question_list) { QuestionList.create(name: 'Parent Questions', question_ids: "#{question.id},2,3")}
let(:recipient) { Recipient.create!(name: 'Parent', phone: '1112223333') } let!(:recipient) { create_recipients(school, 1).first }
let(:recipient_list) { RecipientList.create(name: 'Parent List', recipient_ids: recipient.id.to_s)} let!(:recipient_list) do
school.recipient_lists.create!(name: 'Parents', recipient_ids: "#{recipient.id}")
end
let!(:questions) { create_questions(3) }
let!(:question_list) do
QuestionList.create!(name: 'Parent Questions', question_ids: questions.map(&:id).join(','))
end
let(:schedule) do let!(:schedule) do
Schedule.create!( Schedule.create!(
name: 'Parent Schedule', name: 'Parent Schedule',
recipient_list_id: recipient_list.id, recipient_list_id: recipient_list.id,
question_list: question_list, question_list: question_list,
random: false,
frequency_hours: 24 * 7 frequency_hours: 24 * 7
) )
end end
let!(:recipient_schedule) { schedule.recipient_schedules.for(recipient).first }
let!(:recipient_schedule) do
RecipientSchedule.create!(
recipient: recipient,
schedule: schedule,
upcoming_question_ids: "#{question.id},3",
attempted_question_ids: '2',
last_attempt_at: 2.weeks.ago,
next_attempt_at: 2.weeks.ago + (60 * 60 * schedule.frequency_hours)
)
end
let!(:not_ready_recipient_schedule) do let!(:not_ready_recipient_schedule) do
RecipientSchedule.create!( RecipientSchedule.create!(
recipient: recipient, recipient: recipient,
schedule: schedule, schedule: schedule,
upcoming_question_ids: "#{question.id},3", upcoming_question_ids: '1,3',
attempted_question_ids: '2', attempted_question_ids: '2',
last_attempt_at: 1.day.ago, last_attempt_at: 1.day.ago,
next_attempt_at: 1.day.ago + (60 * 60 * schedule.frequency_hours) next_attempt_at: 1.day.ago + (60 * 60 * schedule.frequency_hours)
@ -50,7 +47,7 @@ RSpec.describe RecipientSchedule, type: :model do
describe 'next_question' do describe 'next_question' do
it 'should provide the next question from the upcoming_question_ids list' do it 'should provide the next question from the upcoming_question_ids list' do
expect(recipient_schedule.next_question).to eq(question) expect(recipient_schedule.next_question).to eq(questions.first)
end end
end end
@ -66,17 +63,17 @@ RSpec.describe RecipientSchedule, type: :model do
expect(attempt.recipient).to eq(recipient) expect(attempt.recipient).to eq(recipient)
expect(attempt.schedule).to eq(schedule) expect(attempt.schedule).to eq(schedule)
expect(attempt.recipient_schedule).to eq(recipient_schedule) expect(attempt.recipient_schedule).to eq(recipient_schedule)
expect(attempt.question).to eq(question) expect(attempt.question).to eq(questions.first)
expect(attempt.sent_at.to_i).to eq(Time.new.to_i) expect(attempt.sent_at.to_i).to eq(Time.new.to_i)
expect(attempt.answer_index).to be_nil expect(attempt.answer_index).to be_nil
end end
it 'should update the upcoming_questions_ids' do it 'should update the upcoming_questions_ids' do
expect(recipient_schedule.upcoming_question_ids).to eq('3') expect(recipient_schedule.upcoming_question_ids).to eq(questions[1..2].map(&:id).join(','))
end end
it 'should update the attempted_question_ids' do it 'should update the attempted_question_ids' do
expect(recipient_schedule.attempted_question_ids).to eq("2,#{question.id}") expect(recipient_schedule.attempted_question_ids).to eq(questions.first.id.to_s)
end end
it 'should update last_attempt_at' do it 'should update last_attempt_at' do

@ -2,7 +2,6 @@ require 'rails_helper'
describe Recipient do describe Recipient do
describe "Import" do describe "Import" do
let(:school) { School.create!(name: 'School') } let(:school) { School.create!(name: 'School') }
let(:data) { "name,phone\rJared,111-222-333\rLauren,222-333-4444\rAbby,333-444-5555\r" } let(:data) { "name,phone\rJared,111-222-333\rLauren,222-333-4444\rAbby,333-444-5555\r" }
let(:file) { instance_double('File', path: 'path') } let(:file) { instance_double('File', path: 'path') }
@ -15,4 +14,8 @@ describe Recipient do
expect(Recipient.all.map(&:school).uniq).to eq([school]) expect(Recipient.all.map(&:school).uniq).to eq([school])
end end
end end
describe "When Deleted" do
it 'should delete all recipient_schedules'
end
end end

@ -2,46 +2,61 @@ require 'rails_helper'
describe Schedule do describe Schedule do
describe "active" do let!(:school) { School.create!(name: 'School') }
let!(:school) { School.create!(name: 'School') } let!(:recipients) { create_recipients(school, 3) }
let!(:recipient_list) { RecipientList.create!(name: 'Parents', recipient_id_array: [1, 2, 3]) } let!(:recipient_list) do
let!(:kids_recipient_list) { RecipientList.create!(name: 'Kids', recipient_id_array: [4, 5, 6]) } school.recipient_lists.create!(name: 'Parents', recipient_ids: recipients.map(&:id).join(','))
let!(:question_list) { QuestionList.create!(name: 'Questions', question_id_array: [1, 2, 3]) } end
let(:default_schedule_params) {
{
school: school,
recipient_list: recipient_list,
question_list: question_list,
name: 'Parents Schedule',
description: 'Schedule for parent questions',
start_date: 1.month.ago,
end_date: 11.months.from_now,
active: true
}
}
let!(:active_schedule) do let!(:kid_recipients) { create_recipients(school, 3) }
Schedule.create!(default_schedule_params) let!(:kids_recipient_list) do
end school.recipient_lists.create!(name: 'Kids', recipient_ids: kid_recipients.map(&:id).join(','))
end
let!(:active_schedule_kids) do let!(:questions) { create_questions(3) }
Schedule.create!(default_schedule_params.merge!(name: 'Kids Schedule', recipient_list: kids_recipient_list)) let!(:question_list) do
end QuestionList.create!(name: 'Questions', question_ids: questions.map(&:id).join(','))
end
let!(:old_schedule) { let(:default_schedule_params) {
Schedule.create!(default_schedule_params.merge!(start_date: 13.month.ago, end_date: 1.months.ago)) {
school: school,
recipient_list: recipient_list,
question_list: question_list,
name: 'Parents Schedule',
description: 'Schedule for parent questions',
start_date: 1.month.ago,
end_date: 11.months.from_now,
active: true
} }
}
let!(:paused_schedule) { let!(:active_schedule) do
Schedule.create!(default_schedule_params.merge!(active: false)) Schedule.create!(default_schedule_params)
} end
let!(:active_schedule_kids) do
Schedule.create!(default_schedule_params.merge!(name: 'Kids Schedule', recipient_list: kids_recipient_list))
end
let!(:old_schedule) {
Schedule.create!(default_schedule_params.merge!(start_date: 13.month.ago, end_date: 1.months.ago))
}
let!(:paused_schedule) {
Schedule.create!(default_schedule_params.merge!(active: false))
}
describe "active" do
it 'finds active schedules' do it 'finds active schedules' do
active = Schedule.active active = Schedule.active
expect(active.length).to eq(2) expect(active.length).to eq(2)
end end
end
it 'creates a recipient_schedule for every recipient when created' do
expect(active_schedule.recipient_schedules.length).to eq(3)
end end
end end

@ -121,3 +121,29 @@ class FakeSMS
self.class.messages << Message.new(from, to, body) self.class.messages << Message.new(from, to, body)
end end
end end
def create_recipients(school, count)
recipients = []
count.times do |i|
recipients << school.recipients.create(
name: "Person#{count}",
phone: "#{count}" * 10,
)
end
return recipients
end
def create_questions(count)
questions = []
count.times do |i|
questions << Question.create(
text: "Question #{i}:#{count}",
option1: "Option #{i}:#{count} A",
option2: "Option #{i}:#{count} B",
option3: "Option #{i}:#{count} C",
option4: "Option #{i}:#{count} D",
option5: "Option #{i}:#{count} E"
)
end
return questions
end

Loading…
Cancel
Save