diff --git a/app/assets/javascripts/categories.coffee b/app/assets/javascripts/categories.coffee new file mode 100644 index 00000000..24f83d18 --- /dev/null +++ b/app/assets/javascripts/categories.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/categories.scss b/app/assets/stylesheets/categories.scss new file mode 100644 index 00000000..42976cbc --- /dev/null +++ b/app/assets/stylesheets/categories.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Categories 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/categories_controller.rb b/app/controllers/categories_controller.rb new file mode 100644 index 00000000..5ff956aa --- /dev/null +++ b/app/controllers/categories_controller.rb @@ -0,0 +1,74 @@ +class CategoriesController < ApplicationController + before_action :set_category, only: [:show, :edit, :update, :destroy] + + # GET /categories + # GET /categories.json + def index + @categories = Category.all + end + + # GET /categories/1 + # GET /categories/1.json + def show + end + + # GET /categories/new + def new + @category = Category.new + end + + # GET /categories/1/edit + def edit + end + + # POST /categories + # POST /categories.json + def create + @category = Category.new(category_params) + + respond_to do |format| + if @category.save + format.html { redirect_to @category, notice: 'Category was successfully created.' } + format.json { render :show, status: :created, location: @category } + else + format.html { render :new } + format.json { render json: @category.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /categories/1 + # PATCH/PUT /categories/1.json + def update + respond_to do |format| + if @category.update(category_params) + format.html { redirect_to @category, notice: 'Category was successfully updated.' } + format.json { render :show, status: :ok, location: @category } + else + format.html { render :edit } + format.json { render json: @category.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /categories/1 + # DELETE /categories/1.json + def destroy + @category.destroy + respond_to do |format| + format.html { redirect_to categories_url, notice: 'Category was successfully destroyed.' } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_category + @category = Category.find(params[:id]) + end + + # Never trust parameters from the scary internet, only allow the white list through. + def category_params + params.require(:category).permit(:name, :blurb, :description, :external_id, :parent_category_id) + end +end diff --git a/app/helpers/categories_helper.rb b/app/helpers/categories_helper.rb new file mode 100644 index 00000000..e06f3155 --- /dev/null +++ b/app/helpers/categories_helper.rb @@ -0,0 +1,2 @@ +module CategoriesHelper +end diff --git a/app/models/category.rb b/app/models/category.rb new file mode 100644 index 00000000..e73efe67 --- /dev/null +++ b/app/models/category.rb @@ -0,0 +1,5 @@ +class Category < ApplicationRecord + + validates :name, presence: true + +end diff --git a/app/views/categories/_form.html.erb b/app/views/categories/_form.html.erb new file mode 100644 index 00000000..e86104ea --- /dev/null +++ b/app/views/categories/_form.html.erb @@ -0,0 +1,42 @@ +<%= form_for(category) do |f| %> + <% if category.errors.any? %> +
<%= notice %>
+ +| Name | +Blurb | +Description | +External | +Parent category | ++ | ||
|---|---|---|---|---|---|---|---|
| <%= category.name %> | +<%= category.blurb %> | +<%= category.description %> | +<%= category.external_id %> | +<%= category.parent_category_id %> | +<%= link_to 'Show', category %> | +<%= link_to 'Edit', edit_category_path(category) %> | +<%= link_to 'Destroy', category, method: :delete, data: { confirm: 'Are you sure?' } %> | +
<%= notice %>
+ ++ Name: + <%= @category.name %> +
+ ++ Blurb: + <%= @category.blurb %> +
+ ++ Description: + <%= @category.description %> +
+ ++ External: + <%= @category.external_id %> +
+ ++ Parent category: + <%= @category.parent_category_id %> +
+ +<%= link_to 'Edit', edit_category_path(@category) %> | +<%= link_to 'Back', categories_path %> diff --git a/app/views/categories/show.json.jbuilder b/app/views/categories/show.json.jbuilder new file mode 100644 index 00000000..7b1171fb --- /dev/null +++ b/app/views/categories/show.json.jbuilder @@ -0,0 +1 @@ +json.extract! @category, :id, :name, :blurb, :description, :external_id, :parent_category_id, :created_at, :updated_at diff --git a/config/routes.rb b/config/routes.rb index 97e028d6..2a936a24 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,5 @@ Rails.application.routes.draw do + resources :categories resources :districts resources :schools do diff --git a/db/migrate/20170303162123_create_categories.rb b/db/migrate/20170303162123_create_categories.rb new file mode 100644 index 00000000..2ef44115 --- /dev/null +++ b/db/migrate/20170303162123_create_categories.rb @@ -0,0 +1,13 @@ +class CreateCategories < ActiveRecord::Migration[5.0] + def change + create_table :categories do |t| + t.string :name + t.string :blurb + t.text :description + t.string :external_id + t.integer :parent_category_id + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 0c224712..93ca50dd 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,11 +10,21 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170302154609) do +ActiveRecord::Schema.define(version: 20170303162123) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" + create_table "categories", force: :cascade do |t| + t.string "name" + t.string "blurb" + t.text "description" + t.string "external_id" + t.integer "parent_category_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "districts", force: :cascade do |t| t.string "name" t.integer "state_id" diff --git a/spec/controllers/categories_controller_spec.rb b/spec/controllers/categories_controller_spec.rb new file mode 100644 index 00000000..074175e7 --- /dev/null +++ b/spec/controllers/categories_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 CategoriesController, type: :controller do + + # This should return the minimal set of attributes required to create a valid + # Category. As you add validations to Category, be sure to + # adjust the attributes here as well. + let(:valid_attributes) { + {name: 'Category', external_id: 'A'} + } + + let(:invalid_attributes) { + {name: ''} + } + + # 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 + # CategoriesController. Be sure to keep this updated too. + let(:valid_session) { {} } + + describe "GET #index" do + it "assigns all categories as @categories" do + category = Category.create! valid_attributes + get :index, params: {}, session: valid_session + expect(assigns(:categories)).to eq([category]) + end + end + + describe "GET #show" do + it "assigns the requested category as @category" do + category = Category.create! valid_attributes + get :show, params: {id: category.to_param}, session: valid_session + expect(assigns(:category)).to eq(category) + end + end + + describe "GET #new" do + it "assigns a new category as @category" do + get :new, params: {}, session: valid_session + expect(assigns(:category)).to be_a_new(Category) + end + end + + describe "GET #edit" do + it "assigns the requested category as @category" do + category = Category.create! valid_attributes + get :edit, params: {id: category.to_param}, session: valid_session + expect(assigns(:category)).to eq(category) + end + end + + describe "POST #create" do + context "with valid params" do + it "creates a new Category" do + expect { + post :create, params: {category: valid_attributes}, session: valid_session + }.to change(Category, :count).by(1) + end + + it "assigns a newly created category as @category" do + post :create, params: {category: valid_attributes}, session: valid_session + expect(assigns(:category)).to be_a(Category) + expect(assigns(:category)).to be_persisted + end + + it "redirects to the created category" do + post :create, params: {category: valid_attributes}, session: valid_session + expect(response).to redirect_to(Category.last) + end + end + + context "with invalid params" do + it "assigns a newly created but unsaved category as @category" do + post :create, params: {category: invalid_attributes}, session: valid_session + expect(assigns(:category)).to be_a_new(Category) + end + + it "re-renders the 'new' template" do + post :create, params: {category: 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) { + {name: 'Category 2'} + } + + it "updates the requested category" do + category = Category.create! valid_attributes + put :update, params: {id: category.to_param, category: new_attributes}, session: valid_session + category.reload + expect(category.name).to eq('Category 2') + end + + it "assigns the requested category as @category" do + category = Category.create! valid_attributes + put :update, params: {id: category.to_param, category: valid_attributes}, session: valid_session + expect(assigns(:category)).to eq(category) + end + + it "redirects to the category" do + category = Category.create! valid_attributes + put :update, params: {id: category.to_param, category: valid_attributes}, session: valid_session + expect(response).to redirect_to(category) + end + end + + context "with invalid params" do + it "assigns the category as @category" do + category = Category.create! valid_attributes + put :update, params: {id: category.to_param, category: invalid_attributes}, session: valid_session + expect(assigns(:category)).to eq(category) + end + + it "re-renders the 'edit' template" do + category = Category.create! valid_attributes + put :update, params: {id: category.to_param, category: invalid_attributes}, session: valid_session + expect(response).to render_template("edit") + end + end + end + + describe "DELETE #destroy" do + it "destroys the requested category" do + category = Category.create! valid_attributes + expect { + delete :destroy, params: {id: category.to_param}, session: valid_session + }.to change(Category, :count).by(-1) + end + + it "redirects to the categories list" do + category = Category.create! valid_attributes + delete :destroy, params: {id: category.to_param}, session: valid_session + expect(response).to redirect_to(categories_url) + end + end + +end diff --git a/spec/routing/categories_routing_spec.rb b/spec/routing/categories_routing_spec.rb new file mode 100644 index 00000000..162e5d13 --- /dev/null +++ b/spec/routing/categories_routing_spec.rb @@ -0,0 +1,39 @@ +require "rails_helper" + +RSpec.describe CategoriesController, type: :routing do + describe "routing" do + + it "routes to #index" do + expect(:get => "/categories").to route_to("categories#index") + end + + it "routes to #new" do + expect(:get => "/categories/new").to route_to("categories#new") + end + + it "routes to #show" do + expect(:get => "/categories/1").to route_to("categories#show", :id => "1") + end + + it "routes to #edit" do + expect(:get => "/categories/1/edit").to route_to("categories#edit", :id => "1") + end + + it "routes to #create" do + expect(:post => "/categories").to route_to("categories#create") + end + + it "routes to #update via PUT" do + expect(:put => "/categories/1").to route_to("categories#update", :id => "1") + end + + it "routes to #update via PATCH" do + expect(:patch => "/categories/1").to route_to("categories#update", :id => "1") + end + + it "routes to #destroy" do + expect(:delete => "/categories/1").to route_to("categories#destroy", :id => "1") + end + + end +end diff --git a/spec/views/categories/edit.html.erb_spec.rb b/spec/views/categories/edit.html.erb_spec.rb new file mode 100644 index 00000000..b18e335c --- /dev/null +++ b/spec/views/categories/edit.html.erb_spec.rb @@ -0,0 +1,30 @@ +require 'rails_helper' + +RSpec.describe "categories/edit", type: :view do + before(:each) do + @category = assign(:category, Category.create!( + :name => "MyString", + :blurb => "MyString", + :description => "MyText", + :external_id => "MyString", + :parent_category_id => 1 + )) + end + + it "renders the edit category form" do + render + + assert_select "form[action=?][method=?]", category_path(@category), "post" do + + assert_select "input#category_name[name=?]", "category[name]" + + assert_select "input#category_blurb[name=?]", "category[blurb]" + + assert_select "textarea#category_description[name=?]", "category[description]" + + assert_select "input#category_external_id[name=?]", "category[external_id]" + + assert_select "input#category_parent_category_id[name=?]", "category[parent_category_id]" + end + end +end diff --git a/spec/views/categories/index.html.erb_spec.rb b/spec/views/categories/index.html.erb_spec.rb new file mode 100644 index 00000000..72856143 --- /dev/null +++ b/spec/views/categories/index.html.erb_spec.rb @@ -0,0 +1,31 @@ +require 'rails_helper' + +RSpec.describe "categories/index", type: :view do + before(:each) do + assign(:categories, [ + Category.create!( + :name => "Name", + :blurb => "Blurb", + :description => "MyText", + :external_id => "External", + :parent_category_id => 2 + ), + Category.create!( + :name => "Name", + :blurb => "Blurb", + :description => "MyText", + :external_id => "External", + :parent_category_id => 2 + ) + ]) + end + + it "renders a list of categories" do + render + assert_select "tr>td", :text => "Name".to_s, :count => 2 + assert_select "tr>td", :text => "Blurb".to_s, :count => 2 + assert_select "tr>td", :text => "MyText".to_s, :count => 2 + assert_select "tr>td", :text => "External".to_s, :count => 2 + assert_select "tr>td", :text => 2.to_s, :count => 2 + end +end diff --git a/spec/views/categories/new.html.erb_spec.rb b/spec/views/categories/new.html.erb_spec.rb new file mode 100644 index 00000000..d9af1069 --- /dev/null +++ b/spec/views/categories/new.html.erb_spec.rb @@ -0,0 +1,30 @@ +require 'rails_helper' + +RSpec.describe "categories/new", type: :view do + before(:each) do + assign(:category, Category.new( + :name => "MyString", + :blurb => "MyString", + :description => "MyText", + :external_id => "MyString", + :parent_category_id => 1 + )) + end + + it "renders new category form" do + render + + assert_select "form[action=?][method=?]", categories_path, "post" do + + assert_select "input#category_name[name=?]", "category[name]" + + assert_select "input#category_blurb[name=?]", "category[blurb]" + + assert_select "textarea#category_description[name=?]", "category[description]" + + assert_select "input#category_external_id[name=?]", "category[external_id]" + + assert_select "input#category_parent_category_id[name=?]", "category[parent_category_id]" + end + end +end diff --git a/spec/views/categories/show.html.erb_spec.rb b/spec/views/categories/show.html.erb_spec.rb new file mode 100644 index 00000000..8cb76e13 --- /dev/null +++ b/spec/views/categories/show.html.erb_spec.rb @@ -0,0 +1,22 @@ +require 'rails_helper' + +RSpec.describe "categories/show", type: :view do + before(:each) do + @category = assign(:category, Category.create!( + :name => "Name", + :blurb => "Blurb", + :description => "MyText", + :external_id => "External", + :parent_category_id => 2 + )) + end + + it "renders attributes in" do + render + expect(rendered).to match(/Name/) + expect(rendered).to match(/Blurb/) + expect(rendered).to match(/MyText/) + expect(rendered).to match(/External/) + expect(rendered).to match(/2/) + end +end