diff --git a/Gemfile b/Gemfile index d17d402b..e3eee649 100644 --- a/Gemfile +++ b/Gemfile @@ -63,6 +63,7 @@ group :development do gem 'spring' gem 'spring-watcher-listen', '~> 2.0.0' gem 'seed_dump' + gem 'nested_scaffold' end group 'test' do diff --git a/Gemfile.lock b/Gemfile.lock index a0695444..6d37b29f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -111,6 +111,7 @@ GEM mini_portile2 (2.1.0) minitest (5.10.1) multi_json (1.12.1) + nested_scaffold (1.0.0) newrelic_rpm (3.17.1.326) nio4r (1.2.1) nokogiri (1.6.8) @@ -247,6 +248,7 @@ DEPENDENCIES jquery-ui-rails launchy listen (~> 3.0.5) + nested_scaffold newrelic_rpm omniauth pg diff --git a/app/assets/javascripts/recipient_lists.coffee b/app/assets/javascripts/recipient_lists.coffee new file mode 100644 index 00000000..24f83d18 --- /dev/null +++ b/app/assets/javascripts/recipient_lists.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/stylesheets/recipient_lists.scss b/app/assets/stylesheets/recipient_lists.scss new file mode 100644 index 00000000..d6141781 --- /dev/null +++ b/app/assets/stylesheets/recipient_lists.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the recipient_lists controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/recipient_lists_controller.rb b/app/controllers/recipient_lists_controller.rb new file mode 100644 index 00000000..bc356c67 --- /dev/null +++ b/app/controllers/recipient_lists_controller.rb @@ -0,0 +1,64 @@ +class RecipientListsController < ApplicationController + before_action :set_school + before_action :set_recipient_list, only: [:show, :edit, :update, :destroy] + + # GET schools/1/recipient_lists + def index + @recipient_lists = @school.recipient_lists + end + + # GET schools/1/recipient_lists/1 + def show + end + + # GET schools/1/recipient_lists/new + def new + @recipient_list = @school.recipient_lists.build + end + + # GET schools/1/recipient_lists/1/edit + def edit + end + + # POST schools/1/recipient_lists + def create + @recipient_list = @school.recipient_lists.build(recipient_list_params) + + if @recipient_list.save + redirect_to([@recipient_list.school, @recipient_list], notice: 'Recipient list was successfully created.') + else + render action: 'new' + end + end + + # PUT schools/1/recipient_lists/1 + def update + if @recipient_list.update_attributes(recipient_list_params) + redirect_to([@recipient_list.school, @recipient_list], notice: 'Recipient list was successfully updated.') + else + render action: 'edit' + end + end + + # DELETE schools/1/recipient_lists/1 + def destroy + @recipient_list.destroy + + redirect_to @school + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_school + @school = School.find(params[:school_id]) + end + + def set_recipient_list + @recipient_list = @school.recipient_lists.find(params[:id]) + end + + # Only allow a trusted parameter "white list" through. + def recipient_list_params + params.require(:recipient_list).permit(:name, :description, :recipient_ids) + end +end diff --git a/app/helpers/recipient_lists_helper.rb b/app/helpers/recipient_lists_helper.rb new file mode 100644 index 00000000..21b39b5e --- /dev/null +++ b/app/helpers/recipient_lists_helper.rb @@ -0,0 +1,2 @@ +module RecipientListsHelper +end diff --git a/app/models/recipient_list.rb b/app/models/recipient_list.rb new file mode 100644 index 00000000..6f33aec8 --- /dev/null +++ b/app/models/recipient_list.rb @@ -0,0 +1,6 @@ +class RecipientList < ApplicationRecord + belongs_to :school + + validates :name, presence: true + validates :recipient_ids, presence: true +end diff --git a/app/models/school.rb b/app/models/school.rb index d4a0113f..baaf661c 100644 --- a/app/models/school.rb +++ b/app/models/school.rb @@ -1,4 +1,5 @@ class School < ApplicationRecord + has_many :recipient_lists belongs_to :district has_many :recipients diff --git a/app/views/recipient_lists/_form.html.haml b/app/views/recipient_lists/_form.html.haml new file mode 100644 index 00000000..dbd9c0fc --- /dev/null +++ b/app/views/recipient_lists/_form.html.haml @@ -0,0 +1,23 @@ += form_for([@school, @recipient_list]) do |f| + - if @recipient_list.errors.any? + #error_explanation + %h2 + = pluralize(@recipient_list.errors.count, "error") + prohibited this recipient_list from being saved: + %ul + - @recipient_list.errors.full_messages.each do |msg| + %li= msg + .field + = f.label :name + %br/ + = f.text_field :name + .field + = f.label :description + %br/ + = f.text_area :description + .field + = f.label :recipient_ids + %br/ + = f.text_area :recipient_ids + .actions + = f.submit diff --git a/app/views/recipient_lists/edit.html.haml b/app/views/recipient_lists/edit.html.haml new file mode 100644 index 00000000..5a27ad63 --- /dev/null +++ b/app/views/recipient_lists/edit.html.haml @@ -0,0 +1,5 @@ +%h1 Editing recipient_list += render 'form' += link_to 'Show', [@recipient_list.school, @recipient_list] +| += link_to 'Back', school_recipient_lists_path(@recipient_list.school) diff --git a/app/views/recipient_lists/index.html.haml b/app/views/recipient_lists/index.html.haml new file mode 100644 index 00000000..f064ed06 --- /dev/null +++ b/app/views/recipient_lists/index.html.haml @@ -0,0 +1,19 @@ +%h1 Listing recipient_lists +%table + %tr + %th Name + %th Description + %th Recipient ids + %th + %th + %th + - @recipient_lists.each do |recipient_list| + %tr + %td= recipient_list.name + %td= recipient_list.description + %td= recipient_list.recipient_ids + %td= link_to 'Show', [recipient_list.school, recipient_list] + %td= link_to 'Edit', edit_school_recipient_list_path(recipient_list.school, recipient_list) + %td= link_to 'Destroy', [recipient_list.school, recipient_list], :confirm => 'Are you sure?', :method => :delete +%br/ += link_to 'New Recipient list', new_school_recipient_list_path(@school) diff --git a/app/views/recipient_lists/new.html.haml b/app/views/recipient_lists/new.html.haml new file mode 100644 index 00000000..2db4c52f --- /dev/null +++ b/app/views/recipient_lists/new.html.haml @@ -0,0 +1,3 @@ +%h1 New recipient_list += render 'form' += link_to 'Back', school_recipient_lists_path(@recipient_list.school) diff --git a/app/views/recipient_lists/show.html.haml b/app/views/recipient_lists/show.html.haml new file mode 100644 index 00000000..b31897ba --- /dev/null +++ b/app/views/recipient_lists/show.html.haml @@ -0,0 +1,13 @@ +%p#notice= notice +%p + %b Name: + = @recipient_list.name +%p + %b Description: + = @recipient_list.description +%p + %b Recipient ids: + = @recipient_list.recipient_ids += link_to 'Edit', edit_school_recipient_list_path(@recipient_list.school, @recipient_list) +| += link_to 'Back', school_recipient_lists_path(@recipient_list.school) diff --git a/app/views/school/recipient_lists/index.json.jbuilder b/app/views/school/recipient_lists/index.json.jbuilder new file mode 100644 index 00000000..1a8de98a --- /dev/null +++ b/app/views/school/recipient_lists/index.json.jbuilder @@ -0,0 +1,4 @@ +json.array!(@school_recipient_lists) do |school_recipient_list| + json.extract! school_recipient_list, :id, :name, :description, :recipient_ids + json.url school_recipient_list_url(school_recipient_list, format: :json) +end diff --git a/app/views/school/recipient_lists/show.json.jbuilder b/app/views/school/recipient_lists/show.json.jbuilder new file mode 100644 index 00000000..0b70cc59 --- /dev/null +++ b/app/views/school/recipient_lists/show.json.jbuilder @@ -0,0 +1 @@ +json.extract! @school_recipient_list, :id, :name, :description, :recipient_ids, :created_at, :updated_at diff --git a/config/routes.rb b/config/routes.rb index ac1ed306..97e028d6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,6 +2,7 @@ Rails.application.routes.draw do resources :districts resources :schools do + resources :recipient_lists resources :recipients do collection do get :import diff --git a/db/migrate/20170302154609_create_recipient_lists.rb b/db/migrate/20170302154609_create_recipient_lists.rb new file mode 100644 index 00000000..4a947a42 --- /dev/null +++ b/db/migrate/20170302154609_create_recipient_lists.rb @@ -0,0 +1,12 @@ +class CreateRecipientLists < ActiveRecord::Migration[5.0] + def change + create_table :recipient_lists do |t| + t.references :school, foreign_key: true + t.string :name + t.text :description + t.text :recipient_ids + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 49c795c3..0c224712 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170228164245) do +ActiveRecord::Schema.define(version: 20170302154609) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -22,6 +22,16 @@ ActiveRecord::Schema.define(version: 20170228164245) do t.datetime "updated_at", null: false end + create_table "recipient_lists", force: :cascade do |t| + t.integer "school_id" + t.string "name" + t.text "description" + t.text "recipient_ids" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["school_id"], name: "index_recipient_lists_on_school_id", using: :btree + end + create_table "recipients", force: :cascade do |t| t.string "name" t.string "phone" @@ -61,4 +71,5 @@ ActiveRecord::Schema.define(version: 20170228164245) do t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree end + add_foreign_key "recipient_lists", "schools" end diff --git a/spec/controllers/recipient_lists_controller_spec.rb b/spec/controllers/recipient_lists_controller_spec.rb new file mode 100644 index 00000000..a439fbc3 --- /dev/null +++ b/spec/controllers/recipient_lists_controller_spec.rb @@ -0,0 +1,166 @@ +require 'rails_helper' + +# This spec was generated by rspec-rails when you ran the scaffold generator. +# It demonstrates how one might use RSpec to specify the controller code that +# was generated by Rails when you ran the scaffold generator. +# +# It assumes that the implementation code is generated by the rails scaffold +# generator. If you are using any extension libraries to generate different +# controller code, this generated spec may or may not pass. +# +# It only uses APIs available in rails and/or rspec-rails. There are a number +# of tools you can use to make these specs even more expressive, but we're +# sticking to rails and rspec-rails APIs to keep things simple and stable. +# +# Compared to earlier versions of this generator, there is very limited use of +# stubs and message expectations in this spec. Stubs are only used when there +# is no simpler way to get a handle on the object needed for the example. +# Message expectations are only used when there is no simpler way to specify +# that an instance is receiving a specific message. + +RSpec.describe RecipientListsController, type: :controller do + + let(:school) { School.create!(name: 'School') } + + # This should return the minimal set of attributes required to create a valid + # RecipientList. As you add validations to RecipientList, be sure to + # adjust the attributes here as well. + let(:valid_attributes) { + { + school_id: school.id, + recipient_ids: '1,2,3', + name: 'Parents', + description: 'List of parents.' + } + } + + let(:invalid_attributes) { + {school_id: school.id, name: 'Empty List', recipient_ids: ''} + } + + # This should return the minimal set of values that should be in the session + # in order to pass any filters (e.g. authentication) defined in + # RecipientListsController. Be sure to keep this updated too. + let(:valid_session) { {} } + + describe "GET #index" do + it "assigns all recipient_lists as @recipient_lists" do + recipient_list = RecipientList.create! valid_attributes + get :index, params: {school_id: school.to_param}, session: valid_session + expect(assigns(:recipient_lists)).to eq([recipient_list]) + end + end + + describe "GET #show" do + it "assigns the requested recipient_list as @recipient_list" do + recipient_list = RecipientList.create! valid_attributes + get :show, params: {school_id: school.to_param, id: recipient_list.to_param}, session: valid_session + expect(assigns(:recipient_list)).to eq(recipient_list) + end + end + + describe "GET #new" do + it "assigns a new recipient_list as @recipient_list" do + get :new, params: {school_id: school.to_param}, session: valid_session + expect(assigns(:recipient_list)).to be_a_new(RecipientList) + end + end + + describe "GET #edit" do + it "assigns the requested recipient_list as @recipient_list" do + recipient_list = RecipientList.create! valid_attributes + get :edit, params: {school_id: school.to_param, id: recipient_list.to_param}, session: valid_session + expect(assigns(:recipient_list)).to eq(recipient_list) + end + end + + describe "POST #create" do + context "with valid params" do + it "creates a new RecipientList" do + expect { + post :create, params: {school_id: school.to_param, recipient_list: valid_attributes}, session: valid_session + }.to change(RecipientList, :count).by(1) + end + + it "assigns a newly created recipient_list as @recipient_list" do + post :create, params: {school_id: school.to_param, recipient_list: valid_attributes}, session: valid_session + expect(assigns(:recipient_list)).to be_a(RecipientList) + expect(assigns(:recipient_list)).to be_persisted + end + + it "redirects to the created recipient_list" do + post :create, params: {school_id: school.to_param, recipient_list: valid_attributes}, session: valid_session + expect(response).to redirect_to(school_recipient_list_path(school, RecipientList.last)) + end + end + + context "with invalid params" do + it "assigns a newly created but unsaved recipient_list as @recipient_list" do + post :create, params: {school_id: school.to_param, recipient_list: invalid_attributes}, session: valid_session + expect(assigns(:recipient_list)).to be_a_new(RecipientList) + end + + it "re-renders the 'new' template" do + post :create, params: {school_id: school.to_param, recipient_list: invalid_attributes}, session: valid_session + expect(response).to render_template("new") + end + end + end + + describe "PUT #update" do + context "with valid params" do + let(:new_attributes) { + {recipient_ids: '3,4,5'} + } + + it "updates the requested recipient_list" do + recipient_list = RecipientList.create! valid_attributes + put :update, params: {school_id: school.to_param, id: recipient_list.to_param, recipient_list: new_attributes}, session: valid_session + recipient_list.reload + expect(recipient_list.recipient_ids).to eq('3,4,5') + end + + it "assigns the requested recipient_list as @recipient_list" do + recipient_list = RecipientList.create! valid_attributes + put :update, params: {school_id: school.to_param, id: recipient_list.to_param, recipient_list: valid_attributes}, session: valid_session + expect(assigns(:recipient_list)).to eq(recipient_list) + end + + it "redirects to the recipient_list" do + recipient_list = RecipientList.create! valid_attributes + put :update, params: {school_id: school.to_param, id: recipient_list.to_param, recipient_list: valid_attributes}, session: valid_session + expect(response).to redirect_to(school_recipient_list_url(school, recipient_list)) + end + end + + context "with invalid params" do + it "assigns the recipient_list as @recipient_list" do + recipient_list = RecipientList.create! valid_attributes + put :update, params: {school_id: school.to_param, id: recipient_list.to_param, recipient_list: invalid_attributes}, session: valid_session + expect(assigns(:recipient_list)).to eq(recipient_list) + end + + it "re-renders the 'edit' template" do + recipient_list = RecipientList.create! valid_attributes + put :update, params: {school_id: school.to_param, id: recipient_list.to_param, recipient_list: invalid_attributes}, session: valid_session + expect(response).to render_template("edit") + end + end + end + + describe "DELETE #destroy" do + it "destroys the requested recipient_list" do + recipient_list = RecipientList.create! valid_attributes + expect { + delete :destroy, params: {school_id: school.to_param, id: recipient_list.to_param}, session: valid_session + }.to change(RecipientList, :count).by(-1) + end + + it "redirects to the recipient_lists list" do + recipient_list = RecipientList.create! valid_attributes + delete :destroy, params: {school_id: school.to_param, id: recipient_list.to_param}, session: valid_session + expect(response).to redirect_to(school) + end + end + +end diff --git a/spec/routing/recipient_lists_routing_spec.rb b/spec/routing/recipient_lists_routing_spec.rb new file mode 100644 index 00000000..4bf4b5d4 --- /dev/null +++ b/spec/routing/recipient_lists_routing_spec.rb @@ -0,0 +1,45 @@ +require "rails_helper" + +RSpec.describe RecipientListsController, type: :routing do + describe "routing" do + before(:each) do + @school = School.create!( + :name => "MyString", + :district_id => 1 + ) + end + + it "routes to #index" do + expect(:get => "schools/#{@school.id}/recipient_lists").to route_to("recipient_lists#index", school_id: @school.id.to_s) + end + + it "routes to #new" do + expect(:get => "schools/#{@school.id}/recipient_lists/new").to route_to("recipient_lists#new", school_id: @school.id.to_s) + end + + it "routes to #show" do + expect(:get => "schools/#{@school.id}/recipient_lists/1").to route_to("recipient_lists#show", school_id: @school.id.to_s, :id => "1") + end + + it "routes to #edit" do + expect(:get => "schools/#{@school.id}/recipient_lists/1/edit").to route_to("recipient_lists#edit", school_id: @school.id.to_s, :id => "1") + end + + it "routes to #create" do + expect(:post => "schools/#{@school.id}/recipient_lists").to route_to("recipient_lists#create", school_id: @school.id.to_s) + end + + it "routes to #update via PUT" do + expect(:put => "schools/#{@school.id}/recipient_lists/1").to route_to("recipient_lists#update", school_id: @school.id.to_s, :id => "1") + end + + it "routes to #update via PATCH" do + expect(:patch => "schools/#{@school.id}/recipient_lists/1").to route_to("recipient_lists#update", school_id: @school.id.to_s, :id => "1") + end + + it "routes to #destroy" do + expect(:delete => "schools/#{@school.id}/recipient_lists/1").to route_to("recipient_lists#destroy", school_id: @school.id.to_s, :id => "1") + end + + end +end diff --git a/spec/views/recipient_lists/edit.html.erb_spec.rb b/spec/views/recipient_lists/edit.html.erb_spec.rb new file mode 100644 index 00000000..dcf6442f --- /dev/null +++ b/spec/views/recipient_lists/edit.html.erb_spec.rb @@ -0,0 +1,29 @@ +require 'rails_helper' + +RSpec.describe "recipient_lists/edit", type: :view do + before(:each) do + @school = assign(:school, School.create!( + :name => "School" + )) + + @recipient_list = assign(:recipient_list, RecipientList.create!( + :name => "MyString", + :description => "MyText", + :recipient_ids => "1,2,3", + :school_id => @school.id + )) + end + + it "renders the edit recipient_list form" do + render + + assert_select "form[action=?][method=?]", school_recipient_list_path(@school, @recipient_list), "post" do + + assert_select "input#recipient_list_name[name=?]", "recipient_list[name]" + + assert_select "textarea#recipient_list_description[name=?]", "recipient_list[description]" + + assert_select "textarea#recipient_list_recipient_ids[name=?]", "recipient_list[recipient_ids]" + end + end +end diff --git a/spec/views/recipient_lists/index.html.erb_spec.rb b/spec/views/recipient_lists/index.html.erb_spec.rb new file mode 100644 index 00000000..e1efd65b --- /dev/null +++ b/spec/views/recipient_lists/index.html.erb_spec.rb @@ -0,0 +1,30 @@ +require 'rails_helper' + +RSpec.describe "recipient_lists/index", type: :view do + before(:each) do + @school = assign(:school, School.create!(name: 'School')) + + assign(:recipient_lists, [ + RecipientList.create!( + :name => "Name", + :description => "MyText", + :recipient_ids => "1,2,3", + :school_id => @school.id + ), + RecipientList.create!( + :name => "Name", + :description => "MyText", + :recipient_ids => "2,3,4", + :school_id => @school.id + ) + ]) + end + + it "renders a list of recipient_lists" do + render + assert_select "tr>td", :text => "Name".to_s, :count => 2 + assert_select "tr>td", :text => "MyText".to_s, :count => 2 + assert_select "tr>td", :text => "1,2,3".to_s, :count => 1 + assert_select "tr>td", :text => "2,3,4".to_s, :count => 1 + end +end diff --git a/spec/views/recipient_lists/new.html.erb_spec.rb b/spec/views/recipient_lists/new.html.erb_spec.rb new file mode 100644 index 00000000..5ab14010 --- /dev/null +++ b/spec/views/recipient_lists/new.html.erb_spec.rb @@ -0,0 +1,26 @@ +require 'rails_helper' + +RSpec.describe "recipient_lists/new", type: :view do + before(:each) do + @school = assign(:school, School.create!(name: 'School')) + + @recipient_list = assign(:recipient_list, RecipientList.new( + :name => "MyString", + :description => "MyText", + :recipient_ids => "MyText", + :school_id => @school.id + )) + end + + it "renders new recipient_list form" do + render + + assert_select "form[action=?][method=?]", school_recipient_lists_path(@school, @recipient_list), "post" do + assert_select "input#recipient_list_name[name=?]", "recipient_list[name]" + + assert_select "textarea#recipient_list_description[name=?]", "recipient_list[description]" + + assert_select "textarea#recipient_list_recipient_ids[name=?]", "recipient_list[recipient_ids]" + end + end +end diff --git a/spec/views/recipient_lists/show.html.erb_spec.rb b/spec/views/recipient_lists/show.html.erb_spec.rb new file mode 100644 index 00000000..79796e5a --- /dev/null +++ b/spec/views/recipient_lists/show.html.erb_spec.rb @@ -0,0 +1,20 @@ +require 'rails_helper' + +RSpec.describe "recipient_lists/show", type: :view do + before(:each) do + @school = assign(:school, School.create!(name: 'School')) + @recipient_list = assign(:recipient_list, RecipientList.create!( + :name => "Name", + :description => "MyText", + :recipient_ids => "MyText", + :school_id => @school.id + )) + end + + it "renders attributes in
" do + render + expect(rendered).to match(/Name/) + expect(rendered).to match(/MyText/) + expect(rendered).to match(/MyText/) + end +end