diff --git a/app/assets/javascripts/question_lists.coffee b/app/assets/javascripts/question_lists.coffee new file mode 100644 index 00000000..24f83d18 --- /dev/null +++ b/app/assets/javascripts/question_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/question_lists.scss b/app/assets/stylesheets/question_lists.scss new file mode 100644 index 00000000..c5b1e232 --- /dev/null +++ b/app/assets/stylesheets/question_lists.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the QuestionLists 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/question_lists_controller.rb b/app/controllers/question_lists_controller.rb new file mode 100644 index 00000000..daf90aac --- /dev/null +++ b/app/controllers/question_lists_controller.rb @@ -0,0 +1,74 @@ +class QuestionListsController < ApplicationController + before_action :set_question_list, only: [:show, :edit, :update, :destroy] + + # GET /question_lists + # GET /question_lists.json + def index + @question_lists = QuestionList.all + end + + # GET /question_lists/1 + # GET /question_lists/1.json + def show + end + + # GET /question_lists/new + def new + @question_list = QuestionList.new + end + + # GET /question_lists/1/edit + def edit + end + + # POST /question_lists + # POST /question_lists.json + def create + @question_list = QuestionList.new(question_list_params) + + respond_to do |format| + if @question_list.save + format.html { redirect_to @question_list, notice: 'Question list was successfully created.' } + format.json { render :show, status: :created, location: @question_list } + else + format.html { render :new } + format.json { render json: @question_list.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /question_lists/1 + # PATCH/PUT /question_lists/1.json + def update + respond_to do |format| + if @question_list.update(question_list_params) + format.html { redirect_to @question_list, notice: 'Question list was successfully updated.' } + format.json { render :show, status: :ok, location: @question_list } + else + format.html { render :edit } + format.json { render json: @question_list.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /question_lists/1 + # DELETE /question_lists/1.json + def destroy + @question_list.destroy + respond_to do |format| + format.html { redirect_to question_lists_url, notice: 'Question list was successfully destroyed.' } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_question_list + @question_list = QuestionList.find(params[:id]) + end + + # Never trust parameters from the scary internet, only allow the white list through. + def question_list_params + params.require(:question_list).permit(:name, :description, question_id_array: []) + end +end diff --git a/app/helpers/question_lists_helper.rb b/app/helpers/question_lists_helper.rb new file mode 100644 index 00000000..61134f41 --- /dev/null +++ b/app/helpers/question_lists_helper.rb @@ -0,0 +1,2 @@ +module QuestionListsHelper +end diff --git a/app/models/question_list.rb b/app/models/question_list.rb new file mode 100644 index 00000000..07e89187 --- /dev/null +++ b/app/models/question_list.rb @@ -0,0 +1,26 @@ +class QuestionList < ApplicationRecord + + validates :name, presence: true + validates :question_ids, presence: true + + attr_accessor :question_id_array + before_validation :convert_question_id_array + after_initialize :set_question_id_array + + def questions + question_id_array.collect { |id| Question.where(id: id).first } + end + + private + + def convert_question_id_array + return if question_id_array.blank? + self.question_ids = question_id_array.reject { |id| id.to_s.empty? }.join(',') + end + + def set_question_id_array + return if question_ids.blank? + self.question_id_array = question_ids.split(',').map(&:to_i) + end + +end diff --git a/app/views/categories/_full_path.html.haml b/app/views/categories/_full_path.html.haml index 1e8550d2..a483f2c9 100644 --- a/app/views/categories/_full_path.html.haml +++ b/app/views/categories/_full_path.html.haml @@ -1,3 +1,3 @@ - categories = [category] -- categories << category while (category = category.parent_category) +- categories << category while (category = category.parent_category).present? = categories.reverse.map { |category| link_to(category.name, category) }.join(' | ').html_safe diff --git a/app/views/question_lists/_form.html.haml b/app/views/question_lists/_form.html.haml new file mode 100644 index 00000000..04f5ff5a --- /dev/null +++ b/app/views/question_lists/_form.html.haml @@ -0,0 +1,20 @@ += form_for(question_list) do |f| + - if question_list.errors.any? + #error_explanation + %h2 + = pluralize(question_list.errors.count, "error") + prohibited this question_list from being saved: + %ul + - question_list.errors.full_messages.each do |message| + %li= message + .field + = f.label :name + = f.text_field :name + .field + = f.label :description + = f.text_area :description + .field + = f.label :question_ids + = f.text_area :question_ids + .actions + = f.submit diff --git a/app/views/question_lists/edit.html.haml b/app/views/question_lists/edit.html.haml new file mode 100644 index 00000000..374f01b9 --- /dev/null +++ b/app/views/question_lists/edit.html.haml @@ -0,0 +1,5 @@ +%h1 Editing Question List += render 'form', question_list: @question_list += link_to 'Show', @question_list +| += link_to 'Back', question_lists_path diff --git a/app/views/question_lists/index.html.haml b/app/views/question_lists/index.html.haml new file mode 100644 index 00000000..2e68099a --- /dev/null +++ b/app/views/question_lists/index.html.haml @@ -0,0 +1,20 @@ +%p#notice= notice +%h1 Question Lists +%table + %thead + %tr + %th Name + %th Description + %th Question ids + %th{:colspan => "3"} + %tbody + - @question_lists.each do |question_list| + %tr + %td= question_list.name + %td= question_list.description + %td= question_list.question_ids + %td= link_to 'Show', question_list + %td= link_to 'Edit', edit_question_list_path(question_list) + %td= link_to 'Destroy', question_list, method: :delete, data: { confirm: 'Are you sure?' } +%br/ += link_to 'New Question List', new_question_list_path diff --git a/app/views/question_lists/index.json.jbuilder b/app/views/question_lists/index.json.jbuilder new file mode 100644 index 00000000..2b20ef0e --- /dev/null +++ b/app/views/question_lists/index.json.jbuilder @@ -0,0 +1,4 @@ +json.array!(@question_lists) do |question_list| + json.extract! question_list, :id, :name, :description, :question_ids + json.url question_list_url(question_list, format: :json) +end diff --git a/app/views/question_lists/new.html.haml b/app/views/question_lists/new.html.haml new file mode 100644 index 00000000..ad8f1932 --- /dev/null +++ b/app/views/question_lists/new.html.haml @@ -0,0 +1,3 @@ +%h1 New Question List += render 'form', question_list: @question_list += link_to 'Back', question_lists_path diff --git a/app/views/question_lists/show.html.haml b/app/views/question_lists/show.html.haml new file mode 100644 index 00000000..dc09959b --- /dev/null +++ b/app/views/question_lists/show.html.haml @@ -0,0 +1,13 @@ +%p#notice= notice +%p + %strong Name: + = @question_list.name +%p + %strong Description: + = @question_list.description +%p + %strong Question ids: + = @question_list.question_ids += link_to 'Edit', edit_question_list_path(@question_list) +| += link_to 'Back', question_lists_path diff --git a/app/views/question_lists/show.json.jbuilder b/app/views/question_lists/show.json.jbuilder new file mode 100644 index 00000000..2768b318 --- /dev/null +++ b/app/views/question_lists/show.json.jbuilder @@ -0,0 +1 @@ +json.extract! @question_list, :id, :name, :description, :question_ids, :created_at, :updated_at diff --git a/app/views/questions/show.html.haml b/app/views/questions/show.html.haml index c975825d..08a1e351 100644 --- a/app/views/questions/show.html.haml +++ b/app/views/questions/show.html.haml @@ -20,7 +20,10 @@ %p %strong Category: - = render partial: 'categories/full_path', locals: {category: @question.category} + - if @question.category.present? + = render partial: 'categories/full_path', locals: {category: @question.category} + - else + No Category = link_to 'Edit', edit_question_path(@question) | diff --git a/config/routes.rb b/config/routes.rb index a65d2976..71f3a1f2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,5 @@ Rails.application.routes.draw do + resources :question_lists resources :questions resources :categories resources :districts diff --git a/db/migrate/20170305155018_create_question_lists.rb b/db/migrate/20170305155018_create_question_lists.rb new file mode 100644 index 00000000..b0ee44b9 --- /dev/null +++ b/db/migrate/20170305155018_create_question_lists.rb @@ -0,0 +1,11 @@ +class CreateQuestionLists < ActiveRecord::Migration[5.0] + def change + create_table :question_lists do |t| + t.string :name + t.text :description + t.text :question_ids + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index adb591d2..69d9717a 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: 20170304020530) do +ActiveRecord::Schema.define(version: 20170305155018) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -32,6 +32,14 @@ ActiveRecord::Schema.define(version: 20170304020530) do t.datetime "updated_at", null: false end + create_table "question_lists", force: :cascade do |t| + t.string "name" + t.text "description" + t.text "question_ids" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "questions", force: :cascade do |t| t.string "text" t.string "option1" diff --git a/spec/controllers/question_lists_controller_spec.rb b/spec/controllers/question_lists_controller_spec.rb new file mode 100644 index 00000000..9cc18c0d --- /dev/null +++ b/spec/controllers/question_lists_controller_spec.rb @@ -0,0 +1,159 @@ +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 QuestionListsController, type: :controller do + + # This should return the minimal set of attributes required to create a valid + # QuestionList. As you add validations to QuestionList, be sure to + # adjust the attributes here as well. + let(:valid_attributes) { + {name: 'Questions for Parents', question_id_array: ['', '1', '2', '3']} + } + + let(:invalid_attributes) { + {question_id_array: ['']} + } + + # 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 + # QuestionListsController. Be sure to keep this updated too. + let(:valid_session) { {} } + + describe "GET #index" do + it "assigns all question_lists as @question_lists" do + question_list = QuestionList.create! valid_attributes + get :index, params: {}, session: valid_session + expect(assigns(:question_lists)).to eq([question_list]) + end + end + + describe "GET #show" do + it "assigns the requested question_list as @question_list" do + question_list = QuestionList.create! valid_attributes + get :show, params: {id: question_list.to_param}, session: valid_session + expect(assigns(:question_list)).to eq(question_list) + end + end + + describe "GET #new" do + it "assigns a new question_list as @question_list" do + get :new, params: {}, session: valid_session + expect(assigns(:question_list)).to be_a_new(QuestionList) + end + end + + describe "GET #edit" do + it "assigns the requested question_list as @question_list" do + question_list = QuestionList.create! valid_attributes + get :edit, params: {id: question_list.to_param}, session: valid_session + expect(assigns(:question_list)).to eq(question_list) + end + end + + describe "POST #create" do + context "with valid params" do + it "creates a new QuestionList" do + expect { + post :create, params: {question_list: valid_attributes}, session: valid_session + }.to change(QuestionList, :count).by(1) + end + + it "assigns a newly created question_list as @question_list" do + post :create, params: {question_list: valid_attributes}, session: valid_session + expect(assigns(:question_list)).to be_a(QuestionList) + expect(assigns(:question_list)).to be_persisted + end + + it "redirects to the created question_list" do + post :create, params: {question_list: valid_attributes}, session: valid_session + expect(response).to redirect_to(QuestionList.last) + end + end + + context "with invalid params" do + it "assigns a newly created but unsaved question_list as @question_list" do + post :create, params: {question_list: invalid_attributes}, session: valid_session + expect(assigns(:question_list)).to be_a_new(QuestionList) + end + + it "re-renders the 'new' template" do + post :create, params: {question_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) { + {question_id_array: ['', '2', '3']} + } + + it "updates the requested question_list" do + question_list = QuestionList.create! valid_attributes + put :update, params: {id: question_list.to_param, question_list: new_attributes}, session: valid_session + question_list.reload + expect(question_list.question_ids).to eq('2,3') + end + + it "assigns the requested question_list as @question_list" do + question_list = QuestionList.create! valid_attributes + put :update, params: {id: question_list.to_param, question_list: valid_attributes}, session: valid_session + expect(assigns(:question_list)).to eq(question_list) + end + + it "redirects to the question_list" do + question_list = QuestionList.create! valid_attributes + put :update, params: {id: question_list.to_param, question_list: valid_attributes}, session: valid_session + expect(response).to redirect_to(question_list) + end + end + + context "with invalid params" do + it "assigns the question_list as @question_list" do + question_list = QuestionList.create! valid_attributes + put :update, params: {id: question_list.to_param, question_list: invalid_attributes}, session: valid_session + expect(assigns(:question_list)).to eq(question_list) + end + + it "re-renders the 'edit' template" do + question_list = QuestionList.create! valid_attributes + put :update, params: {id: question_list.to_param, question_list: invalid_attributes}, session: valid_session + expect(response).to render_template("edit") + end + end + end + + describe "DELETE #destroy" do + it "destroys the requested question_list" do + question_list = QuestionList.create! valid_attributes + expect { + delete :destroy, params: {id: question_list.to_param}, session: valid_session + }.to change(QuestionList, :count).by(-1) + end + + it "redirects to the question_lists list" do + question_list = QuestionList.create! valid_attributes + delete :destroy, params: {id: question_list.to_param}, session: valid_session + expect(response).to redirect_to(question_lists_url) + end + end + +end diff --git a/spec/routing/question_lists_routing_spec.rb b/spec/routing/question_lists_routing_spec.rb new file mode 100644 index 00000000..e3d2faa1 --- /dev/null +++ b/spec/routing/question_lists_routing_spec.rb @@ -0,0 +1,39 @@ +require "rails_helper" + +RSpec.describe QuestionListsController, type: :routing do + describe "routing" do + + it "routes to #index" do + expect(:get => "/question_lists").to route_to("question_lists#index") + end + + it "routes to #new" do + expect(:get => "/question_lists/new").to route_to("question_lists#new") + end + + it "routes to #show" do + expect(:get => "/question_lists/1").to route_to("question_lists#show", :id => "1") + end + + it "routes to #edit" do + expect(:get => "/question_lists/1/edit").to route_to("question_lists#edit", :id => "1") + end + + it "routes to #create" do + expect(:post => "/question_lists").to route_to("question_lists#create") + end + + it "routes to #update via PUT" do + expect(:put => "/question_lists/1").to route_to("question_lists#update", :id => "1") + end + + it "routes to #update via PATCH" do + expect(:patch => "/question_lists/1").to route_to("question_lists#update", :id => "1") + end + + it "routes to #destroy" do + expect(:delete => "/question_lists/1").to route_to("question_lists#destroy", :id => "1") + end + + end +end diff --git a/spec/views/categories/show.html.erb_spec.rb b/spec/views/categories/show.html.erb_spec.rb index 8cb76e13..6e8f6f50 100644 --- a/spec/views/categories/show.html.erb_spec.rb +++ b/spec/views/categories/show.html.erb_spec.rb @@ -7,7 +7,7 @@ RSpec.describe "categories/show", type: :view do :blurb => "Blurb", :description => "MyText", :external_id => "External", - :parent_category_id => 2 + :parent_category => Category.create(name: 'Parent Category') )) end @@ -17,6 +17,6 @@ RSpec.describe "categories/show", type: :view do expect(rendered).to match(/Blurb/) expect(rendered).to match(/MyText/) expect(rendered).to match(/External/) - expect(rendered).to match(/2/) + expect(rendered).to match(/Parent Category/) end end diff --git a/spec/views/question_lists/edit.html.erb_spec.rb b/spec/views/question_lists/edit.html.erb_spec.rb new file mode 100644 index 00000000..c6921c7d --- /dev/null +++ b/spec/views/question_lists/edit.html.erb_spec.rb @@ -0,0 +1,24 @@ +require 'rails_helper' + +RSpec.describe "question_lists/edit", type: :view do + before(:each) do + @question_list = assign(:question_list, QuestionList.create!( + :name => "MyString", + :description => "MyText", + :question_ids => "MyText" + )) + end + + it "renders the edit question_list form" do + render + + assert_select "form[action=?][method=?]", question_list_path(@question_list), "post" do + + assert_select "input#question_list_name[name=?]", "question_list[name]" + + assert_select "textarea#question_list_description[name=?]", "question_list[description]" + + assert_select "textarea#question_list_question_ids[name=?]", "question_list[question_ids]" + end + end +end diff --git a/spec/views/question_lists/index.html.erb_spec.rb b/spec/views/question_lists/index.html.erb_spec.rb new file mode 100644 index 00000000..00222e74 --- /dev/null +++ b/spec/views/question_lists/index.html.erb_spec.rb @@ -0,0 +1,26 @@ +require 'rails_helper' + +RSpec.describe "question_lists/index", type: :view do + before(:each) do + assign(:question_lists, [ + QuestionList.create!( + :name => "Name", + :description => "MyText", + :question_ids => "1,2,3" + ), + QuestionList.create!( + :name => "Name", + :description => "MyText", + :question_ids => "2,3,4" + ) + ]) + end + + it "renders a list of question_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/question_lists/new.html.erb_spec.rb b/spec/views/question_lists/new.html.erb_spec.rb new file mode 100644 index 00000000..b36fbe8a --- /dev/null +++ b/spec/views/question_lists/new.html.erb_spec.rb @@ -0,0 +1,24 @@ +require 'rails_helper' + +RSpec.describe "question_lists/new", type: :view do + before(:each) do + assign(:question_list, QuestionList.new( + :name => "MyString", + :description => "MyText", + :question_ids => "MyText" + )) + end + + it "renders new question_list form" do + render + + assert_select "form[action=?][method=?]", question_lists_path, "post" do + + assert_select "input#question_list_name[name=?]", "question_list[name]" + + assert_select "textarea#question_list_description[name=?]", "question_list[description]" + + assert_select "textarea#question_list_question_ids[name=?]", "question_list[question_ids]" + end + end +end diff --git a/spec/views/question_lists/show.html.erb_spec.rb b/spec/views/question_lists/show.html.erb_spec.rb new file mode 100644 index 00000000..4e3e5875 --- /dev/null +++ b/spec/views/question_lists/show.html.erb_spec.rb @@ -0,0 +1,18 @@ +require 'rails_helper' + +RSpec.describe "question_lists/show", type: :view do + before(:each) do + @question_list = assign(:question_list, QuestionList.create!( + :name => "Name", + :description => "MyText", + :question_ids => "MyText" + )) + end + + it "renders attributes in
" do + render + expect(rendered).to match(/Name/) + expect(rendered).to match(/MyText/) + expect(rendered).to match(/MyText/) + end +end diff --git a/spec/views/questions/index.html.erb_spec.rb b/spec/views/questions/index.html.erb_spec.rb index 8ab6fc10..f4095d23 100644 --- a/spec/views/questions/index.html.erb_spec.rb +++ b/spec/views/questions/index.html.erb_spec.rb @@ -10,7 +10,7 @@ RSpec.describe "questions/index", type: :view do :option3 => "Option3", :option4 => "Option4", :option5 => "Option5", - :category_id => 2 + :category => Category.create(name: "Category 1") ), Question.create!( :text => "Text", @@ -19,7 +19,7 @@ RSpec.describe "questions/index", type: :view do :option3 => "Option3", :option4 => "Option4", :option5 => "Option5", - :category_id => 2 + :category => Category.create(name: "Category 2") ) ]) end @@ -32,6 +32,7 @@ RSpec.describe "questions/index", type: :view do assert_select "tr>td", :text => "Option3".to_s, :count => 2 assert_select "tr>td", :text => "Option4".to_s, :count => 2 assert_select "tr>td", :text => "Option5".to_s, :count => 2 - assert_select "tr>td", :text => 2.to_s, :count => 2 + assert_select "tr>td", :text => "Category 1", :count => 1 + assert_select "tr>td", :text => "Category 2", :count => 1 end end diff --git a/spec/views/questions/show.html.erb_spec.rb b/spec/views/questions/show.html.erb_spec.rb index ee1c1fb0..4e5f4da0 100644 --- a/spec/views/questions/show.html.erb_spec.rb +++ b/spec/views/questions/show.html.erb_spec.rb @@ -9,7 +9,7 @@ RSpec.describe "questions/show", type: :view do :option3 => "Option3", :option4 => "Option4", :option5 => "Option5", - :category_id => 2 + :category => Category.create!(name: 'Category Name') )) end @@ -21,6 +21,6 @@ RSpec.describe "questions/show", type: :view do expect(rendered).to match(/Option3/) expect(rendered).to match(/Option4/) expect(rendered).to match(/Option5/) - expect(rendered).to match(/2/) + expect(rendered).to match(/Category Name/) end end