From af38f8574eda7f1fa0fd50904424c741cd2f25dc Mon Sep 17 00:00:00 2001 From: Skud Date: Tue, 7 May 2013 20:56:10 +1000 Subject: [PATCH] rails g scaffold Product... --- app/assets/javascripts/products.js.coffee | 3 + app/controllers/products_controller.rb | 83 +++++++++++ app/helpers/products_helper.rb | 2 + app/models/ability.rb | 4 +- app/models/product.rb | 3 + app/views/products/_form.html.haml | 19 +++ app/views/products/edit.html.haml | 7 + app/views/products/index.html.haml | 23 +++ app/views/products/new.html.haml | 5 + app/views/products/show.html.haml | 15 ++ db/migrate/20130507105357_create_products.rb | 11 ++ spec/controllers/products_controller_spec.rb | 144 +++++++++++++++++++ spec/factories/products.rb | 9 ++ spec/models/product_spec.rb | 5 + spec/requests/products_spec.rb | 11 ++ spec/routing/products_routing_spec.rb | 35 +++++ spec/views/products/edit.html.haml_spec.rb | 22 +++ spec/views/products/index.html.haml_spec.rb | 26 ++++ spec/views/products/new.html.haml_spec.rb | 22 +++ spec/views/products/show.html.haml_spec.rb | 19 +++ 20 files changed, 467 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/products.js.coffee create mode 100644 app/controllers/products_controller.rb create mode 100644 app/helpers/products_helper.rb create mode 100644 app/models/product.rb create mode 100644 app/views/products/_form.html.haml create mode 100644 app/views/products/edit.html.haml create mode 100644 app/views/products/index.html.haml create mode 100644 app/views/products/new.html.haml create mode 100644 app/views/products/show.html.haml create mode 100644 db/migrate/20130507105357_create_products.rb create mode 100644 spec/controllers/products_controller_spec.rb create mode 100644 spec/factories/products.rb create mode 100644 spec/models/product_spec.rb create mode 100644 spec/requests/products_spec.rb create mode 100644 spec/routing/products_routing_spec.rb create mode 100644 spec/views/products/edit.html.haml_spec.rb create mode 100644 spec/views/products/index.html.haml_spec.rb create mode 100644 spec/views/products/new.html.haml_spec.rb create mode 100644 spec/views/products/show.html.haml_spec.rb diff --git a/app/assets/javascripts/products.js.coffee b/app/assets/javascripts/products.js.coffee new file mode 100644 index 000000000..761567942 --- /dev/null +++ b/app/assets/javascripts/products.js.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://jashkenas.github.com/coffee-script/ diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb new file mode 100644 index 000000000..1fbfefc6c --- /dev/null +++ b/app/controllers/products_controller.rb @@ -0,0 +1,83 @@ +class ProductsController < ApplicationController + # GET /products + # GET /products.json + def index + @products = Product.all + + respond_to do |format| + format.html # index.html.erb + format.json { render json: @products } + end + end + + # GET /products/1 + # GET /products/1.json + def show + @product = Product.find(params[:id]) + + respond_to do |format| + format.html # show.html.erb + format.json { render json: @product } + end + end + + # GET /products/new + # GET /products/new.json + def new + @product = Product.new + + respond_to do |format| + format.html # new.html.erb + format.json { render json: @product } + end + end + + # GET /products/1/edit + def edit + @product = Product.find(params[:id]) + end + + # POST /products + # POST /products.json + def create + @product = Product.new(params[:product]) + + respond_to do |format| + if @product.save + format.html { redirect_to @product, notice: 'Product was successfully created.' } + format.json { render json: @product, status: :created, location: @product } + else + format.html { render action: "new" } + format.json { render json: @product.errors, status: :unprocessable_entity } + end + end + end + + # PUT /products/1 + # PUT /products/1.json + def update + @product = Product.find(params[:id]) + + respond_to do |format| + if @product.update_attributes(params[:product]) + format.html { redirect_to @product, notice: 'Product was successfully updated.' } + format.json { head :no_content } + else + format.html { render action: "edit" } + format.json { render json: @product.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /products/1 + # DELETE /products/1.json + def destroy + @product = Product.find(params[:id]) + @product.destroy + + respond_to do |format| + format.html { redirect_to products_url } + format.json { head :no_content } + end + end +end diff --git a/app/helpers/products_helper.rb b/app/helpers/products_helper.rb new file mode 100644 index 000000000..ab5c42b32 --- /dev/null +++ b/app/helpers/products_helper.rb @@ -0,0 +1,2 @@ +module ProductsHelper +end diff --git a/app/models/ability.rb b/app/models/ability.rb index e8ffaf75c..c29f7cbbd 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -6,12 +6,14 @@ class Ability # everyone can do these things, even non-logged in can :read, :all + + # except these, which don't make sense if you're not logged in cannot :read, Notification - cannot :create, Notification cannot :read, Authentication # nobody should be able to view this except admins cannot :read, Role + cannot :read, Product if member diff --git a/app/models/product.rb b/app/models/product.rb new file mode 100644 index 000000000..9e32d40d5 --- /dev/null +++ b/app/models/product.rb @@ -0,0 +1,3 @@ +class Product < ActiveRecord::Base + attr_accessible :description, :min_price, :name +end diff --git a/app/views/products/_form.html.haml b/app/views/products/_form.html.haml new file mode 100644 index 000000000..8b2909af7 --- /dev/null +++ b/app/views/products/_form.html.haml @@ -0,0 +1,19 @@ += form_for @product do |f| + - if @product.errors.any? + #error_explanation + %h2= "#{pluralize(@product.errors.count, "error")} prohibited this product from being saved:" + %ul + - @product.errors.full_messages.each do |msg| + %li= msg + + .field + = f.label :name + = f.text_field :name + .field + = f.label :description + = f.text_field :description + .field + = f.label :min_price + = f.text_field :min_price + .actions + = f.submit 'Save' diff --git a/app/views/products/edit.html.haml b/app/views/products/edit.html.haml new file mode 100644 index 000000000..9c16087ea --- /dev/null +++ b/app/views/products/edit.html.haml @@ -0,0 +1,7 @@ +%h1 Editing product + += render 'form' + += link_to 'Show', @product +\| += link_to 'Back', products_path diff --git a/app/views/products/index.html.haml b/app/views/products/index.html.haml new file mode 100644 index 000000000..caf508db7 --- /dev/null +++ b/app/views/products/index.html.haml @@ -0,0 +1,23 @@ +%h1 Listing products + +%table + %tr + %th Name + %th Description + %th Min price + %th + %th + %th + + - @products.each do |product| + %tr + %td= product.name + %td= product.description + %td= product.min_price + %td= link_to 'Show', product + %td= link_to 'Edit', edit_product_path(product) + %td= link_to 'Destroy', product, :method => :delete, :data => { :confirm => 'Are you sure?' } + +%br + += link_to 'New Product', new_product_path diff --git a/app/views/products/new.html.haml b/app/views/products/new.html.haml new file mode 100644 index 000000000..71ed863eb --- /dev/null +++ b/app/views/products/new.html.haml @@ -0,0 +1,5 @@ +%h1 New product + += render 'form' + += link_to 'Back', products_path diff --git a/app/views/products/show.html.haml b/app/views/products/show.html.haml new file mode 100644 index 000000000..03b2e6e08 --- /dev/null +++ b/app/views/products/show.html.haml @@ -0,0 +1,15 @@ +%p#notice= notice + +%p + %b Name: + = @product.name +%p + %b Description: + = @product.description +%p + %b Min price: + = @product.min_price + += link_to 'Edit', edit_product_path(@product) +\| += link_to 'Back', products_path diff --git a/db/migrate/20130507105357_create_products.rb b/db/migrate/20130507105357_create_products.rb new file mode 100644 index 000000000..0ad9b1063 --- /dev/null +++ b/db/migrate/20130507105357_create_products.rb @@ -0,0 +1,11 @@ +class CreateProducts < ActiveRecord::Migration + def change + create_table :products do |t| + t.string :name, :null => false + t.string :description, :null => false + t.decimal :min_price, :null => false + + t.timestamps + end + end +end diff --git a/spec/controllers/products_controller_spec.rb b/spec/controllers/products_controller_spec.rb new file mode 100644 index 000000000..c31c2c9ae --- /dev/null +++ b/spec/controllers/products_controller_spec.rb @@ -0,0 +1,144 @@ +require 'spec_helper' + +describe ProductsController do + + def valid_attributes + { + :name => "product name", + :description => 'some description', + :min_price => 9.99 + } + end + + def valid_session + {} + end + + describe "GET index" do + it "assigns all products as @products" do + product = Product.create! valid_attributes + get :index, {}, valid_session + assigns(:products).should eq([product]) + end + end + + describe "GET show" do + it "assigns the requested product as @product" do + product = Product.create! valid_attributes + get :show, {:id => product.to_param}, valid_session + assigns(:product).should eq(product) + end + end + + describe "GET new" do + it "assigns a new product as @product" do + get :new, {}, valid_session + assigns(:product).should be_a_new(Product) + end + end + + describe "GET edit" do + it "assigns the requested product as @product" do + product = Product.create! valid_attributes + get :edit, {:id => product.to_param}, valid_session + assigns(:product).should eq(product) + end + end + + describe "POST create" do + describe "with valid params" do + it "creates a new Product" do + expect { + post :create, {:product => valid_attributes}, valid_session + }.to change(Product, :count).by(1) + end + + it "assigns a newly created product as @product" do + post :create, {:product => valid_attributes}, valid_session + assigns(:product).should be_a(Product) + assigns(:product).should be_persisted + end + + it "redirects to the created product" do + post :create, {:product => valid_attributes}, valid_session + response.should redirect_to(Product.last) + end + end + + describe "with invalid params" do + it "assigns a newly created but unsaved product as @product" do + # Trigger the behavior that occurs when invalid params are submitted + Product.any_instance.stub(:save).and_return(false) + post :create, {:product => { "name" => "invalid value" }}, valid_session + assigns(:product).should be_a_new(Product) + end + + it "re-renders the 'new' template" do + # Trigger the behavior that occurs when invalid params are submitted + Product.any_instance.stub(:save).and_return(false) + post :create, {:product => { "name" => "invalid value" }}, valid_session + response.should render_template("new") + end + end + end + + describe "PUT update" do + describe "with valid params" do + it "updates the requested product" do + product = Product.create! valid_attributes + # Assuming there are no other products in the database, this + # specifies that the Product created on the previous line + # receives the :update_attributes message with whatever params are + # submitted in the request. + Product.any_instance.should_receive(:update_attributes).with({ "name" => "MyString" }) + put :update, {:id => product.to_param, :product => { "name" => "MyString" }}, valid_session + end + + it "assigns the requested product as @product" do + product = Product.create! valid_attributes + put :update, {:id => product.to_param, :product => valid_attributes}, valid_session + assigns(:product).should eq(product) + end + + it "redirects to the product" do + product = Product.create! valid_attributes + put :update, {:id => product.to_param, :product => valid_attributes}, valid_session + response.should redirect_to(product) + end + end + + describe "with invalid params" do + it "assigns the product as @product" do + product = Product.create! valid_attributes + # Trigger the behavior that occurs when invalid params are submitted + Product.any_instance.stub(:save).and_return(false) + put :update, {:id => product.to_param, :product => { "name" => "invalid value" }}, valid_session + assigns(:product).should eq(product) + end + + it "re-renders the 'edit' template" do + product = Product.create! valid_attributes + # Trigger the behavior that occurs when invalid params are submitted + Product.any_instance.stub(:save).and_return(false) + put :update, {:id => product.to_param, :product => { "name" => "invalid value" }}, valid_session + response.should render_template("edit") + end + end + end + + describe "DELETE destroy" do + it "destroys the requested product" do + product = Product.create! valid_attributes + expect { + delete :destroy, {:id => product.to_param}, valid_session + }.to change(Product, :count).by(-1) + end + + it "redirects to the products list" do + product = Product.create! valid_attributes + delete :destroy, {:id => product.to_param}, valid_session + response.should redirect_to(products_url) + end + end + +end diff --git a/spec/factories/products.rb b/spec/factories/products.rb new file mode 100644 index 000000000..405924518 --- /dev/null +++ b/spec/factories/products.rb @@ -0,0 +1,9 @@ +# Read about factories at https://github.com/thoughtbot/factory_girl + +FactoryGirl.define do + factory :product do + name "annual subscription" + description "paid membership, renewing yearly" + min_price "9.99" + end +end diff --git a/spec/models/product_spec.rb b/spec/models/product_spec.rb new file mode 100644 index 000000000..267720887 --- /dev/null +++ b/spec/models/product_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe Product do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/requests/products_spec.rb b/spec/requests/products_spec.rb new file mode 100644 index 000000000..5618d7115 --- /dev/null +++ b/spec/requests/products_spec.rb @@ -0,0 +1,11 @@ +require 'spec_helper' + +describe "Products" do + describe "GET /products" do + it "works! (now write some real specs)" do + # Run the generator again with the --webrat flag if you want to use webrat methods/matchers + get products_path + response.status.should be(200) + end + end +end diff --git a/spec/routing/products_routing_spec.rb b/spec/routing/products_routing_spec.rb new file mode 100644 index 000000000..e50a77956 --- /dev/null +++ b/spec/routing/products_routing_spec.rb @@ -0,0 +1,35 @@ +require "spec_helper" + +describe ProductsController do + describe "routing" do + + it "routes to #index" do + get("/products").should route_to("products#index") + end + + it "routes to #new" do + get("/products/new").should route_to("products#new") + end + + it "routes to #show" do + get("/products/1").should route_to("products#show", :id => "1") + end + + it "routes to #edit" do + get("/products/1/edit").should route_to("products#edit", :id => "1") + end + + it "routes to #create" do + post("/products").should route_to("products#create") + end + + it "routes to #update" do + put("/products/1").should route_to("products#update", :id => "1") + end + + it "routes to #destroy" do + delete("/products/1").should route_to("products#destroy", :id => "1") + end + + end +end diff --git a/spec/views/products/edit.html.haml_spec.rb b/spec/views/products/edit.html.haml_spec.rb new file mode 100644 index 000000000..26cd392c5 --- /dev/null +++ b/spec/views/products/edit.html.haml_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe "products/edit" do + before(:each) do + @product = assign(:product, stub_model(Product, + :name => "MyString", + :description => "MyString", + :min_price => "9.99" + )) + end + + it "renders the edit product form" do + render + + # Run the generator again with the --webrat flag if you want to use webrat matchers + assert_select "form", :action => products_path(@product), :method => "post" do + assert_select "input#product_name", :name => "product[name]" + assert_select "input#product_description", :name => "product[description]" + assert_select "input#product_min_price", :name => "product[min_price]" + end + end +end diff --git a/spec/views/products/index.html.haml_spec.rb b/spec/views/products/index.html.haml_spec.rb new file mode 100644 index 000000000..5f300415a --- /dev/null +++ b/spec/views/products/index.html.haml_spec.rb @@ -0,0 +1,26 @@ +require 'spec_helper' + +describe "products/index" do + before(:each) do + assign(:products, [ + stub_model(Product, + :name => "Name", + :description => "Description", + :min_price => "9.99" + ), + stub_model(Product, + :name => "Name", + :description => "Description", + :min_price => "9.99" + ) + ]) + end + + it "renders a list of products" do + render + # Run the generator again with the --webrat flag if you want to use webrat matchers + assert_select "tr>td", :text => "Name".to_s, :count => 2 + assert_select "tr>td", :text => "Description".to_s, :count => 2 + assert_select "tr>td", :text => "9.99".to_s, :count => 2 + end +end diff --git a/spec/views/products/new.html.haml_spec.rb b/spec/views/products/new.html.haml_spec.rb new file mode 100644 index 000000000..c508a89c5 --- /dev/null +++ b/spec/views/products/new.html.haml_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe "products/new" do + before(:each) do + assign(:product, stub_model(Product, + :name => "MyString", + :description => "MyString", + :min_price => "9.99" + ).as_new_record) + end + + it "renders new product form" do + render + + # Run the generator again with the --webrat flag if you want to use webrat matchers + assert_select "form", :action => products_path, :method => "post" do + assert_select "input#product_name", :name => "product[name]" + assert_select "input#product_description", :name => "product[description]" + assert_select "input#product_min_price", :name => "product[min_price]" + end + end +end diff --git a/spec/views/products/show.html.haml_spec.rb b/spec/views/products/show.html.haml_spec.rb new file mode 100644 index 000000000..b49bbbae2 --- /dev/null +++ b/spec/views/products/show.html.haml_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe "products/show" do + before(:each) do + @product = assign(:product, stub_model(Product, + :name => "Name", + :description => "Description", + :min_price => "9.99" + )) + end + + it "renders attributes in

" do + render + # Run the generator again with the --webrat flag if you want to use webrat matchers + rendered.should match(/Name/) + rendered.should match(/Description/) + rendered.should match(/9.99/) + end +end