From 80d1b20eeb9d1b067a40173ea1fae44142c8b602 Mon Sep 17 00:00:00 2001 From: Tammy Date: Tue, 8 Dec 2015 12:01:41 -0800 Subject: [PATCH 001/299] created Catergory model controller and CRUD --- app/assets/javascripts/categories.coffee | 3 + app/assets/stylesheets/categories.scss | 3 + app/controllers/categories_controller.rb | 74 ++++++++ app/helpers/categories_helper.rb | 2 + app/models/category.rb | 2 + app/views/categories/_form.html.erb | 21 +++ app/views/categories/edit.html.erb | 6 + app/views/categories/index.html.erb | 27 +++ app/views/categories/index.json.jbuilder | 4 + app/views/categories/new.html.erb | 5 + app/views/categories/show.html.erb | 9 + app/views/categories/show.json.jbuilder | 1 + config/routes.rb | 1 + .../20151208200117_create_categories.rb | 9 + .../controllers/categories_controller_spec.rb | 159 ++++++++++++++++++ spec/helpers/categories_helper_spec.rb | 15 ++ spec/models/category_spec.rb | 5 + spec/requests/categories_spec.rb | 10 ++ spec/routing/categories_routing_spec.rb | 39 +++++ spec/views/categories/edit.html.erb_spec.rb | 18 ++ spec/views/categories/index.html.erb_spec.rb | 19 +++ spec/views/categories/new.html.erb_spec.rb | 18 ++ spec/views/categories/show.html.erb_spec.rb | 14 ++ 23 files changed, 464 insertions(+) create mode 100644 app/assets/javascripts/categories.coffee create mode 100644 app/assets/stylesheets/categories.scss create mode 100644 app/controllers/categories_controller.rb create mode 100644 app/helpers/categories_helper.rb create mode 100644 app/models/category.rb create mode 100644 app/views/categories/_form.html.erb create mode 100644 app/views/categories/edit.html.erb create mode 100644 app/views/categories/index.html.erb create mode 100644 app/views/categories/index.json.jbuilder create mode 100644 app/views/categories/new.html.erb create mode 100644 app/views/categories/show.html.erb create mode 100644 app/views/categories/show.json.jbuilder create mode 100644 db/migrate/20151208200117_create_categories.rb create mode 100644 spec/controllers/categories_controller_spec.rb create mode 100644 spec/helpers/categories_helper_spec.rb create mode 100644 spec/models/category_spec.rb create mode 100644 spec/requests/categories_spec.rb create mode 100644 spec/routing/categories_routing_spec.rb create mode 100644 spec/views/categories/edit.html.erb_spec.rb create mode 100644 spec/views/categories/index.html.erb_spec.rb create mode 100644 spec/views/categories/new.html.erb_spec.rb create mode 100644 spec/views/categories/show.html.erb_spec.rb diff --git a/app/assets/javascripts/categories.coffee b/app/assets/javascripts/categories.coffee new file mode 100644 index 0000000000..24f83d18bb --- /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 0000000000..42976cbc11 --- /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 0000000000..363c1cb628 --- /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) + end +end diff --git a/app/helpers/categories_helper.rb b/app/helpers/categories_helper.rb new file mode 100644 index 0000000000..e06f31554c --- /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 0000000000..910a0098c4 --- /dev/null +++ b/app/models/category.rb @@ -0,0 +1,2 @@ +class Category < ActiveRecord::Base +end diff --git a/app/views/categories/_form.html.erb b/app/views/categories/_form.html.erb new file mode 100644 index 0000000000..dd35d336a7 --- /dev/null +++ b/app/views/categories/_form.html.erb @@ -0,0 +1,21 @@ +<%= form_for(@category) do |f| %> + <% if @category.errors.any? %> +
+

<%= pluralize(@category.errors.count, "error") %> prohibited this category from being saved:

+ + +
+ <% end %> + +
+ <%= f.label :name %>
+ <%= f.text_field :name %> +
+
+ <%= f.submit %> +
+<% end %> diff --git a/app/views/categories/edit.html.erb b/app/views/categories/edit.html.erb new file mode 100644 index 0000000000..5ded0a83ff --- /dev/null +++ b/app/views/categories/edit.html.erb @@ -0,0 +1,6 @@ +

Editing Category

+ +<%= render 'form' %> + +<%= link_to 'Show', @category %> | +<%= link_to 'Back', categories_path %> diff --git a/app/views/categories/index.html.erb b/app/views/categories/index.html.erb new file mode 100644 index 0000000000..84ab2e3b41 --- /dev/null +++ b/app/views/categories/index.html.erb @@ -0,0 +1,27 @@ +

<%= notice %>

+ +

Listing Categories

+ + + + + + + + + + + <% @categories.each do |category| %> + + + + + + + <% end %> + +
Name
<%= category.name %><%= link_to 'Show', category %><%= link_to 'Edit', edit_category_path(category) %><%= link_to 'Destroy', category, method: :delete, data: { confirm: 'Are you sure?' } %>
+ +
+ +<%= link_to 'New Category', new_category_path %> diff --git a/app/views/categories/index.json.jbuilder b/app/views/categories/index.json.jbuilder new file mode 100644 index 0000000000..997fe33a31 --- /dev/null +++ b/app/views/categories/index.json.jbuilder @@ -0,0 +1,4 @@ +json.array!(@categories) do |category| + json.extract! category, :id, :name + json.url category_url(category, format: :json) +end diff --git a/app/views/categories/new.html.erb b/app/views/categories/new.html.erb new file mode 100644 index 0000000000..ade3b7a7e5 --- /dev/null +++ b/app/views/categories/new.html.erb @@ -0,0 +1,5 @@ +

New Category

+ +<%= render 'form' %> + +<%= link_to 'Back', categories_path %> diff --git a/app/views/categories/show.html.erb b/app/views/categories/show.html.erb new file mode 100644 index 0000000000..09b199c8c5 --- /dev/null +++ b/app/views/categories/show.html.erb @@ -0,0 +1,9 @@ +

<%= notice %>

+ +

+ Name: + <%= @category.name %> +

+ +<%= 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 0000000000..19636d23c8 --- /dev/null +++ b/app/views/categories/show.json.jbuilder @@ -0,0 +1 @@ +json.extract! @category, :id, :name, :created_at, :updated_at diff --git a/config/routes.rb b/config/routes.rb index 3cfaf1cded..773e6d4d9a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,5 @@ Rails.application.routes.draw do + resources :categories resources :users # The priority is based upon order of creation: first created -> highest priority. # See how all your routes lay out with "rake routes". diff --git a/db/migrate/20151208200117_create_categories.rb b/db/migrate/20151208200117_create_categories.rb new file mode 100644 index 0000000000..b574669a21 --- /dev/null +++ b/db/migrate/20151208200117_create_categories.rb @@ -0,0 +1,9 @@ +class CreateCategories < ActiveRecord::Migration + def change + create_table :categories do |t| + t.string :name + + t.timestamps null: false + end + end +end diff --git a/spec/controllers/categories_controller_spec.rb b/spec/controllers/categories_controller_spec.rb new file mode 100644 index 0000000000..e273ded83a --- /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) { + skip("Add a hash of attributes valid for your model") + } + + let(:invalid_attributes) { + skip("Add a hash of attributes invalid for your model") + } + + # 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, {}, 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, {:id => category.to_param}, valid_session + expect(assigns(:category)).to eq(category) + end + end + + describe "GET #new" do + it "assigns a new category as @category" do + get :new, {}, 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, {:id => category.to_param}, 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, {:category => valid_attributes}, valid_session + }.to change(Category, :count).by(1) + end + + it "assigns a newly created category as @category" do + post :create, {:category => valid_attributes}, 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, {:category => valid_attributes}, 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, {:category => invalid_attributes}, valid_session + expect(assigns(:category)).to be_a_new(Category) + end + + it "re-renders the 'new' template" do + post :create, {:category => invalid_attributes}, valid_session + expect(response).to render_template("new") + end + end + end + + describe "PUT #update" do + context "with valid params" do + let(:new_attributes) { + skip("Add a hash of attributes valid for your model") + } + + it "updates the requested category" do + category = Category.create! valid_attributes + put :update, {:id => category.to_param, :category => new_attributes}, valid_session + category.reload + skip("Add assertions for updated state") + end + + it "assigns the requested category as @category" do + category = Category.create! valid_attributes + put :update, {:id => category.to_param, :category => valid_attributes}, valid_session + expect(assigns(:category)).to eq(category) + end + + it "redirects to the category" do + category = Category.create! valid_attributes + put :update, {:id => category.to_param, :category => valid_attributes}, 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, {:id => category.to_param, :category => invalid_attributes}, valid_session + expect(assigns(:category)).to eq(category) + end + + it "re-renders the 'edit' template" do + category = Category.create! valid_attributes + put :update, {:id => category.to_param, :category => invalid_attributes}, 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, {:id => category.to_param}, valid_session + }.to change(Category, :count).by(-1) + end + + it "redirects to the categories list" do + category = Category.create! valid_attributes + delete :destroy, {:id => category.to_param}, valid_session + expect(response).to redirect_to(categories_url) + end + end + +end diff --git a/spec/helpers/categories_helper_spec.rb b/spec/helpers/categories_helper_spec.rb new file mode 100644 index 0000000000..e717765aea --- /dev/null +++ b/spec/helpers/categories_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the CategoriesHelper. For example: +# +# describe CategoriesHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe CategoriesHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/category_spec.rb b/spec/models/category_spec.rb new file mode 100644 index 0000000000..0c9fefae09 --- /dev/null +++ b/spec/models/category_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Category, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/requests/categories_spec.rb b/spec/requests/categories_spec.rb new file mode 100644 index 0000000000..c5bdce0e1f --- /dev/null +++ b/spec/requests/categories_spec.rb @@ -0,0 +1,10 @@ +require 'rails_helper' + +RSpec.describe "Categories", type: :request do + describe "GET /categories" do + it "works! (now write some real specs)" do + get categories_path + expect(response).to have_http_status(200) + end + end +end diff --git a/spec/routing/categories_routing_spec.rb b/spec/routing/categories_routing_spec.rb new file mode 100644 index 0000000000..162e5d1397 --- /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 0000000000..6e6f92c6c7 --- /dev/null +++ b/spec/views/categories/edit.html.erb_spec.rb @@ -0,0 +1,18 @@ +require 'rails_helper' + +RSpec.describe "categories/edit", type: :view do + before(:each) do + @category = assign(:category, Category.create!( + :name => "MyString" + )) + 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]" + 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 0000000000..7131ca8e1e --- /dev/null +++ b/spec/views/categories/index.html.erb_spec.rb @@ -0,0 +1,19 @@ +require 'rails_helper' + +RSpec.describe "categories/index", type: :view do + before(:each) do + assign(:categories, [ + Category.create!( + :name => "Name" + ), + Category.create!( + :name => "Name" + ) + ]) + end + + it "renders a list of categories" do + render + assert_select "tr>td", :text => "Name".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 0000000000..b3aa22d739 --- /dev/null +++ b/spec/views/categories/new.html.erb_spec.rb @@ -0,0 +1,18 @@ +require 'rails_helper' + +RSpec.describe "categories/new", type: :view do + before(:each) do + assign(:category, Category.new( + :name => "MyString" + )) + 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]" + 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 0000000000..7c95100ffa --- /dev/null +++ b/spec/views/categories/show.html.erb_spec.rb @@ -0,0 +1,14 @@ +require 'rails_helper' + +RSpec.describe "categories/show", type: :view do + before(:each) do + @category = assign(:category, Category.create!( + :name => "Name" + )) + end + + it "renders attributes in

" do + render + expect(rendered).to match(/Name/) + end +end From 771c7098218b61a70b1da24e296c54e95ba7abb2 Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 8 Dec 2015 12:03:14 -0800 Subject: [PATCH 002/299] Create product model --- app/assets/javascripts/products.coffee | 3 + app/assets/stylesheets/products.scss | 3 + app/controllers/products_controller.rb | 74 +++++++++ app/helpers/products_helper.rb | 2 + app/models/product.rb | 2 + app/views/products/_form.html.erb | 45 ++++++ app/views/products/edit.html.erb | 6 + app/views/products/index.html.erb | 39 +++++ app/views/products/index.json.jbuilder | 4 + app/views/products/new.html.erb | 5 + app/views/products/show.html.erb | 39 +++++ app/views/products/show.json.jbuilder | 1 + config/routes.rb | 1 + db/migrate/20151208200155_create_products.rb | 15 ++ spec/controllers/products_controller_spec.rb | 159 +++++++++++++++++++ spec/helpers/products_helper_spec.rb | 15 ++ spec/models/product_spec.rb | 5 + spec/requests/products_spec.rb | 10 ++ spec/routing/products_routing_spec.rb | 39 +++++ spec/views/products/edit.html.erb_spec.rb | 36 +++++ spec/views/products/index.html.erb_spec.rb | 37 +++++ spec/views/products/new.html.erb_spec.rb | 36 +++++ spec/views/products/show.html.erb_spec.rb | 26 +++ 23 files changed, 602 insertions(+) create mode 100644 app/assets/javascripts/products.coffee create mode 100644 app/assets/stylesheets/products.scss 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.erb create mode 100644 app/views/products/edit.html.erb create mode 100644 app/views/products/index.html.erb create mode 100644 app/views/products/index.json.jbuilder create mode 100644 app/views/products/new.html.erb create mode 100644 app/views/products/show.html.erb create mode 100644 app/views/products/show.json.jbuilder create mode 100644 db/migrate/20151208200155_create_products.rb create mode 100644 spec/controllers/products_controller_spec.rb create mode 100644 spec/helpers/products_helper_spec.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.erb_spec.rb create mode 100644 spec/views/products/index.html.erb_spec.rb create mode 100644 spec/views/products/new.html.erb_spec.rb create mode 100644 spec/views/products/show.html.erb_spec.rb diff --git a/app/assets/javascripts/products.coffee b/app/assets/javascripts/products.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/products.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/products.scss b/app/assets/stylesheets/products.scss new file mode 100644 index 0000000000..89e2e8db07 --- /dev/null +++ b/app/assets/stylesheets/products.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the products 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/products_controller.rb b/app/controllers/products_controller.rb new file mode 100644 index 0000000000..aa0f1de53e --- /dev/null +++ b/app/controllers/products_controller.rb @@ -0,0 +1,74 @@ +class ProductsController < ApplicationController + before_action :set_product, only: [:show, :edit, :update, :destroy] + + # GET /products + # GET /products.json + def index + @products = Product.all + end + + # GET /products/1 + # GET /products/1.json + def show + end + + # GET /products/new + def new + @product = Product.new + end + + # GET /products/1/edit + def edit + end + + # POST /products + # POST /products.json + def create + @product = Product.new(product_params) + + respond_to do |format| + if @product.save + format.html { redirect_to @product, notice: 'Product was successfully created.' } + format.json { render :show, status: :created, location: @product } + else + format.html { render :new } + format.json { render json: @product.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /products/1 + # PATCH/PUT /products/1.json + def update + respond_to do |format| + if @product.update(product_params) + format.html { redirect_to @product, notice: 'Product was successfully updated.' } + format.json { render :show, status: :ok, location: @product } + else + format.html { render :edit } + format.json { render json: @product.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /products/1 + # DELETE /products/1.json + def destroy + @product.destroy + respond_to do |format| + format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_product + @product = Product.find(params[:id]) + end + + # Never trust parameters from the scary internet, only allow the white list through. + def product_params + params.require(:product).permit(:name, :price, :user_id, :photo_url, :stock, :description, :active) + end +end diff --git a/app/helpers/products_helper.rb b/app/helpers/products_helper.rb new file mode 100644 index 0000000000..ab5c42b325 --- /dev/null +++ b/app/helpers/products_helper.rb @@ -0,0 +1,2 @@ +module ProductsHelper +end diff --git a/app/models/product.rb b/app/models/product.rb new file mode 100644 index 0000000000..077a819795 --- /dev/null +++ b/app/models/product.rb @@ -0,0 +1,2 @@ +class Product < ActiveRecord::Base +end diff --git a/app/views/products/_form.html.erb b/app/views/products/_form.html.erb new file mode 100644 index 0000000000..ebfc42cfe5 --- /dev/null +++ b/app/views/products/_form.html.erb @@ -0,0 +1,45 @@ +<%= form_for(@product) do |f| %> + <% if @product.errors.any? %> +

+

<%= pluralize(@product.errors.count, "error") %> prohibited this product from being saved:

+ + +
+ <% end %> + +
+ <%= f.label :name %>
+ <%= f.text_field :name %> +
+
+ <%= f.label :price %>
+ <%= f.number_field :price %> +
+
+ <%= f.label :user_id %>
+ <%= f.number_field :user_id %> +
+
+ <%= f.label :photo_url %>
+ <%= f.text_field :photo_url %> +
+
+ <%= f.label :stock %>
+ <%= f.number_field :stock %> +
+
+ <%= f.label :description %>
+ <%= f.text_field :description %> +
+
+ <%= f.label :active %>
+ <%= f.check_box :active %> +
+
+ <%= f.submit %> +
+<% end %> diff --git a/app/views/products/edit.html.erb b/app/views/products/edit.html.erb new file mode 100644 index 0000000000..39f848b282 --- /dev/null +++ b/app/views/products/edit.html.erb @@ -0,0 +1,6 @@ +

Editing Product

+ +<%= render 'form' %> + +<%= link_to 'Show', @product %> | +<%= link_to 'Back', products_path %> diff --git a/app/views/products/index.html.erb b/app/views/products/index.html.erb new file mode 100644 index 0000000000..9f7fe66938 --- /dev/null +++ b/app/views/products/index.html.erb @@ -0,0 +1,39 @@ +

<%= notice %>

+ +

Listing Products

+ + + + + + + + + + + + + + + + + <% @products.each do |product| %> + + + + + + + + + + + + + <% end %> + +
NamePriceUserPhoto urlStockDescriptionActive
<%= product.name %><%= product.price %><%= product.user_id %><%= product.photo_url %><%= product.stock %><%= product.description %><%= product.active %><%= link_to 'Show', product %><%= link_to 'Edit', edit_product_path(product) %><%= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' } %>
+ +
+ +<%= link_to 'New Product', new_product_path %> diff --git a/app/views/products/index.json.jbuilder b/app/views/products/index.json.jbuilder new file mode 100644 index 0000000000..daee3ccd95 --- /dev/null +++ b/app/views/products/index.json.jbuilder @@ -0,0 +1,4 @@ +json.array!(@products) do |product| + json.extract! product, :id, :name, :price, :user_id, :photo_url, :stock, :description, :active + json.url product_url(product, format: :json) +end diff --git a/app/views/products/new.html.erb b/app/views/products/new.html.erb new file mode 100644 index 0000000000..18db96a399 --- /dev/null +++ b/app/views/products/new.html.erb @@ -0,0 +1,5 @@ +

New Product

+ +<%= render 'form' %> + +<%= link_to 'Back', products_path %> diff --git a/app/views/products/show.html.erb b/app/views/products/show.html.erb new file mode 100644 index 0000000000..0dbbdb4d14 --- /dev/null +++ b/app/views/products/show.html.erb @@ -0,0 +1,39 @@ +

<%= notice %>

+ +

+ Name: + <%= @product.name %> +

+ +

+ Price: + <%= @product.price %> +

+ +

+ User: + <%= @product.user_id %> +

+ +

+ Photo url: + <%= @product.photo_url %> +

+ +

+ Stock: + <%= @product.stock %> +

+ +

+ Description: + <%= @product.description %> +

+ +

+ Active: + <%= @product.active %> +

+ +<%= link_to 'Edit', edit_product_path(@product) %> | +<%= link_to 'Back', products_path %> diff --git a/app/views/products/show.json.jbuilder b/app/views/products/show.json.jbuilder new file mode 100644 index 0000000000..c8f4238fc8 --- /dev/null +++ b/app/views/products/show.json.jbuilder @@ -0,0 +1 @@ +json.extract! @product, :id, :name, :price, :user_id, :photo_url, :stock, :description, :active, :created_at, :updated_at diff --git a/config/routes.rb b/config/routes.rb index 3cfaf1cded..b545a8cd87 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,5 @@ Rails.application.routes.draw do + resources :products resources :users # The priority is based upon order of creation: first created -> highest priority. # See how all your routes lay out with "rake routes". diff --git a/db/migrate/20151208200155_create_products.rb b/db/migrate/20151208200155_create_products.rb new file mode 100644 index 0000000000..041adb5ff8 --- /dev/null +++ b/db/migrate/20151208200155_create_products.rb @@ -0,0 +1,15 @@ +class CreateProducts < ActiveRecord::Migration + def change + create_table :products do |t| + t.string :name + t.integer :price + t.integer :user_id + t.string :photo_url + t.integer :stock + t.string :description + t.boolean :active + + t.timestamps null: false + end + end +end diff --git a/spec/controllers/products_controller_spec.rb b/spec/controllers/products_controller_spec.rb new file mode 100644 index 0000000000..21530babc7 --- /dev/null +++ b/spec/controllers/products_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 ProductsController, type: :controller do + + # This should return the minimal set of attributes required to create a valid + # Product. As you add validations to Product, be sure to + # adjust the attributes here as well. + let(:valid_attributes) { + skip("Add a hash of attributes valid for your model") + } + + let(:invalid_attributes) { + skip("Add a hash of attributes invalid for your model") + } + + # 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 + # ProductsController. Be sure to keep this updated too. + let(:valid_session) { {} } + + describe "GET #index" do + it "assigns all products as @products" do + product = Product.create! valid_attributes + get :index, {}, valid_session + expect(assigns(:products)).to 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 + expect(assigns(:product)).to eq(product) + end + end + + describe "GET #new" do + it "assigns a new product as @product" do + get :new, {}, valid_session + expect(assigns(:product)).to 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 + expect(assigns(:product)).to eq(product) + end + end + + describe "POST #create" do + context "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 + expect(assigns(:product)).to be_a(Product) + expect(assigns(:product)).to be_persisted + end + + it "redirects to the created product" do + post :create, {:product => valid_attributes}, valid_session + expect(response).to redirect_to(Product.last) + end + end + + context "with invalid params" do + it "assigns a newly created but unsaved product as @product" do + post :create, {:product => invalid_attributes}, valid_session + expect(assigns(:product)).to be_a_new(Product) + end + + it "re-renders the 'new' template" do + post :create, {:product => invalid_attributes}, valid_session + expect(response).to render_template("new") + end + end + end + + describe "PUT #update" do + context "with valid params" do + let(:new_attributes) { + skip("Add a hash of attributes valid for your model") + } + + it "updates the requested product" do + product = Product.create! valid_attributes + put :update, {:id => product.to_param, :product => new_attributes}, valid_session + product.reload + skip("Add assertions for updated state") + 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 + expect(assigns(:product)).to 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 + expect(response).to redirect_to(product) + end + end + + context "with invalid params" do + it "assigns the product as @product" do + product = Product.create! valid_attributes + put :update, {:id => product.to_param, :product => invalid_attributes}, valid_session + expect(assigns(:product)).to eq(product) + end + + it "re-renders the 'edit' template" do + product = Product.create! valid_attributes + put :update, {:id => product.to_param, :product => invalid_attributes}, valid_session + expect(response).to 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 + expect(response).to redirect_to(products_url) + end + end + +end diff --git a/spec/helpers/products_helper_spec.rb b/spec/helpers/products_helper_spec.rb new file mode 100644 index 0000000000..40a13ae055 --- /dev/null +++ b/spec/helpers/products_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the ProductsHelper. For example: +# +# describe ProductsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe ProductsHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/product_spec.rb b/spec/models/product_spec.rb new file mode 100644 index 0000000000..f22fbfdd36 --- /dev/null +++ b/spec/models/product_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Product, type: :model 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 0000000000..314ad3de73 --- /dev/null +++ b/spec/requests/products_spec.rb @@ -0,0 +1,10 @@ +require 'rails_helper' + +RSpec.describe "Products", type: :request do + describe "GET /products" do + it "works! (now write some real specs)" do + get products_path + expect(response).to have_http_status(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 0000000000..e9f99d4b23 --- /dev/null +++ b/spec/routing/products_routing_spec.rb @@ -0,0 +1,39 @@ +require "rails_helper" + +RSpec.describe ProductsController, type: :routing do + describe "routing" do + + it "routes to #index" do + expect(:get => "/products").to route_to("products#index") + end + + it "routes to #new" do + expect(:get => "/products/new").to route_to("products#new") + end + + it "routes to #show" do + expect(:get => "/products/1").to route_to("products#show", :id => "1") + end + + it "routes to #edit" do + expect(:get => "/products/1/edit").to route_to("products#edit", :id => "1") + end + + it "routes to #create" do + expect(:post => "/products").to route_to("products#create") + end + + it "routes to #update via PUT" do + expect(:put => "/products/1").to route_to("products#update", :id => "1") + end + + it "routes to #update via PATCH" do + expect(:patch => "/products/1").to route_to("products#update", :id => "1") + end + + it "routes to #destroy" do + expect(:delete => "/products/1").to route_to("products#destroy", :id => "1") + end + + end +end diff --git a/spec/views/products/edit.html.erb_spec.rb b/spec/views/products/edit.html.erb_spec.rb new file mode 100644 index 0000000000..3625755533 --- /dev/null +++ b/spec/views/products/edit.html.erb_spec.rb @@ -0,0 +1,36 @@ +require 'rails_helper' + +RSpec.describe "products/edit", type: :view do + before(:each) do + @product = assign(:product, Product.create!( + :name => "MyString", + :price => 1, + :user_id => 1, + :photo_url => "MyString", + :stock => 1, + :description => "MyString", + :active => false + )) + end + + it "renders the edit product form" do + render + + assert_select "form[action=?][method=?]", product_path(@product), "post" do + + assert_select "input#product_name[name=?]", "product[name]" + + assert_select "input#product_price[name=?]", "product[price]" + + assert_select "input#product_user_id[name=?]", "product[user_id]" + + assert_select "input#product_photo_url[name=?]", "product[photo_url]" + + assert_select "input#product_stock[name=?]", "product[stock]" + + assert_select "input#product_description[name=?]", "product[description]" + + assert_select "input#product_active[name=?]", "product[active]" + end + end +end diff --git a/spec/views/products/index.html.erb_spec.rb b/spec/views/products/index.html.erb_spec.rb new file mode 100644 index 0000000000..a44be22ba6 --- /dev/null +++ b/spec/views/products/index.html.erb_spec.rb @@ -0,0 +1,37 @@ +require 'rails_helper' + +RSpec.describe "products/index", type: :view do + before(:each) do + assign(:products, [ + Product.create!( + :name => "Name", + :price => 1, + :user_id => 2, + :photo_url => "Photo Url", + :stock => 3, + :description => "Description", + :active => false + ), + Product.create!( + :name => "Name", + :price => 1, + :user_id => 2, + :photo_url => "Photo Url", + :stock => 3, + :description => "Description", + :active => false + ) + ]) + end + + it "renders a list of products" do + render + assert_select "tr>td", :text => "Name".to_s, :count => 2 + assert_select "tr>td", :text => 1.to_s, :count => 2 + assert_select "tr>td", :text => 2.to_s, :count => 2 + assert_select "tr>td", :text => "Photo Url".to_s, :count => 2 + assert_select "tr>td", :text => 3.to_s, :count => 2 + assert_select "tr>td", :text => "Description".to_s, :count => 2 + assert_select "tr>td", :text => false.to_s, :count => 2 + end +end diff --git a/spec/views/products/new.html.erb_spec.rb b/spec/views/products/new.html.erb_spec.rb new file mode 100644 index 0000000000..93f6984b91 --- /dev/null +++ b/spec/views/products/new.html.erb_spec.rb @@ -0,0 +1,36 @@ +require 'rails_helper' + +RSpec.describe "products/new", type: :view do + before(:each) do + assign(:product, Product.new( + :name => "MyString", + :price => 1, + :user_id => 1, + :photo_url => "MyString", + :stock => 1, + :description => "MyString", + :active => false + )) + end + + it "renders new product form" do + render + + assert_select "form[action=?][method=?]", products_path, "post" do + + assert_select "input#product_name[name=?]", "product[name]" + + assert_select "input#product_price[name=?]", "product[price]" + + assert_select "input#product_user_id[name=?]", "product[user_id]" + + assert_select "input#product_photo_url[name=?]", "product[photo_url]" + + assert_select "input#product_stock[name=?]", "product[stock]" + + assert_select "input#product_description[name=?]", "product[description]" + + assert_select "input#product_active[name=?]", "product[active]" + end + end +end diff --git a/spec/views/products/show.html.erb_spec.rb b/spec/views/products/show.html.erb_spec.rb new file mode 100644 index 0000000000..99469c9e23 --- /dev/null +++ b/spec/views/products/show.html.erb_spec.rb @@ -0,0 +1,26 @@ +require 'rails_helper' + +RSpec.describe "products/show", type: :view do + before(:each) do + @product = assign(:product, Product.create!( + :name => "Name", + :price => 1, + :user_id => 2, + :photo_url => "Photo Url", + :stock => 3, + :description => "Description", + :active => false + )) + end + + it "renders attributes in

" do + render + expect(rendered).to match(/Name/) + expect(rendered).to match(/1/) + expect(rendered).to match(/2/) + expect(rendered).to match(/Photo Url/) + expect(rendered).to match(/3/) + expect(rendered).to match(/Description/) + expect(rendered).to match(/false/) + end +end From fe0020fce55d2089800578fffa9be89c3cd8a202 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 8 Dec 2015 12:03:49 -0800 Subject: [PATCH 003/299] create order scaffold --- app/assets/javascripts/orders.coffee | 3 + app/assets/stylesheets/orders.scss | 3 + app/controllers/orders_controller.rb | 74 ++++++++++ app/helpers/orders_helper.rb | 2 + app/models/order.rb | 2 + app/views/orders/_form.html.erb | 53 +++++++ app/views/orders/edit.html.erb | 6 + app/views/orders/index.html.erb | 43 ++++++ app/views/orders/index.json.jbuilder | 4 + app/views/orders/new.html.erb | 5 + app/views/orders/show.html.erb | 49 +++++++ app/views/orders/show.json.jbuilder | 1 + config/routes.rb | 1 + db/migrate/20151208200141_create_orders.rb | 17 +++ spec/controllers/orders_controller_spec.rb | 159 +++++++++++++++++++++ spec/helpers/orders_helper_spec.rb | 15 ++ spec/models/order_spec.rb | 5 + spec/requests/orders_spec.rb | 10 ++ spec/routing/orders_routing_spec.rb | 39 +++++ spec/views/orders/edit.html.erb_spec.rb | 39 +++++ spec/views/orders/index.html.erb_spec.rb | 40 ++++++ spec/views/orders/new.html.erb_spec.rb | 39 +++++ spec/views/orders/show.html.erb_spec.rb | 28 ++++ 23 files changed, 637 insertions(+) create mode 100644 app/assets/javascripts/orders.coffee create mode 100644 app/assets/stylesheets/orders.scss create mode 100644 app/controllers/orders_controller.rb create mode 100644 app/helpers/orders_helper.rb create mode 100644 app/models/order.rb create mode 100644 app/views/orders/_form.html.erb create mode 100644 app/views/orders/edit.html.erb create mode 100644 app/views/orders/index.html.erb create mode 100644 app/views/orders/index.json.jbuilder create mode 100644 app/views/orders/new.html.erb create mode 100644 app/views/orders/show.html.erb create mode 100644 app/views/orders/show.json.jbuilder create mode 100644 db/migrate/20151208200141_create_orders.rb create mode 100644 spec/controllers/orders_controller_spec.rb create mode 100644 spec/helpers/orders_helper_spec.rb create mode 100644 spec/models/order_spec.rb create mode 100644 spec/requests/orders_spec.rb create mode 100644 spec/routing/orders_routing_spec.rb create mode 100644 spec/views/orders/edit.html.erb_spec.rb create mode 100644 spec/views/orders/index.html.erb_spec.rb create mode 100644 spec/views/orders/new.html.erb_spec.rb create mode 100644 spec/views/orders/show.html.erb_spec.rb diff --git a/app/assets/javascripts/orders.coffee b/app/assets/javascripts/orders.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/orders.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/orders.scss b/app/assets/stylesheets/orders.scss new file mode 100644 index 0000000000..741506954d --- /dev/null +++ b/app/assets/stylesheets/orders.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Orders 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/orders_controller.rb b/app/controllers/orders_controller.rb new file mode 100644 index 0000000000..1480125d8e --- /dev/null +++ b/app/controllers/orders_controller.rb @@ -0,0 +1,74 @@ +class OrdersController < ApplicationController + before_action :set_order, only: [:show, :edit, :update, :destroy] + + # GET /orders + # GET /orders.json + def index + @orders = Order.all + end + + # GET /orders/1 + # GET /orders/1.json + def show + end + + # GET /orders/new + def new + @order = Order.new + end + + # GET /orders/1/edit + def edit + end + + # POST /orders + # POST /orders.json + def create + @order = Order.new(order_params) + + respond_to do |format| + if @order.save + format.html { redirect_to @order, notice: 'Order was successfully created.' } + format.json { render :show, status: :created, location: @order } + else + format.html { render :new } + format.json { render json: @order.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /orders/1 + # PATCH/PUT /orders/1.json + def update + respond_to do |format| + if @order.update(order_params) + format.html { redirect_to @order, notice: 'Order was successfully updated.' } + format.json { render :show, status: :ok, location: @order } + else + format.html { render :edit } + format.json { render json: @order.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /orders/1 + # DELETE /orders/1.json + def destroy + @order.destroy + respond_to do |format| + format.html { redirect_to orders_url, notice: 'Order was successfully destroyed.' } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_order + @order = Order.find(params[:id]) + end + + # Never trust parameters from the scary internet, only allow the white list through. + def order_params + params.require(:order).permit(:email, :street, :city, :state, :zip, :cc_num, :cc_exp, :cc_cvv, :cc_name) + end +end diff --git a/app/helpers/orders_helper.rb b/app/helpers/orders_helper.rb new file mode 100644 index 0000000000..443227fd48 --- /dev/null +++ b/app/helpers/orders_helper.rb @@ -0,0 +1,2 @@ +module OrdersHelper +end diff --git a/app/models/order.rb b/app/models/order.rb new file mode 100644 index 0000000000..0bcb15832b --- /dev/null +++ b/app/models/order.rb @@ -0,0 +1,2 @@ +class Order < ActiveRecord::Base +end diff --git a/app/views/orders/_form.html.erb b/app/views/orders/_form.html.erb new file mode 100644 index 0000000000..bb9519ad22 --- /dev/null +++ b/app/views/orders/_form.html.erb @@ -0,0 +1,53 @@ +<%= form_for(@order) do |f| %> + <% if @order.errors.any? %> +

+

<%= pluralize(@order.errors.count, "error") %> prohibited this order from being saved:

+ + +
+ <% end %> + +
+ <%= f.label :email %>
+ <%= f.text_field :email %> +
+
+ <%= f.label :street %>
+ <%= f.text_field :street %> +
+
+ <%= f.label :city %>
+ <%= f.text_field :city %> +
+
+ <%= f.label :state %>
+ <%= f.text_field :state %> +
+
+ <%= f.label :zip %>
+ <%= f.text_field :zip %> +
+
+ <%= f.label :cc_num %>
+ <%= f.text_field :cc_num %> +
+
+ <%= f.label :cc_exp %>
+ <%= f.date_select :cc_exp %> +
+
+ <%= f.label :cc_cvv %>
+ <%= f.number_field :cc_cvv %> +
+
+ <%= f.label :cc_name %>
+ <%= f.text_field :cc_name %> +
+
+ <%= f.submit %> +
+<% end %> diff --git a/app/views/orders/edit.html.erb b/app/views/orders/edit.html.erb new file mode 100644 index 0000000000..c621bd2ac5 --- /dev/null +++ b/app/views/orders/edit.html.erb @@ -0,0 +1,6 @@ +

Editing Order

+ +<%= render 'form' %> + +<%= link_to 'Show', @order %> | +<%= link_to 'Back', orders_path %> diff --git a/app/views/orders/index.html.erb b/app/views/orders/index.html.erb new file mode 100644 index 0000000000..74a155cf74 --- /dev/null +++ b/app/views/orders/index.html.erb @@ -0,0 +1,43 @@ +

<%= notice %>

+ +

Listing Orders

+ + + + + + + + + + + + + + + + + + + <% @orders.each do |order| %> + + + + + + + + + + + + + + + <% end %> + +
EmailStreetCityStateZipCc numCc expCc cvvCc name
<%= order.email %><%= order.street %><%= order.city %><%= order.state %><%= order.zip %><%= order.cc_num %><%= order.cc_exp %><%= order.cc_cvv %><%= order.cc_name %><%= link_to 'Show', order %><%= link_to 'Edit', edit_order_path(order) %><%= link_to 'Destroy', order, method: :delete, data: { confirm: 'Are you sure?' } %>
+ +
+ +<%= link_to 'New Order', new_order_path %> diff --git a/app/views/orders/index.json.jbuilder b/app/views/orders/index.json.jbuilder new file mode 100644 index 0000000000..d7ea427621 --- /dev/null +++ b/app/views/orders/index.json.jbuilder @@ -0,0 +1,4 @@ +json.array!(@orders) do |order| + json.extract! order, :id, :email, :street, :city, :state, :zip, :cc_num, :cc_exp, :cc_cvv, :cc_name + json.url order_url(order, format: :json) +end diff --git a/app/views/orders/new.html.erb b/app/views/orders/new.html.erb new file mode 100644 index 0000000000..a7214a026a --- /dev/null +++ b/app/views/orders/new.html.erb @@ -0,0 +1,5 @@ +

New Order

+ +<%= render 'form' %> + +<%= link_to 'Back', orders_path %> diff --git a/app/views/orders/show.html.erb b/app/views/orders/show.html.erb new file mode 100644 index 0000000000..3c72eac73f --- /dev/null +++ b/app/views/orders/show.html.erb @@ -0,0 +1,49 @@ +

<%= notice %>

+ +

+ Email: + <%= @order.email %> +

+ +

+ Street: + <%= @order.street %> +

+ +

+ City: + <%= @order.city %> +

+ +

+ State: + <%= @order.state %> +

+ +

+ Zip: + <%= @order.zip %> +

+ +

+ Cc num: + <%= @order.cc_num %> +

+ +

+ Cc exp: + <%= @order.cc_exp %> +

+ +

+ Cc cvv: + <%= @order.cc_cvv %> +

+ +

+ Cc name: + <%= @order.cc_name %> +

+ +<%= link_to 'Edit', edit_order_path(@order) %> | +<%= link_to 'Back', orders_path %> diff --git a/app/views/orders/show.json.jbuilder b/app/views/orders/show.json.jbuilder new file mode 100644 index 0000000000..486eceb4db --- /dev/null +++ b/app/views/orders/show.json.jbuilder @@ -0,0 +1 @@ +json.extract! @order, :id, :email, :street, :city, :state, :zip, :cc_num, :cc_exp, :cc_cvv, :cc_name, :created_at, :updated_at diff --git a/config/routes.rb b/config/routes.rb index 3cfaf1cded..a18d6be141 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,5 @@ Rails.application.routes.draw do + resources :orders resources :users # The priority is based upon order of creation: first created -> highest priority. # See how all your routes lay out with "rake routes". diff --git a/db/migrate/20151208200141_create_orders.rb b/db/migrate/20151208200141_create_orders.rb new file mode 100644 index 0000000000..21d39a1f94 --- /dev/null +++ b/db/migrate/20151208200141_create_orders.rb @@ -0,0 +1,17 @@ +class CreateOrders < ActiveRecord::Migration + def change + create_table :orders do |t| + t.string :email + t.string :street + t.string :city + t.string :state + t.string :zip + t.string :cc_num + t.date :cc_exp + t.integer :cc_cvv + t.string :cc_name + + t.timestamps null: false + end + end +end diff --git a/spec/controllers/orders_controller_spec.rb b/spec/controllers/orders_controller_spec.rb new file mode 100644 index 0000000000..0c9b109e05 --- /dev/null +++ b/spec/controllers/orders_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 OrdersController, type: :controller do + + # This should return the minimal set of attributes required to create a valid + # Order. As you add validations to Order, be sure to + # adjust the attributes here as well. + let(:valid_attributes) { + skip("Add a hash of attributes valid for your model") + } + + let(:invalid_attributes) { + skip("Add a hash of attributes invalid for your model") + } + + # 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 + # OrdersController. Be sure to keep this updated too. + let(:valid_session) { {} } + + describe "GET #index" do + it "assigns all orders as @orders" do + order = Order.create! valid_attributes + get :index, {}, valid_session + expect(assigns(:orders)).to eq([order]) + end + end + + describe "GET #show" do + it "assigns the requested order as @order" do + order = Order.create! valid_attributes + get :show, {:id => order.to_param}, valid_session + expect(assigns(:order)).to eq(order) + end + end + + describe "GET #new" do + it "assigns a new order as @order" do + get :new, {}, valid_session + expect(assigns(:order)).to be_a_new(Order) + end + end + + describe "GET #edit" do + it "assigns the requested order as @order" do + order = Order.create! valid_attributes + get :edit, {:id => order.to_param}, valid_session + expect(assigns(:order)).to eq(order) + end + end + + describe "POST #create" do + context "with valid params" do + it "creates a new Order" do + expect { + post :create, {:order => valid_attributes}, valid_session + }.to change(Order, :count).by(1) + end + + it "assigns a newly created order as @order" do + post :create, {:order => valid_attributes}, valid_session + expect(assigns(:order)).to be_a(Order) + expect(assigns(:order)).to be_persisted + end + + it "redirects to the created order" do + post :create, {:order => valid_attributes}, valid_session + expect(response).to redirect_to(Order.last) + end + end + + context "with invalid params" do + it "assigns a newly created but unsaved order as @order" do + post :create, {:order => invalid_attributes}, valid_session + expect(assigns(:order)).to be_a_new(Order) + end + + it "re-renders the 'new' template" do + post :create, {:order => invalid_attributes}, valid_session + expect(response).to render_template("new") + end + end + end + + describe "PUT #update" do + context "with valid params" do + let(:new_attributes) { + skip("Add a hash of attributes valid for your model") + } + + it "updates the requested order" do + order = Order.create! valid_attributes + put :update, {:id => order.to_param, :order => new_attributes}, valid_session + order.reload + skip("Add assertions for updated state") + end + + it "assigns the requested order as @order" do + order = Order.create! valid_attributes + put :update, {:id => order.to_param, :order => valid_attributes}, valid_session + expect(assigns(:order)).to eq(order) + end + + it "redirects to the order" do + order = Order.create! valid_attributes + put :update, {:id => order.to_param, :order => valid_attributes}, valid_session + expect(response).to redirect_to(order) + end + end + + context "with invalid params" do + it "assigns the order as @order" do + order = Order.create! valid_attributes + put :update, {:id => order.to_param, :order => invalid_attributes}, valid_session + expect(assigns(:order)).to eq(order) + end + + it "re-renders the 'edit' template" do + order = Order.create! valid_attributes + put :update, {:id => order.to_param, :order => invalid_attributes}, valid_session + expect(response).to render_template("edit") + end + end + end + + describe "DELETE #destroy" do + it "destroys the requested order" do + order = Order.create! valid_attributes + expect { + delete :destroy, {:id => order.to_param}, valid_session + }.to change(Order, :count).by(-1) + end + + it "redirects to the orders list" do + order = Order.create! valid_attributes + delete :destroy, {:id => order.to_param}, valid_session + expect(response).to redirect_to(orders_url) + end + end + +end diff --git a/spec/helpers/orders_helper_spec.rb b/spec/helpers/orders_helper_spec.rb new file mode 100644 index 0000000000..6ba135076e --- /dev/null +++ b/spec/helpers/orders_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the OrdersHelper. For example: +# +# describe OrdersHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe OrdersHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/order_spec.rb b/spec/models/order_spec.rb new file mode 100644 index 0000000000..f48229a01b --- /dev/null +++ b/spec/models/order_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Order, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/requests/orders_spec.rb b/spec/requests/orders_spec.rb new file mode 100644 index 0000000000..72550885ca --- /dev/null +++ b/spec/requests/orders_spec.rb @@ -0,0 +1,10 @@ +require 'rails_helper' + +RSpec.describe "Orders", type: :request do + describe "GET /orders" do + it "works! (now write some real specs)" do + get orders_path + expect(response).to have_http_status(200) + end + end +end diff --git a/spec/routing/orders_routing_spec.rb b/spec/routing/orders_routing_spec.rb new file mode 100644 index 0000000000..2e44550636 --- /dev/null +++ b/spec/routing/orders_routing_spec.rb @@ -0,0 +1,39 @@ +require "rails_helper" + +RSpec.describe OrdersController, type: :routing do + describe "routing" do + + it "routes to #index" do + expect(:get => "/orders").to route_to("orders#index") + end + + it "routes to #new" do + expect(:get => "/orders/new").to route_to("orders#new") + end + + it "routes to #show" do + expect(:get => "/orders/1").to route_to("orders#show", :id => "1") + end + + it "routes to #edit" do + expect(:get => "/orders/1/edit").to route_to("orders#edit", :id => "1") + end + + it "routes to #create" do + expect(:post => "/orders").to route_to("orders#create") + end + + it "routes to #update via PUT" do + expect(:put => "/orders/1").to route_to("orders#update", :id => "1") + end + + it "routes to #update via PATCH" do + expect(:patch => "/orders/1").to route_to("orders#update", :id => "1") + end + + it "routes to #destroy" do + expect(:delete => "/orders/1").to route_to("orders#destroy", :id => "1") + end + + end +end diff --git a/spec/views/orders/edit.html.erb_spec.rb b/spec/views/orders/edit.html.erb_spec.rb new file mode 100644 index 0000000000..00a9bd18a5 --- /dev/null +++ b/spec/views/orders/edit.html.erb_spec.rb @@ -0,0 +1,39 @@ +require 'rails_helper' + +RSpec.describe "orders/edit", type: :view do + before(:each) do + @order = assign(:order, Order.create!( + :email => "MyString", + :street => "MyString", + :city => "MyString", + :state => "MyString", + :zip => "MyString", + :cc_num => "MyString", + :cc_cvv => 1, + :cc_name => "MyString" + )) + end + + it "renders the edit order form" do + render + + assert_select "form[action=?][method=?]", order_path(@order), "post" do + + assert_select "input#order_email[name=?]", "order[email]" + + assert_select "input#order_street[name=?]", "order[street]" + + assert_select "input#order_city[name=?]", "order[city]" + + assert_select "input#order_state[name=?]", "order[state]" + + assert_select "input#order_zip[name=?]", "order[zip]" + + assert_select "input#order_cc_num[name=?]", "order[cc_num]" + + assert_select "input#order_cc_cvv[name=?]", "order[cc_cvv]" + + assert_select "input#order_cc_name[name=?]", "order[cc_name]" + end + end +end diff --git a/spec/views/orders/index.html.erb_spec.rb b/spec/views/orders/index.html.erb_spec.rb new file mode 100644 index 0000000000..a38f782137 --- /dev/null +++ b/spec/views/orders/index.html.erb_spec.rb @@ -0,0 +1,40 @@ +require 'rails_helper' + +RSpec.describe "orders/index", type: :view do + before(:each) do + assign(:orders, [ + Order.create!( + :email => "Email", + :street => "Street", + :city => "City", + :state => "State", + :zip => "Zip", + :cc_num => "Cc Num", + :cc_cvv => 1, + :cc_name => "Cc Name" + ), + Order.create!( + :email => "Email", + :street => "Street", + :city => "City", + :state => "State", + :zip => "Zip", + :cc_num => "Cc Num", + :cc_cvv => 1, + :cc_name => "Cc Name" + ) + ]) + end + + it "renders a list of orders" do + render + assert_select "tr>td", :text => "Email".to_s, :count => 2 + assert_select "tr>td", :text => "Street".to_s, :count => 2 + assert_select "tr>td", :text => "City".to_s, :count => 2 + assert_select "tr>td", :text => "State".to_s, :count => 2 + assert_select "tr>td", :text => "Zip".to_s, :count => 2 + assert_select "tr>td", :text => "Cc Num".to_s, :count => 2 + assert_select "tr>td", :text => 1.to_s, :count => 2 + assert_select "tr>td", :text => "Cc Name".to_s, :count => 2 + end +end diff --git a/spec/views/orders/new.html.erb_spec.rb b/spec/views/orders/new.html.erb_spec.rb new file mode 100644 index 0000000000..2b1083d95b --- /dev/null +++ b/spec/views/orders/new.html.erb_spec.rb @@ -0,0 +1,39 @@ +require 'rails_helper' + +RSpec.describe "orders/new", type: :view do + before(:each) do + assign(:order, Order.new( + :email => "MyString", + :street => "MyString", + :city => "MyString", + :state => "MyString", + :zip => "MyString", + :cc_num => "MyString", + :cc_cvv => 1, + :cc_name => "MyString" + )) + end + + it "renders new order form" do + render + + assert_select "form[action=?][method=?]", orders_path, "post" do + + assert_select "input#order_email[name=?]", "order[email]" + + assert_select "input#order_street[name=?]", "order[street]" + + assert_select "input#order_city[name=?]", "order[city]" + + assert_select "input#order_state[name=?]", "order[state]" + + assert_select "input#order_zip[name=?]", "order[zip]" + + assert_select "input#order_cc_num[name=?]", "order[cc_num]" + + assert_select "input#order_cc_cvv[name=?]", "order[cc_cvv]" + + assert_select "input#order_cc_name[name=?]", "order[cc_name]" + end + end +end diff --git a/spec/views/orders/show.html.erb_spec.rb b/spec/views/orders/show.html.erb_spec.rb new file mode 100644 index 0000000000..34affa4524 --- /dev/null +++ b/spec/views/orders/show.html.erb_spec.rb @@ -0,0 +1,28 @@ +require 'rails_helper' + +RSpec.describe "orders/show", type: :view do + before(:each) do + @order = assign(:order, Order.create!( + :email => "Email", + :street => "Street", + :city => "City", + :state => "State", + :zip => "Zip", + :cc_num => "Cc Num", + :cc_cvv => 1, + :cc_name => "Cc Name" + )) + end + + it "renders attributes in

" do + render + expect(rendered).to match(/Email/) + expect(rendered).to match(/Street/) + expect(rendered).to match(/City/) + expect(rendered).to match(/State/) + expect(rendered).to match(/Zip/) + expect(rendered).to match(/Cc Num/) + expect(rendered).to match(/1/) + expect(rendered).to match(/Cc Name/) + end +end From 5457f5b1f8d5209901eff75d9ff7ac53a59bbcb5 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 8 Dec 2015 12:10:07 -0800 Subject: [PATCH 004/299] create welcome controller --- app/assets/javascripts/welcome.coffee | 3 +++ app/assets/stylesheets/welcome.scss | 3 +++ app/controllers/welcome_controller.rb | 4 ++++ app/helpers/welcome_helper.rb | 2 ++ app/views/welcome/index.html.erb | 2 ++ config/routes.rb | 2 ++ spec/controllers/welcome_controller_spec.rb | 12 ++++++++++++ spec/helpers/welcome_helper_spec.rb | 15 +++++++++++++++ spec/views/welcome/index.html.erb_spec.rb | 5 +++++ 9 files changed, 48 insertions(+) create mode 100644 app/assets/javascripts/welcome.coffee create mode 100644 app/assets/stylesheets/welcome.scss create mode 100644 app/controllers/welcome_controller.rb create mode 100644 app/helpers/welcome_helper.rb create mode 100644 app/views/welcome/index.html.erb create mode 100644 spec/controllers/welcome_controller_spec.rb create mode 100644 spec/helpers/welcome_helper_spec.rb create mode 100644 spec/views/welcome/index.html.erb_spec.rb diff --git a/app/assets/javascripts/welcome.coffee b/app/assets/javascripts/welcome.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/welcome.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/welcome.scss b/app/assets/stylesheets/welcome.scss new file mode 100644 index 0000000000..77ce11a740 --- /dev/null +++ b/app/assets/stylesheets/welcome.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the welcome 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/welcome_controller.rb b/app/controllers/welcome_controller.rb new file mode 100644 index 0000000000..f9b859b9c9 --- /dev/null +++ b/app/controllers/welcome_controller.rb @@ -0,0 +1,4 @@ +class WelcomeController < ApplicationController + def index + end +end diff --git a/app/helpers/welcome_helper.rb b/app/helpers/welcome_helper.rb new file mode 100644 index 0000000000..eeead45fc9 --- /dev/null +++ b/app/helpers/welcome_helper.rb @@ -0,0 +1,2 @@ +module WelcomeHelper +end diff --git a/app/views/welcome/index.html.erb b/app/views/welcome/index.html.erb new file mode 100644 index 0000000000..0a01a01efe --- /dev/null +++ b/app/views/welcome/index.html.erb @@ -0,0 +1,2 @@ +

Welcome#index

+

Find me in app/views/welcome/index.html.erb

diff --git a/config/routes.rb b/config/routes.rb index 0ec272a5bf..182a1d074f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,6 @@ Rails.application.routes.draw do + root 'welcome/index' + resources :orders resources :products resources :categories diff --git a/spec/controllers/welcome_controller_spec.rb b/spec/controllers/welcome_controller_spec.rb new file mode 100644 index 0000000000..133f9e71ec --- /dev/null +++ b/spec/controllers/welcome_controller_spec.rb @@ -0,0 +1,12 @@ +require 'rails_helper' + +RSpec.describe WelcomeController, type: :controller do + + describe "GET #index" do + it "returns http success" do + get :index + expect(response).to have_http_status(:success) + end + end + +end diff --git a/spec/helpers/welcome_helper_spec.rb b/spec/helpers/welcome_helper_spec.rb new file mode 100644 index 0000000000..a899852950 --- /dev/null +++ b/spec/helpers/welcome_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the WelcomeHelper. For example: +# +# describe WelcomeHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe WelcomeHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/welcome/index.html.erb_spec.rb b/spec/views/welcome/index.html.erb_spec.rb new file mode 100644 index 0000000000..226835cead --- /dev/null +++ b/spec/views/welcome/index.html.erb_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe "welcome/index.html.erb", type: :view do + pending "add some examples to (or delete) #{__FILE__}" +end From 6d04ac9fc464458776fded804a04a5b28fe8c286 Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 8 Dec 2015 12:10:31 -0800 Subject: [PATCH 005/299] Add OrderItem model --- app/assets/javascripts/order_items.coffee | 3 + app/assets/stylesheets/order_items.scss | 3 + app/controllers/order_items_controller.rb | 74 ++++++++ app/helpers/order_items_helper.rb | 2 + app/models/order_item.rb | 2 + app/views/order_items/_form.html.erb | 29 ++++ app/views/order_items/edit.html.erb | 6 + app/views/order_items/index.html.erb | 31 ++++ app/views/order_items/index.json.jbuilder | 4 + app/views/order_items/new.html.erb | 5 + app/views/order_items/show.html.erb | 19 +++ app/views/order_items/show.json.jbuilder | 1 + config/routes.rb | 1 + .../20151208201017_create_order_items.rb | 11 ++ .../order_items_controller_spec.rb | 159 ++++++++++++++++++ spec/helpers/order_items_helper_spec.rb | 15 ++ spec/models/order_item_spec.rb | 5 + spec/requests/order_items_spec.rb | 10 ++ spec/routing/order_items_routing_spec.rb | 39 +++++ spec/views/order_items/edit.html.erb_spec.rb | 24 +++ spec/views/order_items/index.html.erb_spec.rb | 25 +++ spec/views/order_items/new.html.erb_spec.rb | 24 +++ spec/views/order_items/show.html.erb_spec.rb | 18 ++ 23 files changed, 510 insertions(+) create mode 100644 app/assets/javascripts/order_items.coffee create mode 100644 app/assets/stylesheets/order_items.scss create mode 100644 app/controllers/order_items_controller.rb create mode 100644 app/helpers/order_items_helper.rb create mode 100644 app/models/order_item.rb create mode 100644 app/views/order_items/_form.html.erb create mode 100644 app/views/order_items/edit.html.erb create mode 100644 app/views/order_items/index.html.erb create mode 100644 app/views/order_items/index.json.jbuilder create mode 100644 app/views/order_items/new.html.erb create mode 100644 app/views/order_items/show.html.erb create mode 100644 app/views/order_items/show.json.jbuilder create mode 100644 db/migrate/20151208201017_create_order_items.rb create mode 100644 spec/controllers/order_items_controller_spec.rb create mode 100644 spec/helpers/order_items_helper_spec.rb create mode 100644 spec/models/order_item_spec.rb create mode 100644 spec/requests/order_items_spec.rb create mode 100644 spec/routing/order_items_routing_spec.rb create mode 100644 spec/views/order_items/edit.html.erb_spec.rb create mode 100644 spec/views/order_items/index.html.erb_spec.rb create mode 100644 spec/views/order_items/new.html.erb_spec.rb create mode 100644 spec/views/order_items/show.html.erb_spec.rb diff --git a/app/assets/javascripts/order_items.coffee b/app/assets/javascripts/order_items.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/order_items.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/order_items.scss b/app/assets/stylesheets/order_items.scss new file mode 100644 index 0000000000..584862de9b --- /dev/null +++ b/app/assets/stylesheets/order_items.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the OrderItems 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/order_items_controller.rb b/app/controllers/order_items_controller.rb new file mode 100644 index 0000000000..7220417f8c --- /dev/null +++ b/app/controllers/order_items_controller.rb @@ -0,0 +1,74 @@ +class OrderItemsController < ApplicationController + before_action :set_order_item, only: [:show, :edit, :update, :destroy] + + # GET /order_items + # GET /order_items.json + def index + @order_items = OrderItem.all + end + + # GET /order_items/1 + # GET /order_items/1.json + def show + end + + # GET /order_items/new + def new + @order_item = OrderItem.new + end + + # GET /order_items/1/edit + def edit + end + + # POST /order_items + # POST /order_items.json + def create + @order_item = OrderItem.new(order_item_params) + + respond_to do |format| + if @order_item.save + format.html { redirect_to @order_item, notice: 'Order item was successfully created.' } + format.json { render :show, status: :created, location: @order_item } + else + format.html { render :new } + format.json { render json: @order_item.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /order_items/1 + # PATCH/PUT /order_items/1.json + def update + respond_to do |format| + if @order_item.update(order_item_params) + format.html { redirect_to @order_item, notice: 'Order item was successfully updated.' } + format.json { render :show, status: :ok, location: @order_item } + else + format.html { render :edit } + format.json { render json: @order_item.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /order_items/1 + # DELETE /order_items/1.json + def destroy + @order_item.destroy + respond_to do |format| + format.html { redirect_to order_items_url, notice: 'Order item was successfully destroyed.' } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_order_item + @order_item = OrderItem.find(params[:id]) + end + + # Never trust parameters from the scary internet, only allow the white list through. + def order_item_params + params.require(:order_item).permit(:product_id, :order_id, :quantity) + end +end diff --git a/app/helpers/order_items_helper.rb b/app/helpers/order_items_helper.rb new file mode 100644 index 0000000000..e197528ae1 --- /dev/null +++ b/app/helpers/order_items_helper.rb @@ -0,0 +1,2 @@ +module OrderItemsHelper +end diff --git a/app/models/order_item.rb b/app/models/order_item.rb new file mode 100644 index 0000000000..7d3194a569 --- /dev/null +++ b/app/models/order_item.rb @@ -0,0 +1,2 @@ +class OrderItem < ActiveRecord::Base +end diff --git a/app/views/order_items/_form.html.erb b/app/views/order_items/_form.html.erb new file mode 100644 index 0000000000..643a8acd7d --- /dev/null +++ b/app/views/order_items/_form.html.erb @@ -0,0 +1,29 @@ +<%= form_for(@order_item) do |f| %> + <% if @order_item.errors.any? %> +
+

<%= pluralize(@order_item.errors.count, "error") %> prohibited this order_item from being saved:

+ +
    + <% @order_item.errors.full_messages.each do |message| %> +
  • <%= message %>
  • + <% end %> +
+
+ <% end %> + +
+ <%= f.label :product_id %>
+ <%= f.number_field :product_id %> +
+
+ <%= f.label :order_id %>
+ <%= f.number_field :order_id %> +
+
+ <%= f.label :quantity %>
+ <%= f.number_field :quantity %> +
+
+ <%= f.submit %> +
+<% end %> diff --git a/app/views/order_items/edit.html.erb b/app/views/order_items/edit.html.erb new file mode 100644 index 0000000000..1ed327d538 --- /dev/null +++ b/app/views/order_items/edit.html.erb @@ -0,0 +1,6 @@ +

Editing Order Item

+ +<%= render 'form' %> + +<%= link_to 'Show', @order_item %> | +<%= link_to 'Back', order_items_path %> diff --git a/app/views/order_items/index.html.erb b/app/views/order_items/index.html.erb new file mode 100644 index 0000000000..59f8f7b9fa --- /dev/null +++ b/app/views/order_items/index.html.erb @@ -0,0 +1,31 @@ +

<%= notice %>

+ +

Listing Order Items

+ + + + + + + + + + + + + <% @order_items.each do |order_item| %> + + + + + + + + + <% end %> + +
ProductOrderQuantity
<%= order_item.product_id %><%= order_item.order_id %><%= order_item.quantity %><%= link_to 'Show', order_item %><%= link_to 'Edit', edit_order_item_path(order_item) %><%= link_to 'Destroy', order_item, method: :delete, data: { confirm: 'Are you sure?' } %>
+ +
+ +<%= link_to 'New Order item', new_order_item_path %> diff --git a/app/views/order_items/index.json.jbuilder b/app/views/order_items/index.json.jbuilder new file mode 100644 index 0000000000..6f91220668 --- /dev/null +++ b/app/views/order_items/index.json.jbuilder @@ -0,0 +1,4 @@ +json.array!(@order_items) do |order_item| + json.extract! order_item, :id, :product_id, :order_id, :quantity + json.url order_item_url(order_item, format: :json) +end diff --git a/app/views/order_items/new.html.erb b/app/views/order_items/new.html.erb new file mode 100644 index 0000000000..47a30cc411 --- /dev/null +++ b/app/views/order_items/new.html.erb @@ -0,0 +1,5 @@ +

New Order Item

+ +<%= render 'form' %> + +<%= link_to 'Back', order_items_path %> diff --git a/app/views/order_items/show.html.erb b/app/views/order_items/show.html.erb new file mode 100644 index 0000000000..da52746e2a --- /dev/null +++ b/app/views/order_items/show.html.erb @@ -0,0 +1,19 @@ +

<%= notice %>

+ +

+ Product: + <%= @order_item.product_id %> +

+ +

+ Order: + <%= @order_item.order_id %> +

+ +

+ Quantity: + <%= @order_item.quantity %> +

+ +<%= link_to 'Edit', edit_order_item_path(@order_item) %> | +<%= link_to 'Back', order_items_path %> diff --git a/app/views/order_items/show.json.jbuilder b/app/views/order_items/show.json.jbuilder new file mode 100644 index 0000000000..d69cf5e2d3 --- /dev/null +++ b/app/views/order_items/show.json.jbuilder @@ -0,0 +1 @@ +json.extract! @order_item, :id, :product_id, :order_id, :quantity, :created_at, :updated_at diff --git a/config/routes.rb b/config/routes.rb index 0ec272a5bf..aab32f28f5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,5 @@ Rails.application.routes.draw do + resources :order_items resources :orders resources :products resources :categories diff --git a/db/migrate/20151208201017_create_order_items.rb b/db/migrate/20151208201017_create_order_items.rb new file mode 100644 index 0000000000..fef23e6dab --- /dev/null +++ b/db/migrate/20151208201017_create_order_items.rb @@ -0,0 +1,11 @@ +class CreateOrderItems < ActiveRecord::Migration + def change + create_table :order_items do |t| + t.integer :product_id + t.integer :order_id + t.integer :quantity + + t.timestamps null: false + end + end +end diff --git a/spec/controllers/order_items_controller_spec.rb b/spec/controllers/order_items_controller_spec.rb new file mode 100644 index 0000000000..e931a11594 --- /dev/null +++ b/spec/controllers/order_items_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 OrderItemsController, type: :controller do + + # This should return the minimal set of attributes required to create a valid + # OrderItem. As you add validations to OrderItem, be sure to + # adjust the attributes here as well. + let(:valid_attributes) { + skip("Add a hash of attributes valid for your model") + } + + let(:invalid_attributes) { + skip("Add a hash of attributes invalid for your model") + } + + # 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 + # OrderItemsController. Be sure to keep this updated too. + let(:valid_session) { {} } + + describe "GET #index" do + it "assigns all order_items as @order_items" do + order_item = OrderItem.create! valid_attributes + get :index, {}, valid_session + expect(assigns(:order_items)).to eq([order_item]) + end + end + + describe "GET #show" do + it "assigns the requested order_item as @order_item" do + order_item = OrderItem.create! valid_attributes + get :show, {:id => order_item.to_param}, valid_session + expect(assigns(:order_item)).to eq(order_item) + end + end + + describe "GET #new" do + it "assigns a new order_item as @order_item" do + get :new, {}, valid_session + expect(assigns(:order_item)).to be_a_new(OrderItem) + end + end + + describe "GET #edit" do + it "assigns the requested order_item as @order_item" do + order_item = OrderItem.create! valid_attributes + get :edit, {:id => order_item.to_param}, valid_session + expect(assigns(:order_item)).to eq(order_item) + end + end + + describe "POST #create" do + context "with valid params" do + it "creates a new OrderItem" do + expect { + post :create, {:order_item => valid_attributes}, valid_session + }.to change(OrderItem, :count).by(1) + end + + it "assigns a newly created order_item as @order_item" do + post :create, {:order_item => valid_attributes}, valid_session + expect(assigns(:order_item)).to be_a(OrderItem) + expect(assigns(:order_item)).to be_persisted + end + + it "redirects to the created order_item" do + post :create, {:order_item => valid_attributes}, valid_session + expect(response).to redirect_to(OrderItem.last) + end + end + + context "with invalid params" do + it "assigns a newly created but unsaved order_item as @order_item" do + post :create, {:order_item => invalid_attributes}, valid_session + expect(assigns(:order_item)).to be_a_new(OrderItem) + end + + it "re-renders the 'new' template" do + post :create, {:order_item => invalid_attributes}, valid_session + expect(response).to render_template("new") + end + end + end + + describe "PUT #update" do + context "with valid params" do + let(:new_attributes) { + skip("Add a hash of attributes valid for your model") + } + + it "updates the requested order_item" do + order_item = OrderItem.create! valid_attributes + put :update, {:id => order_item.to_param, :order_item => new_attributes}, valid_session + order_item.reload + skip("Add assertions for updated state") + end + + it "assigns the requested order_item as @order_item" do + order_item = OrderItem.create! valid_attributes + put :update, {:id => order_item.to_param, :order_item => valid_attributes}, valid_session + expect(assigns(:order_item)).to eq(order_item) + end + + it "redirects to the order_item" do + order_item = OrderItem.create! valid_attributes + put :update, {:id => order_item.to_param, :order_item => valid_attributes}, valid_session + expect(response).to redirect_to(order_item) + end + end + + context "with invalid params" do + it "assigns the order_item as @order_item" do + order_item = OrderItem.create! valid_attributes + put :update, {:id => order_item.to_param, :order_item => invalid_attributes}, valid_session + expect(assigns(:order_item)).to eq(order_item) + end + + it "re-renders the 'edit' template" do + order_item = OrderItem.create! valid_attributes + put :update, {:id => order_item.to_param, :order_item => invalid_attributes}, valid_session + expect(response).to render_template("edit") + end + end + end + + describe "DELETE #destroy" do + it "destroys the requested order_item" do + order_item = OrderItem.create! valid_attributes + expect { + delete :destroy, {:id => order_item.to_param}, valid_session + }.to change(OrderItem, :count).by(-1) + end + + it "redirects to the order_items list" do + order_item = OrderItem.create! valid_attributes + delete :destroy, {:id => order_item.to_param}, valid_session + expect(response).to redirect_to(order_items_url) + end + end + +end diff --git a/spec/helpers/order_items_helper_spec.rb b/spec/helpers/order_items_helper_spec.rb new file mode 100644 index 0000000000..21e1eaf98b --- /dev/null +++ b/spec/helpers/order_items_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the OrderItemsHelper. For example: +# +# describe OrderItemsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe OrderItemsHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/order_item_spec.rb b/spec/models/order_item_spec.rb new file mode 100644 index 0000000000..3b4241223a --- /dev/null +++ b/spec/models/order_item_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe OrderItem, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/requests/order_items_spec.rb b/spec/requests/order_items_spec.rb new file mode 100644 index 0000000000..effbfdda3e --- /dev/null +++ b/spec/requests/order_items_spec.rb @@ -0,0 +1,10 @@ +require 'rails_helper' + +RSpec.describe "OrderItems", type: :request do + describe "GET /order_items" do + it "works! (now write some real specs)" do + get order_items_path + expect(response).to have_http_status(200) + end + end +end diff --git a/spec/routing/order_items_routing_spec.rb b/spec/routing/order_items_routing_spec.rb new file mode 100644 index 0000000000..d6c77511f8 --- /dev/null +++ b/spec/routing/order_items_routing_spec.rb @@ -0,0 +1,39 @@ +require "rails_helper" + +RSpec.describe OrderItemsController, type: :routing do + describe "routing" do + + it "routes to #index" do + expect(:get => "/order_items").to route_to("order_items#index") + end + + it "routes to #new" do + expect(:get => "/order_items/new").to route_to("order_items#new") + end + + it "routes to #show" do + expect(:get => "/order_items/1").to route_to("order_items#show", :id => "1") + end + + it "routes to #edit" do + expect(:get => "/order_items/1/edit").to route_to("order_items#edit", :id => "1") + end + + it "routes to #create" do + expect(:post => "/order_items").to route_to("order_items#create") + end + + it "routes to #update via PUT" do + expect(:put => "/order_items/1").to route_to("order_items#update", :id => "1") + end + + it "routes to #update via PATCH" do + expect(:patch => "/order_items/1").to route_to("order_items#update", :id => "1") + end + + it "routes to #destroy" do + expect(:delete => "/order_items/1").to route_to("order_items#destroy", :id => "1") + end + + end +end diff --git a/spec/views/order_items/edit.html.erb_spec.rb b/spec/views/order_items/edit.html.erb_spec.rb new file mode 100644 index 0000000000..6ec53a1ccb --- /dev/null +++ b/spec/views/order_items/edit.html.erb_spec.rb @@ -0,0 +1,24 @@ +require 'rails_helper' + +RSpec.describe "order_items/edit", type: :view do + before(:each) do + @order_item = assign(:order_item, OrderItem.create!( + :product_id => 1, + :order_id => 1, + :quantity => 1 + )) + end + + it "renders the edit order_item form" do + render + + assert_select "form[action=?][method=?]", order_item_path(@order_item), "post" do + + assert_select "input#order_item_product_id[name=?]", "order_item[product_id]" + + assert_select "input#order_item_order_id[name=?]", "order_item[order_id]" + + assert_select "input#order_item_quantity[name=?]", "order_item[quantity]" + end + end +end diff --git a/spec/views/order_items/index.html.erb_spec.rb b/spec/views/order_items/index.html.erb_spec.rb new file mode 100644 index 0000000000..16fc3caf0a --- /dev/null +++ b/spec/views/order_items/index.html.erb_spec.rb @@ -0,0 +1,25 @@ +require 'rails_helper' + +RSpec.describe "order_items/index", type: :view do + before(:each) do + assign(:order_items, [ + OrderItem.create!( + :product_id => 1, + :order_id => 2, + :quantity => 3 + ), + OrderItem.create!( + :product_id => 1, + :order_id => 2, + :quantity => 3 + ) + ]) + end + + it "renders a list of order_items" do + render + assert_select "tr>td", :text => 1.to_s, :count => 2 + assert_select "tr>td", :text => 2.to_s, :count => 2 + assert_select "tr>td", :text => 3.to_s, :count => 2 + end +end diff --git a/spec/views/order_items/new.html.erb_spec.rb b/spec/views/order_items/new.html.erb_spec.rb new file mode 100644 index 0000000000..01edddf94d --- /dev/null +++ b/spec/views/order_items/new.html.erb_spec.rb @@ -0,0 +1,24 @@ +require 'rails_helper' + +RSpec.describe "order_items/new", type: :view do + before(:each) do + assign(:order_item, OrderItem.new( + :product_id => 1, + :order_id => 1, + :quantity => 1 + )) + end + + it "renders new order_item form" do + render + + assert_select "form[action=?][method=?]", order_items_path, "post" do + + assert_select "input#order_item_product_id[name=?]", "order_item[product_id]" + + assert_select "input#order_item_order_id[name=?]", "order_item[order_id]" + + assert_select "input#order_item_quantity[name=?]", "order_item[quantity]" + end + end +end diff --git a/spec/views/order_items/show.html.erb_spec.rb b/spec/views/order_items/show.html.erb_spec.rb new file mode 100644 index 0000000000..3a637b0a0d --- /dev/null +++ b/spec/views/order_items/show.html.erb_spec.rb @@ -0,0 +1,18 @@ +require 'rails_helper' + +RSpec.describe "order_items/show", type: :view do + before(:each) do + @order_item = assign(:order_item, OrderItem.create!( + :product_id => 1, + :order_id => 2, + :quantity => 3 + )) + end + + it "renders attributes in

" do + render + expect(rendered).to match(/1/) + expect(rendered).to match(/2/) + expect(rendered).to match(/3/) + end +end From 851e7b0391d3bf4fdfcbd3421b90fa85c0ffcad0 Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 8 Dec 2015 12:14:48 -0800 Subject: [PATCH 006/299] create review model --- app/assets/javascripts/reviews.coffee | 3 + app/assets/stylesheets/reviews.scss | 3 + app/controllers/reviews_controller.rb | 74 +++++++++ app/helpers/reviews_helper.rb | 2 + app/models/review.rb | 2 + app/views/reviews/_form.html.erb | 29 ++++ app/views/reviews/edit.html.erb | 6 + app/views/reviews/index.html.erb | 31 ++++ app/views/reviews/index.json.jbuilder | 4 + app/views/reviews/new.html.erb | 5 + app/views/reviews/show.html.erb | 19 +++ app/views/reviews/show.json.jbuilder | 1 + config/routes.rb | 1 + db/migrate/20151208201429_create_reviews.rb | 11 ++ spec/controllers/reviews_controller_spec.rb | 159 ++++++++++++++++++++ spec/helpers/reviews_helper_spec.rb | 15 ++ spec/models/review_spec.rb | 5 + spec/requests/reviews_spec.rb | 10 ++ spec/routing/reviews_routing_spec.rb | 39 +++++ spec/views/reviews/edit.html.erb_spec.rb | 24 +++ spec/views/reviews/index.html.erb_spec.rb | 25 +++ spec/views/reviews/new.html.erb_spec.rb | 24 +++ spec/views/reviews/show.html.erb_spec.rb | 18 +++ 23 files changed, 510 insertions(+) create mode 100644 app/assets/javascripts/reviews.coffee create mode 100644 app/assets/stylesheets/reviews.scss create mode 100644 app/controllers/reviews_controller.rb create mode 100644 app/helpers/reviews_helper.rb create mode 100644 app/models/review.rb create mode 100644 app/views/reviews/_form.html.erb create mode 100644 app/views/reviews/edit.html.erb create mode 100644 app/views/reviews/index.html.erb create mode 100644 app/views/reviews/index.json.jbuilder create mode 100644 app/views/reviews/new.html.erb create mode 100644 app/views/reviews/show.html.erb create mode 100644 app/views/reviews/show.json.jbuilder create mode 100644 db/migrate/20151208201429_create_reviews.rb create mode 100644 spec/controllers/reviews_controller_spec.rb create mode 100644 spec/helpers/reviews_helper_spec.rb create mode 100644 spec/models/review_spec.rb create mode 100644 spec/requests/reviews_spec.rb create mode 100644 spec/routing/reviews_routing_spec.rb create mode 100644 spec/views/reviews/edit.html.erb_spec.rb create mode 100644 spec/views/reviews/index.html.erb_spec.rb create mode 100644 spec/views/reviews/new.html.erb_spec.rb create mode 100644 spec/views/reviews/show.html.erb_spec.rb diff --git a/app/assets/javascripts/reviews.coffee b/app/assets/javascripts/reviews.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/reviews.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/reviews.scss b/app/assets/stylesheets/reviews.scss new file mode 100644 index 0000000000..11bbb12cd5 --- /dev/null +++ b/app/assets/stylesheets/reviews.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Reviews 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/reviews_controller.rb b/app/controllers/reviews_controller.rb new file mode 100644 index 0000000000..95cad92e44 --- /dev/null +++ b/app/controllers/reviews_controller.rb @@ -0,0 +1,74 @@ +class ReviewsController < ApplicationController + before_action :set_review, only: [:show, :edit, :update, :destroy] + + # GET /reviews + # GET /reviews.json + def index + @reviews = Review.all + end + + # GET /reviews/1 + # GET /reviews/1.json + def show + end + + # GET /reviews/new + def new + @review = Review.new + end + + # GET /reviews/1/edit + def edit + end + + # POST /reviews + # POST /reviews.json + def create + @review = Review.new(review_params) + + respond_to do |format| + if @review.save + format.html { redirect_to @review, notice: 'Review was successfully created.' } + format.json { render :show, status: :created, location: @review } + else + format.html { render :new } + format.json { render json: @review.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /reviews/1 + # PATCH/PUT /reviews/1.json + def update + respond_to do |format| + if @review.update(review_params) + format.html { redirect_to @review, notice: 'Review was successfully updated.' } + format.json { render :show, status: :ok, location: @review } + else + format.html { render :edit } + format.json { render json: @review.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /reviews/1 + # DELETE /reviews/1.json + def destroy + @review.destroy + respond_to do |format| + format.html { redirect_to reviews_url, notice: 'Review was successfully destroyed.' } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_review + @review = Review.find(params[:id]) + end + + # Never trust parameters from the scary internet, only allow the white list through. + def review_params + params.require(:review).permit(:rating, :product_id, :description) + end +end diff --git a/app/helpers/reviews_helper.rb b/app/helpers/reviews_helper.rb new file mode 100644 index 0000000000..682b7b1abc --- /dev/null +++ b/app/helpers/reviews_helper.rb @@ -0,0 +1,2 @@ +module ReviewsHelper +end diff --git a/app/models/review.rb b/app/models/review.rb new file mode 100644 index 0000000000..2fbac34e64 --- /dev/null +++ b/app/models/review.rb @@ -0,0 +1,2 @@ +class Review < ActiveRecord::Base +end diff --git a/app/views/reviews/_form.html.erb b/app/views/reviews/_form.html.erb new file mode 100644 index 0000000000..0523df239f --- /dev/null +++ b/app/views/reviews/_form.html.erb @@ -0,0 +1,29 @@ +<%= form_for(@review) do |f| %> + <% if @review.errors.any? %> +

+

<%= pluralize(@review.errors.count, "error") %> prohibited this review from being saved:

+ +
    + <% @review.errors.full_messages.each do |message| %> +
  • <%= message %>
  • + <% end %> +
+
+ <% end %> + +
+ <%= f.label :rating %>
+ <%= f.number_field :rating %> +
+
+ <%= f.label :product_id %>
+ <%= f.number_field :product_id %> +
+
+ <%= f.label :description %>
+ <%= f.text_field :description %> +
+
+ <%= f.submit %> +
+<% end %> diff --git a/app/views/reviews/edit.html.erb b/app/views/reviews/edit.html.erb new file mode 100644 index 0000000000..ad7d5091c8 --- /dev/null +++ b/app/views/reviews/edit.html.erb @@ -0,0 +1,6 @@ +

Editing Review

+ +<%= render 'form' %> + +<%= link_to 'Show', @review %> | +<%= link_to 'Back', reviews_path %> diff --git a/app/views/reviews/index.html.erb b/app/views/reviews/index.html.erb new file mode 100644 index 0000000000..0f61d6c7f5 --- /dev/null +++ b/app/views/reviews/index.html.erb @@ -0,0 +1,31 @@ +

<%= notice %>

+ +

Listing Reviews

+ + + + + + + + + + + + + <% @reviews.each do |review| %> + + + + + + + + + <% end %> + +
RatingProductDescription
<%= review.rating %><%= review.product_id %><%= review.description %><%= link_to 'Show', review %><%= link_to 'Edit', edit_review_path(review) %><%= link_to 'Destroy', review, method: :delete, data: { confirm: 'Are you sure?' } %>
+ +
+ +<%= link_to 'New Review', new_review_path %> diff --git a/app/views/reviews/index.json.jbuilder b/app/views/reviews/index.json.jbuilder new file mode 100644 index 0000000000..eef6b1832e --- /dev/null +++ b/app/views/reviews/index.json.jbuilder @@ -0,0 +1,4 @@ +json.array!(@reviews) do |review| + json.extract! review, :id, :rating, :product_id, :description + json.url review_url(review, format: :json) +end diff --git a/app/views/reviews/new.html.erb b/app/views/reviews/new.html.erb new file mode 100644 index 0000000000..3a07bf51f6 --- /dev/null +++ b/app/views/reviews/new.html.erb @@ -0,0 +1,5 @@ +

New Review

+ +<%= render 'form' %> + +<%= link_to 'Back', reviews_path %> diff --git a/app/views/reviews/show.html.erb b/app/views/reviews/show.html.erb new file mode 100644 index 0000000000..26672e35f0 --- /dev/null +++ b/app/views/reviews/show.html.erb @@ -0,0 +1,19 @@ +

<%= notice %>

+ +

+ Rating: + <%= @review.rating %> +

+ +

+ Product: + <%= @review.product_id %> +

+ +

+ Description: + <%= @review.description %> +

+ +<%= link_to 'Edit', edit_review_path(@review) %> | +<%= link_to 'Back', reviews_path %> diff --git a/app/views/reviews/show.json.jbuilder b/app/views/reviews/show.json.jbuilder new file mode 100644 index 0000000000..5574aeb6cd --- /dev/null +++ b/app/views/reviews/show.json.jbuilder @@ -0,0 +1 @@ +json.extract! @review, :id, :rating, :product_id, :description, :created_at, :updated_at diff --git a/config/routes.rb b/config/routes.rb index 512fac7ef4..9d20d7bf40 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,5 @@ Rails.application.routes.draw do + resources :reviews resources :order_items root 'welcome/index' resources :orders diff --git a/db/migrate/20151208201429_create_reviews.rb b/db/migrate/20151208201429_create_reviews.rb new file mode 100644 index 0000000000..cedec96536 --- /dev/null +++ b/db/migrate/20151208201429_create_reviews.rb @@ -0,0 +1,11 @@ +class CreateReviews < ActiveRecord::Migration + def change + create_table :reviews do |t| + t.integer :rating + t.integer :product_id + t.string :description + + t.timestamps null: false + end + end +end diff --git a/spec/controllers/reviews_controller_spec.rb b/spec/controllers/reviews_controller_spec.rb new file mode 100644 index 0000000000..2be4c113c4 --- /dev/null +++ b/spec/controllers/reviews_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 ReviewsController, type: :controller do + + # This should return the minimal set of attributes required to create a valid + # Review. As you add validations to Review, be sure to + # adjust the attributes here as well. + let(:valid_attributes) { + skip("Add a hash of attributes valid for your model") + } + + let(:invalid_attributes) { + skip("Add a hash of attributes invalid for your model") + } + + # 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 + # ReviewsController. Be sure to keep this updated too. + let(:valid_session) { {} } + + describe "GET #index" do + it "assigns all reviews as @reviews" do + review = Review.create! valid_attributes + get :index, {}, valid_session + expect(assigns(:reviews)).to eq([review]) + end + end + + describe "GET #show" do + it "assigns the requested review as @review" do + review = Review.create! valid_attributes + get :show, {:id => review.to_param}, valid_session + expect(assigns(:review)).to eq(review) + end + end + + describe "GET #new" do + it "assigns a new review as @review" do + get :new, {}, valid_session + expect(assigns(:review)).to be_a_new(Review) + end + end + + describe "GET #edit" do + it "assigns the requested review as @review" do + review = Review.create! valid_attributes + get :edit, {:id => review.to_param}, valid_session + expect(assigns(:review)).to eq(review) + end + end + + describe "POST #create" do + context "with valid params" do + it "creates a new Review" do + expect { + post :create, {:review => valid_attributes}, valid_session + }.to change(Review, :count).by(1) + end + + it "assigns a newly created review as @review" do + post :create, {:review => valid_attributes}, valid_session + expect(assigns(:review)).to be_a(Review) + expect(assigns(:review)).to be_persisted + end + + it "redirects to the created review" do + post :create, {:review => valid_attributes}, valid_session + expect(response).to redirect_to(Review.last) + end + end + + context "with invalid params" do + it "assigns a newly created but unsaved review as @review" do + post :create, {:review => invalid_attributes}, valid_session + expect(assigns(:review)).to be_a_new(Review) + end + + it "re-renders the 'new' template" do + post :create, {:review => invalid_attributes}, valid_session + expect(response).to render_template("new") + end + end + end + + describe "PUT #update" do + context "with valid params" do + let(:new_attributes) { + skip("Add a hash of attributes valid for your model") + } + + it "updates the requested review" do + review = Review.create! valid_attributes + put :update, {:id => review.to_param, :review => new_attributes}, valid_session + review.reload + skip("Add assertions for updated state") + end + + it "assigns the requested review as @review" do + review = Review.create! valid_attributes + put :update, {:id => review.to_param, :review => valid_attributes}, valid_session + expect(assigns(:review)).to eq(review) + end + + it "redirects to the review" do + review = Review.create! valid_attributes + put :update, {:id => review.to_param, :review => valid_attributes}, valid_session + expect(response).to redirect_to(review) + end + end + + context "with invalid params" do + it "assigns the review as @review" do + review = Review.create! valid_attributes + put :update, {:id => review.to_param, :review => invalid_attributes}, valid_session + expect(assigns(:review)).to eq(review) + end + + it "re-renders the 'edit' template" do + review = Review.create! valid_attributes + put :update, {:id => review.to_param, :review => invalid_attributes}, valid_session + expect(response).to render_template("edit") + end + end + end + + describe "DELETE #destroy" do + it "destroys the requested review" do + review = Review.create! valid_attributes + expect { + delete :destroy, {:id => review.to_param}, valid_session + }.to change(Review, :count).by(-1) + end + + it "redirects to the reviews list" do + review = Review.create! valid_attributes + delete :destroy, {:id => review.to_param}, valid_session + expect(response).to redirect_to(reviews_url) + end + end + +end diff --git a/spec/helpers/reviews_helper_spec.rb b/spec/helpers/reviews_helper_spec.rb new file mode 100644 index 0000000000..7139af6bbf --- /dev/null +++ b/spec/helpers/reviews_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the ReviewsHelper. For example: +# +# describe ReviewsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe ReviewsHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/review_spec.rb b/spec/models/review_spec.rb new file mode 100644 index 0000000000..8fc758155e --- /dev/null +++ b/spec/models/review_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Review, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/requests/reviews_spec.rb b/spec/requests/reviews_spec.rb new file mode 100644 index 0000000000..6e4dbbd063 --- /dev/null +++ b/spec/requests/reviews_spec.rb @@ -0,0 +1,10 @@ +require 'rails_helper' + +RSpec.describe "Reviews", type: :request do + describe "GET /reviews" do + it "works! (now write some real specs)" do + get reviews_path + expect(response).to have_http_status(200) + end + end +end diff --git a/spec/routing/reviews_routing_spec.rb b/spec/routing/reviews_routing_spec.rb new file mode 100644 index 0000000000..24fa514090 --- /dev/null +++ b/spec/routing/reviews_routing_spec.rb @@ -0,0 +1,39 @@ +require "rails_helper" + +RSpec.describe ReviewsController, type: :routing do + describe "routing" do + + it "routes to #index" do + expect(:get => "/reviews").to route_to("reviews#index") + end + + it "routes to #new" do + expect(:get => "/reviews/new").to route_to("reviews#new") + end + + it "routes to #show" do + expect(:get => "/reviews/1").to route_to("reviews#show", :id => "1") + end + + it "routes to #edit" do + expect(:get => "/reviews/1/edit").to route_to("reviews#edit", :id => "1") + end + + it "routes to #create" do + expect(:post => "/reviews").to route_to("reviews#create") + end + + it "routes to #update via PUT" do + expect(:put => "/reviews/1").to route_to("reviews#update", :id => "1") + end + + it "routes to #update via PATCH" do + expect(:patch => "/reviews/1").to route_to("reviews#update", :id => "1") + end + + it "routes to #destroy" do + expect(:delete => "/reviews/1").to route_to("reviews#destroy", :id => "1") + end + + end +end diff --git a/spec/views/reviews/edit.html.erb_spec.rb b/spec/views/reviews/edit.html.erb_spec.rb new file mode 100644 index 0000000000..06339bace4 --- /dev/null +++ b/spec/views/reviews/edit.html.erb_spec.rb @@ -0,0 +1,24 @@ +require 'rails_helper' + +RSpec.describe "reviews/edit", type: :view do + before(:each) do + @review = assign(:review, Review.create!( + :rating => 1, + :product_id => 1, + :description => "MyString" + )) + end + + it "renders the edit review form" do + render + + assert_select "form[action=?][method=?]", review_path(@review), "post" do + + assert_select "input#review_rating[name=?]", "review[rating]" + + assert_select "input#review_product_id[name=?]", "review[product_id]" + + assert_select "input#review_description[name=?]", "review[description]" + end + end +end diff --git a/spec/views/reviews/index.html.erb_spec.rb b/spec/views/reviews/index.html.erb_spec.rb new file mode 100644 index 0000000000..df5100e8fb --- /dev/null +++ b/spec/views/reviews/index.html.erb_spec.rb @@ -0,0 +1,25 @@ +require 'rails_helper' + +RSpec.describe "reviews/index", type: :view do + before(:each) do + assign(:reviews, [ + Review.create!( + :rating => 1, + :product_id => 2, + :description => "Description" + ), + Review.create!( + :rating => 1, + :product_id => 2, + :description => "Description" + ) + ]) + end + + it "renders a list of reviews" do + render + assert_select "tr>td", :text => 1.to_s, :count => 2 + assert_select "tr>td", :text => 2.to_s, :count => 2 + assert_select "tr>td", :text => "Description".to_s, :count => 2 + end +end diff --git a/spec/views/reviews/new.html.erb_spec.rb b/spec/views/reviews/new.html.erb_spec.rb new file mode 100644 index 0000000000..b813c6abfe --- /dev/null +++ b/spec/views/reviews/new.html.erb_spec.rb @@ -0,0 +1,24 @@ +require 'rails_helper' + +RSpec.describe "reviews/new", type: :view do + before(:each) do + assign(:review, Review.new( + :rating => 1, + :product_id => 1, + :description => "MyString" + )) + end + + it "renders new review form" do + render + + assert_select "form[action=?][method=?]", reviews_path, "post" do + + assert_select "input#review_rating[name=?]", "review[rating]" + + assert_select "input#review_product_id[name=?]", "review[product_id]" + + assert_select "input#review_description[name=?]", "review[description]" + end + end +end diff --git a/spec/views/reviews/show.html.erb_spec.rb b/spec/views/reviews/show.html.erb_spec.rb new file mode 100644 index 0000000000..ac833ca8cd --- /dev/null +++ b/spec/views/reviews/show.html.erb_spec.rb @@ -0,0 +1,18 @@ +require 'rails_helper' + +RSpec.describe "reviews/show", type: :view do + before(:each) do + @review = assign(:review, Review.create!( + :rating => 1, + :product_id => 2, + :description => "Description" + )) + end + + it "renders attributes in

" do + render + expect(rendered).to match(/1/) + expect(rendered).to match(/2/) + expect(rendered).to match(/Description/) + end +end From d50b18050ac543c1e64b3289777567145083623b Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 8 Dec 2015 12:19:48 -0800 Subject: [PATCH 007/299] create sessions controller --- app/assets/javascripts/sessions.coffee | 3 +++ app/assets/stylesheets/sessions.scss | 3 +++ app/controllers/sessions_controller.rb | 11 +++++++++++ app/helpers/sessions_helper.rb | 2 ++ app/views/sessions/index.html.erb | 1 + config/routes.rb | 6 +++++- spec/controllers/sessions_controller_spec.rb | 5 +++++ spec/helpers/sessions_helper_spec.rb | 15 +++++++++++++++ 8 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/sessions.coffee create mode 100644 app/assets/stylesheets/sessions.scss create mode 100644 app/controllers/sessions_controller.rb create mode 100644 app/helpers/sessions_helper.rb create mode 100644 app/views/sessions/index.html.erb create mode 100644 spec/controllers/sessions_controller_spec.rb create mode 100644 spec/helpers/sessions_helper_spec.rb diff --git a/app/assets/javascripts/sessions.coffee b/app/assets/javascripts/sessions.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/sessions.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/sessions.scss b/app/assets/stylesheets/sessions.scss new file mode 100644 index 0000000000..7bef9cf826 --- /dev/null +++ b/app/assets/stylesheets/sessions.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the sessions 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/sessions_controller.rb b/app/controllers/sessions_controller.rb new file mode 100644 index 0000000000..1b484ebd90 --- /dev/null +++ b/app/controllers/sessions_controller.rb @@ -0,0 +1,11 @@ +class SessionsController < ApplicationController + + def new + end + + def create + end + + def destroy + end +end diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb new file mode 100644 index 0000000000..309f8b2eb3 --- /dev/null +++ b/app/helpers/sessions_helper.rb @@ -0,0 +1,2 @@ +module SessionsHelper +end diff --git a/app/views/sessions/index.html.erb b/app/views/sessions/index.html.erb new file mode 100644 index 0000000000..1d6c211720 --- /dev/null +++ b/app/views/sessions/index.html.erb @@ -0,0 +1 @@ +

Login page

diff --git a/config/routes.rb b/config/routes.rb index 512fac7ef4..b2aa3482f0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,10 +1,14 @@ Rails.application.routes.draw do - resources :order_items root 'welcome/index' + resources :order_items resources :orders resources :products resources :categories resources :users + + # get 'login/' => 'sessions#new', as: :login + # post 'login/' => 'sessions#create' + # delete 'logout/' => 'sessions#destroy', as: :logout # The priority is based upon order of creation: first created -> highest priority. # See how all your routes lay out with "rake routes". diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb new file mode 100644 index 0000000000..003bededfb --- /dev/null +++ b/spec/controllers/sessions_controller_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe SessionsController, type: :controller do + +end diff --git a/spec/helpers/sessions_helper_spec.rb b/spec/helpers/sessions_helper_spec.rb new file mode 100644 index 0000000000..9484198350 --- /dev/null +++ b/spec/helpers/sessions_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the SessionsHelper. For example: +# +# describe SessionsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe SessionsHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end From 877c8f91a26560eebcc962df4aa6b271c2702df7 Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 8 Dec 2015 12:22:03 -0800 Subject: [PATCH 008/299] fixed routes --- config/routes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/routes.rb b/config/routes.rb index 9d20d7bf40..7ee9abc39c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,7 @@ Rails.application.routes.draw do resources :reviews resources :order_items - root 'welcome/index' + root 'welcome#index' resources :orders resources :products resources :categories From 678fc5746582eacef24b635402eb90d94cfcbf21 Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 8 Dec 2015 12:26:19 -0800 Subject: [PATCH 009/299] configure routes --- config/routes.rb | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index de40492d23..98c9853232 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,13 +1,16 @@ Rails.application.routes.draw do + root 'welcome#index' - resources :reviews - resources :order_items - root 'welcome#index' - resources :order_items - resources :orders - resources :products + resources :categories - resources :users + resources :users do + resources :orders do + resources :order_items + end + resources :products do + resources :reviews + end + end get 'login/' => 'sessions#new', as: :login post 'login/' => 'sessions#create' From 8ab003a9c3d9c6c0b379ae3d7a0222d7f5885237 Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 8 Dec 2015 13:37:27 -0800 Subject: [PATCH 010/299] add has_secure_password to user model --- app/models/user.rb | 1 + db/schema.rb | 73 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 db/schema.rb diff --git a/app/models/user.rb b/app/models/user.rb index 4a57cf079b..40f0705794 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,2 +1,3 @@ class User < ActiveRecord::Base + has_secure_password end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000000..73a0996ab9 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,73 @@ +# encoding: UTF-8 +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema.define(version: 20151208201429) do + + create_table "categories", force: :cascade do |t| + t.string "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "order_items", force: :cascade do |t| + t.integer "product_id" + t.integer "order_id" + t.integer "quantity" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "orders", force: :cascade do |t| + t.string "email" + t.string "street" + t.string "city" + t.string "state" + t.string "zip" + t.string "cc_num" + t.date "cc_exp" + t.integer "cc_cvv" + t.string "cc_name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "products", force: :cascade do |t| + t.string "name" + t.integer "price" + t.integer "user_id" + t.string "photo_url" + t.integer "stock" + t.string "description" + t.boolean "active" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "reviews", force: :cascade do |t| + t.integer "rating" + t.integer "product_id" + t.string "description" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "users", force: :cascade do |t| + t.string "username" + t.string "email" + t.string "password_digest" + t.string "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + +end From 45c7fb98dc8d367dac2a6a6577efa9295d594aaf Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 8 Dec 2015 13:39:58 -0800 Subject: [PATCH 011/299] create relationships between models --- app/models/category.rb | 1 + app/models/order.rb | 1 + app/models/order_item.rb | 2 ++ app/models/product.rb | 4 ++++ app/models/review.rb | 1 + app/models/user.rb | 1 + 6 files changed, 10 insertions(+) diff --git a/app/models/category.rb b/app/models/category.rb index 910a0098c4..7f018cd725 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -1,2 +1,3 @@ class Category < ActiveRecord::Base + has_and_belongs_to_many :products end diff --git a/app/models/order.rb b/app/models/order.rb index 0bcb15832b..e609bc6c09 100644 --- a/app/models/order.rb +++ b/app/models/order.rb @@ -1,2 +1,3 @@ class Order < ActiveRecord::Base + has_many :order_items end diff --git a/app/models/order_item.rb b/app/models/order_item.rb index 7d3194a569..251c4741c0 100644 --- a/app/models/order_item.rb +++ b/app/models/order_item.rb @@ -1,2 +1,4 @@ class OrderItem < ActiveRecord::Base + belongs_to :product + belongs_to :order end diff --git a/app/models/product.rb b/app/models/product.rb index 077a819795..086f9fb937 100644 --- a/app/models/product.rb +++ b/app/models/product.rb @@ -1,2 +1,6 @@ class Product < ActiveRecord::Base + belongs_to :user + has_many :orders + has_many :reviews + has_and_belongs_to_many :categories end diff --git a/app/models/review.rb b/app/models/review.rb index 2fbac34e64..53d7a4885b 100644 --- a/app/models/review.rb +++ b/app/models/review.rb @@ -1,2 +1,3 @@ class Review < ActiveRecord::Base + belongs_to :product end diff --git a/app/models/user.rb b/app/models/user.rb index 4a57cf079b..bb13153c11 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,2 +1,3 @@ class User < ActiveRecord::Base + has_many :products end From 11354ea1a7621997981030ab52e2ba6708972677 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 8 Dec 2015 13:41:03 -0800 Subject: [PATCH 012/299] add end to user model --- app/models/user.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/user.rb b/app/models/user.rb index f0feda7301..6abdff354e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,3 +1,4 @@ class User < ActiveRecord::Base has_many :products has_secure_password +end From 312c06e6ee647dba343d050bac89f6e72525e836 Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 8 Dec 2015 14:04:43 -0800 Subject: [PATCH 013/299] Add user model validations --- app/models/user.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/models/user.rb b/app/models/user.rb index 6abdff354e..a2e3b9fe80 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,4 +1,8 @@ class User < ActiveRecord::Base has_many :products has_secure_password + + validates :username, :email, presence: true + validates :username, :email, uniqueness: true + # Password Confirmation must match Password end From 5890bffac860fabac0325dab43e3fa32460455be Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 8 Dec 2015 14:13:56 -0800 Subject: [PATCH 014/299] Add product model validations --- app/models/product.rb | 4 ++++ app/models/user.rb | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/models/product.rb b/app/models/product.rb index 086f9fb937..1fd6ed1688 100644 --- a/app/models/product.rb +++ b/app/models/product.rb @@ -3,4 +3,8 @@ class Product < ActiveRecord::Base has_many :orders has_many :reviews has_and_belongs_to_many :categories + + validates :name, :price, presence: true + validates :name, uniqueness: true + validates_numericality_of :price, :greater_than => 0 end diff --git a/app/models/user.rb b/app/models/user.rb index a2e3b9fe80..6838d36e4d 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -4,5 +4,4 @@ class User < ActiveRecord::Base validates :username, :email, presence: true validates :username, :email, uniqueness: true - # Password Confirmation must match Password end From 1632b6a65c133325dfda67b88092df78fab38b40 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 8 Dec 2015 14:21:38 -0800 Subject: [PATCH 015/299] add default true to active field in product --- db/migrate/20151208221927_add_default_to_product.rb | 5 +++++ db/schema.rb | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20151208221927_add_default_to_product.rb diff --git a/db/migrate/20151208221927_add_default_to_product.rb b/db/migrate/20151208221927_add_default_to_product.rb new file mode 100644 index 0000000000..5c087d60e3 --- /dev/null +++ b/db/migrate/20151208221927_add_default_to_product.rb @@ -0,0 +1,5 @@ +class AddDefaultToProduct < ActiveRecord::Migration + def change + change_column_default(:products, :active, true) + end +end diff --git a/db/schema.rb b/db/schema.rb index 73a0996ab9..8b04266991 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20151208201429) do +ActiveRecord::Schema.define(version: 20151208221927) do create_table "categories", force: :cascade do |t| t.string "name" @@ -48,9 +48,9 @@ t.string "photo_url" t.integer "stock" t.string "description" - t.boolean "active" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.boolean "active", default: true + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "reviews", force: :cascade do |t| From 996240db467182360126d623a164d1543b87e3d9 Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 8 Dec 2015 14:38:14 -0800 Subject: [PATCH 016/299] add OrderItem model validations --- app/models/order_item.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/models/order_item.rb b/app/models/order_item.rb index 251c4741c0..45debd6788 100644 --- a/app/models/order_item.rb +++ b/app/models/order_item.rb @@ -1,4 +1,8 @@ class OrderItem < ActiveRecord::Base belongs_to :product belongs_to :order + + validates :quantity, presence: true + validates :quantity, numericality: { only_integer: true, greater_than: 0 } + end From f1a695196dd8dd69f5c705c935f43aaf517d962d Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 8 Dec 2015 14:47:41 -0800 Subject: [PATCH 017/299] Add review model validations --- app/models/order_item.rb | 3 +-- app/models/review.rb | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/models/order_item.rb b/app/models/order_item.rb index 45debd6788..35bab80815 100644 --- a/app/models/order_item.rb +++ b/app/models/order_item.rb @@ -3,6 +3,5 @@ class OrderItem < ActiveRecord::Base belongs_to :order validates :quantity, presence: true - validates :quantity, numericality: { only_integer: true, greater_than: 0 } - + validates_numericality_of :quantity, :greater_than => 0 end diff --git a/app/models/review.rb b/app/models/review.rb index 53d7a4885b..2c8380ed4b 100644 --- a/app/models/review.rb +++ b/app/models/review.rb @@ -1,3 +1,6 @@ class Review < ActiveRecord::Base belongs_to :product + + validates :rating, presence: true + validates :rating, numericality: { :greater_than => 0, less_than: 6 } end From a9636719d2c4944d74ed1a113173f382984e56a1 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 8 Dec 2015 14:48:11 -0800 Subject: [PATCH 018/299] create csvs for seeding data --- seeds_csvs/order_items.csv | 76 +++++++++++++++ seeds_csvs/orders.csv | 11 +++ seeds_csvs/products.csv | 56 +++++++++++ seeds_csvs/reviews.csv | 186 +++++++++++++++++++++++++++++++++++++ seeds_csvs/users.csv | 11 +++ 5 files changed, 340 insertions(+) create mode 100644 seeds_csvs/order_items.csv create mode 100644 seeds_csvs/orders.csv create mode 100644 seeds_csvs/products.csv create mode 100644 seeds_csvs/reviews.csv create mode 100644 seeds_csvs/users.csv diff --git a/seeds_csvs/order_items.csv b/seeds_csvs/order_items.csv new file mode 100644 index 0000000000..c2b7ab4e0e --- /dev/null +++ b/seeds_csvs/order_items.csv @@ -0,0 +1,76 @@ +product_id,order_id,quantity +1,1,1 +26,1,7 +35,1,3 +36,1,1 +51,1,7 +3,2,4 +8,2,8 +12,2,2 +14,2,9 +20,2,6 +40,2,5 +54,2,2 +55,2,8 +4,3,4 +8,3,9 +31,3,10 +35,3,6 +45,3,5 +46,3,8 +1,4,1 +6,4,6 +20,4,4 +40,4,5 +48,4,5 +49,4,1 +11,5,7 +47,5,4 +17,6,4 +24,6,5 +29,6,8 +30,6,3 +32,6,7 +33,6,8 +4,7,3 +8,7,4 +10,7,9 +11,7,8 +19,7,2 +12,7,8 +14,7,9 +20,7,6 +23,7,9 +27,7,5 +30,7,7 +32,7,1 +50,7,8 +55,7,1 +11,8,8 +14,8,1 +36,8,4 +43,8,10 +48,8,8 +52,8,2 +54,8,6 +4,9,1 +21,9,4 +24,9,6 +29,9,8 +34,9,10 +37,9,5 +2,10,3 +4,10,3 +6,10,1 +7,10,8 +11,10,9 +13,10,10 +15,10,6 +16,10,2 +22,10,5 +29,10,1 +35,10,9 +39,10,8 +46,10,9 +49,10,6 +55,10,6 diff --git a/seeds_csvs/orders.csv b/seeds_csvs/orders.csv new file mode 100644 index 0000000000..d9b4a5e41c --- /dev/null +++ b/seeds_csvs/orders.csv @@ -0,0 +1,11 @@ +email,street,city,state,zip,cc_num,cc_exp,cc_cvv,cc_name +user1@example.com,1215 4th Ave,Seattle,WA,98161,12345678,,360,User One +user2@example.com,1216 4th Ave,Seattle,WA,98161,12345679,,139,User Two +user3@example.com,1217 4th Ave,Seattle,WA,98161,12345680,,275,User Three +user4@example.com,1218 4th Ave,Seattle,WA,98161,12345681,,842,User Four +user5@example.com,1219 4th Ave,Seattle,WA,98161,12345682,,119,User Five +user6@example.com,1220 4th Ave,Seattle,WA,98161,12345683,,600,User Six +user7@example.com,1221 4th Ave,Seattle,WA,98161,12345684,,858,User Seven +user8@example.com,1222 4th Ave,Seattle,WA,98161,12345685,,858,User Eight +user9@example.com,1223 4th Ave,Seattle,WA,98161,12345686,,844,User Nine +user10@example.com,1224 4th Ave,Seattle,WA,98161,12345687,,930,User Ten diff --git a/seeds_csvs/products.csv b/seeds_csvs/products.csv new file mode 100644 index 0000000000..4bd9542ac7 --- /dev/null +++ b/seeds_csvs/products.csv @@ -0,0 +1,56 @@ +name,price,user_id,photo_url,stock,description,active +Dive Rings,599,1,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",9,Unbreakable rings stand up on the pool bottom for diving games. Set of 4., +Inflatable Water Wheel,3795,1,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,3,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended.", +Shark Goggles,1196,1,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,9,Made using the highest quality materials, +Swimming Fish Pool Toy,1399,1,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,10,, +Water Noodles,1143,1,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,11,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random., +Water Wings,690,1,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,5,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue, +Dive Rings,599,2,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",14,Unbreakable rings stand up on the pool bottom for diving games. Set of 4., +Dive Sticks,395,2,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,4,Sticks stand upright on pool bottom., +Dory Doll,3000,2,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,12,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll", +Inflatable Water Wheel,3795,2,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,1,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended.", +Swimming Fish Pool Toy,1399,2,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,1,, +Toypedo Bandits,615,2,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,11,Glides underwater up to 30 feet, +Water Noodles,1143,2,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,10,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random., +Water Wings,690,2,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,12,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue, +Dive Rings,599,3,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",1,Unbreakable rings stand up on the pool bottom for diving games. Set of 4., +Dive Sticks,395,3,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,8,Sticks stand upright on pool bottom., +Finding Nemo DVD,1996,3,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,1,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination.", +Inflatable Water Wheel,3795,3,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,2,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended.", +Puddle Jumper Life Jacket,1359,3,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,14,For children 30-50 lbs., +Shark Goggles,1196,3,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,15,Made using the highest quality materials, +Swimming Fish Pool Toy,1399,3,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,14,, +Toypedo Bandits,615,3,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,14,Glides underwater up to 30 feet, +Water Noodles,1143,3,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,1,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random., +Water Wings,690,3,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,13,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue, +Dive Sticks,395,4,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,9,Sticks stand upright on pool bottom., +Finding Nemo DVD,1996,4,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,5,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination.", +Inflatable Water Wheel,3795,4,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,5,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended.", +Puddle Jumper Life Jacket,1359,4,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,2,For children 30-50 lbs., +Shark Goggles,1196,4,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,5,Made using the highest quality materials, +Swimming Fish Pool Toy,1399,4,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,3,, +Water Wings,690,4,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,3,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue, +Dive Rings,599,5,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",3,Unbreakable rings stand up on the pool bottom for diving games. Set of 4., +Dory Doll,3000,5,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,6,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll", +Finding Nemo DVD,1996,5,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,1,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination.", +Dory Doll,3000,6,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,14,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll", +Finding Nemo DVD,1996,6,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,9,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination.", +Water Wings,690,6,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,3,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue, +Dive Sticks,395,7,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,4,Sticks stand upright on pool bottom., +Shark Goggles,1196,7,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,8,Made using the highest quality materials, +Toypedo Bandits,615,7,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,5,Glides underwater up to 30 feet, +Water Noodles,1143,7,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,9,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random., +Dive Sticks,395,8,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,14,Sticks stand upright on pool bottom., +Puddle Jumper Life Jacket,1359,8,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,4,For children 30-50 lbs., +Puddle Jumper Life Jacket,1359,9,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,12,For children 30-50 lbs., +Shark Goggles,1196,8,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,14,Made using the highest quality materials, +Toypedo Bandits,615,8,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,12,Glides underwater up to 30 feet, +Dive Rings,599,9,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",4,Unbreakable rings stand up on the pool bottom for diving games. Set of 4., +Dory Doll,3000,9,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,5,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll", +Inflatable Water Wheel,3795,9,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,14,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended.", +Water Noodles,1143,9,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,11,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random., +Dory Doll,3000,10,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,9,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll", +Finding Nemo DVD,1996,10,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,9,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination.", +Puddle Jumper Life Jacket,1359,10,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,4,For children 30-50 lbs., +Swimming Fish Pool Toy,1399,10,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,11,, +Toypedo Bandits,615,10,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,10,Glides underwater up to 30 feet, diff --git a/seeds_csvs/reviews.csv b/seeds_csvs/reviews.csv new file mode 100644 index 0000000000..4242f6f1a6 --- /dev/null +++ b/seeds_csvs/reviews.csv @@ -0,0 +1,186 @@ +rating,product_id,description +5,55, +2,34, +3,14, +4,7, +3,21, +4,3, +5,22, +1,45, +2,54, +1,5, +1,14, +3,26, +1,30, +4,52, +3,46, +2,47, +3,23, +4,8, +5,24, +1,27, +3,10, +5,52, +5,7, +4,24, +2,37, +1,25, +3,53, +3,16, +1,37, +5,38, +5,18, +4,55, +2,23, +3,32, +4,44, +5,52, +3,31, +2,19, +3,11, +5,46, +3,23, +1,45, +3,46, +4,14, +5,35, +2,43, +5,4, +5,27, +5,30, +2,13, +4,49, +4,33, +1,41, +5,10, +2,43, +1,25, +1,48, +3,26, +1,21, +4,7, +2,32, +3,36, +1,31, +5,23, +5,1, +5,48, +5,1, +4,36, +2,23, +1,22, +3,15, +2,35, +5,35, +5,10, +2,4, +3,4, +5,43, +4,38, +1,14, +3,50, +3,7, +1,35, +4,35, +1,32, +4,54, +3,33, +3,36, +3,40, +5,22, +2,37, +3,28, +5,16, +4,37, +2,24, +4,24, +2,48, +5,1, +4,54, +4,1, +3,36, +5,8, +1,50, +2,44, +4,20, +3,14, +1,14, +2,31, +4,14, +1,48, +3,6, +4,14, +5,43, +2,35, +4,6, +5,3, +1,31, +4,35, +5,5, +1,12, +3,51, +4,17, +3,45, +2,53, +2,52, +3,42, +4,19, +2,5, +3,49, +5,53, +2,20, +4,23, +3,28, +4,16, +5,48, +4,1, +3,21, +3,29, +4,53, +1,52, +2,25, +3,55, +1,9, +4,4, +5,32, +1,26, +4,9, +4,55, +2,13, +5,19, +4,35, +2,4, +1,12, +4,47, +4,22, +2,21, +3,49, +5,26, +5,11, +5,51, +3,3, +3,49, +3,54, +5,23, +4,34, +4,51, +1,11, +3,26, +1,44, +5,28, +3,38, +4,51, +3,20, +3,29, +3,15, +3,1, +4,12, +2,7, +1,38, +5,2, +3,21, +2,49, +4,53, +5,11, +2,46, +5,35, diff --git a/seeds_csvs/users.csv b/seeds_csvs/users.csv new file mode 100644 index 0000000000..ed45bc149a --- /dev/null +++ b/seeds_csvs/users.csv @@ -0,0 +1,11 @@ +username,email,password,password_confirmation,name +user1,user1@example.com,zAJeq7zugu,zAJeq7zugu,User One +user2,user2@example.com,breha8uMaF,breha8uMaF,User Two +user3,user3@example.com,tHu5etudru,tHu5etudru,User Three +user4,user4@example.com,pesA7raket,pesA7raket,User Four +user5,user5@example.com,wrucast7sW,wrucast7sW,User Five +user6,user6@example.com,TreSwe6erE,TreSwe6erE,User Six +user7,user7@example.com,PeJaVa7ewr,PeJaVa7ewr,User Seven +user8,user8@example.com,TRu2hutRuf,TRu2hutRuf,User Eight +user9,user9@example.com,tute6Eqagu,tute6Eqagu,User Nine +user10,user10@example.com,Wref8AQeye,Wref8AQeye,User Ten From fa03a086253d15823ef1a27cfa822e3aa32530ea Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 8 Dec 2015 14:57:17 -0800 Subject: [PATCH 019/299] create seed file --- db/seeds.rb | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/db/seeds.rb b/db/seeds.rb index 4edb1e857e..fdebd195a4 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -5,3 +5,30 @@ # # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) # Mayor.create(name: 'Emanuel', city: cities.first) + +require 'csv' + +tables = { + "Order" => './seeds_csvs/orders.csv', + "Product" => './seeds_csvs/products.csv', + "User" => './seeds_csvs/users.csv', + "Review" => './seeds_csvs/reviews.csv', + 'OrderItem' => './seeds_csvs/order_items.csv' + } + + tables.each do |k, v| + data = CSV.read(v, :headers => true, :header_converters => :symbol).map{ |row| row.to_hash } + data.each do |info| + if k == "Order" + Order.create(info) + elsif k == "Product" + Product.create(info) + elsif k == "User" + User.create(info) + elsif k == "Review" + Review.create(info) + elsif k == "OrderItem" + OrderItem.create(info) + end + end + end From 3606b33768b38cf0abdadcfb107c0c65af5a3de5 Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 8 Dec 2015 15:47:13 -0800 Subject: [PATCH 020/299] add order model validations --- app/models/order.rb | 4 ++++ app/models/user.rb | 2 ++ 2 files changed, 6 insertions(+) diff --git a/app/models/order.rb b/app/models/order.rb index e609bc6c09..a9a17594a5 100644 --- a/app/models/order.rb +++ b/app/models/order.rb @@ -1,3 +1,7 @@ class Order < ActiveRecord::Base has_many :order_items + validates_numericality_of :zip, :cc_num, allow_nil: true + validates_length_of :zip, is: 5, allow_nil: true + validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i }, allow_nil: true + end diff --git a/app/models/user.rb b/app/models/user.rb index 6838d36e4d..251f26d9a1 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -4,4 +4,6 @@ class User < ActiveRecord::Base validates :username, :email, presence: true validates :username, :email, uniqueness: true + validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i } + end From bcf094abff1ae4249665bcdb5dfa3007ddfb072a Mon Sep 17 00:00:00 2001 From: Tammy Date: Tue, 8 Dec 2015 15:47:22 -0800 Subject: [PATCH 021/299] making CRUD and views in peogress --- app/controllers/categories_controller.rb | 45 ++++++----------------- app/controllers/order_items_controller.rb | 40 +++----------------- app/views/order_items/_form.html.erb | 8 +--- app/views/order_items/edit.html.erb | 4 +- app/views/order_items/index.html.erb | 6 +-- app/views/order_items/index.json.jbuilder | 4 -- app/views/order_items/new.html.erb | 2 +- app/views/order_items/show.json.jbuilder | 1 - 8 files changed, 25 insertions(+), 85 deletions(-) delete mode 100644 app/views/order_items/index.json.jbuilder delete mode 100644 app/views/order_items/show.json.jbuilder diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb index 363c1cb628..cb09790c0b 100644 --- a/app/controllers/categories_controller.rb +++ b/app/controllers/categories_controller.rb @@ -1,73 +1,50 @@ 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 } + redirect_to categories_path else - format.html { render :new } - format.json { render json: @category.errors, status: :unprocessable_entity } + render "new" 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 + @category.update(category_params) + redirect_to categories_path 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 + redirect_to categories_path 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) end diff --git a/app/controllers/order_items_controller.rb b/app/controllers/order_items_controller.rb index 7220417f8c..01c40f558d 100644 --- a/app/controllers/order_items_controller.rb +++ b/app/controllers/order_items_controller.rb @@ -1,73 +1,45 @@ class OrderItemsController < ApplicationController before_action :set_order_item, only: [:show, :edit, :update, :destroy] - # GET /order_items - # GET /order_items.json def index @order_items = OrderItem.all end - # GET /order_items/1 - # GET /order_items/1.json def show end - # GET /order_items/new def new @order_item = OrderItem.new end - # GET /order_items/1/edit def edit end - # POST /order_items - # POST /order_items.json def create @order_item = OrderItem.new(order_item_params) - - respond_to do |format| if @order_item.save - format.html { redirect_to @order_item, notice: 'Order item was successfully created.' } - format.json { render :show, status: :created, location: @order_item } + redirect_to user_order_order_items_path else - format.html { render :new } - format.json { render json: @order_item.errors, status: :unprocessable_entity } + render "new" end - end end - # PATCH/PUT /order_items/1 - # PATCH/PUT /order_items/1.json def update - respond_to do |format| - if @order_item.update(order_item_params) - format.html { redirect_to @order_item, notice: 'Order item was successfully updated.' } - format.json { render :show, status: :ok, location: @order_item } - else - format.html { render :edit } - format.json { render json: @order_item.errors, status: :unprocessable_entity } - end - end + @order_item.update(order_item_params) + redirect_to user_order_order_items_path end - # DELETE /order_items/1 - # DELETE /order_items/1.json def destroy @order_item.destroy - respond_to do |format| - format.html { redirect_to order_items_url, notice: 'Order item was successfully destroyed.' } - format.json { head :no_content } - end + redirect_to user_order_order_items_path end private - # Use callbacks to share common setup or constraints between actions. + def set_order_item @order_item = OrderItem.find(params[:id]) end - # Never trust parameters from the scary internet, only allow the white list through. def order_item_params params.require(:order_item).permit(:product_id, :order_id, :quantity) end diff --git a/app/views/order_items/_form.html.erb b/app/views/order_items/_form.html.erb index 643a8acd7d..da9bce9fd6 100644 --- a/app/views/order_items/_form.html.erb +++ b/app/views/order_items/_form.html.erb @@ -1,15 +1,11 @@ <%= form_for(@order_item) do |f| %> - <% if @order_item.errors.any? %> -
-

<%= pluralize(@order_item.errors.count, "error") %> prohibited this order_item from being saved:

- +
<%= f.label :product_id %>
diff --git a/app/views/order_items/edit.html.erb b/app/views/order_items/edit.html.erb index 1ed327d538..44f91677ef 100644 --- a/app/views/order_items/edit.html.erb +++ b/app/views/order_items/edit.html.erb @@ -2,5 +2,5 @@ <%= render 'form' %> -<%= link_to 'Show', @order_item %> | -<%= link_to 'Back', order_items_path %> + +<%= link_to 'Back', user_order_order_items_path %> diff --git a/app/views/order_items/index.html.erb b/app/views/order_items/index.html.erb index 59f8f7b9fa..f7494f2d76 100644 --- a/app/views/order_items/index.html.erb +++ b/app/views/order_items/index.html.erb @@ -18,8 +18,8 @@ <%= order_item.product_id %> <%= order_item.order_id %> <%= order_item.quantity %> - <%= link_to 'Show', order_item %> - <%= link_to 'Edit', edit_order_item_path(order_item) %> + <%= link_to 'Show', user_order_order_item_path %> + <%= link_to 'Destroy', order_item, method: :delete, data: { confirm: 'Are you sure?' } %> <% end %> @@ -28,4 +28,4 @@
-<%= link_to 'New Order item', new_order_item_path %> +<%= link_to 'New Order item', new_user_order_order_item_path %> diff --git a/app/views/order_items/index.json.jbuilder b/app/views/order_items/index.json.jbuilder deleted file mode 100644 index 6f91220668..0000000000 --- a/app/views/order_items/index.json.jbuilder +++ /dev/null @@ -1,4 +0,0 @@ -json.array!(@order_items) do |order_item| - json.extract! order_item, :id, :product_id, :order_id, :quantity - json.url order_item_url(order_item, format: :json) -end diff --git a/app/views/order_items/new.html.erb b/app/views/order_items/new.html.erb index 47a30cc411..63acbe7a45 100644 --- a/app/views/order_items/new.html.erb +++ b/app/views/order_items/new.html.erb @@ -2,4 +2,4 @@ <%= render 'form' %> -<%= link_to 'Back', order_items_path %> +<%= link_to 'Back', user_order_order_items_path %> diff --git a/app/views/order_items/show.json.jbuilder b/app/views/order_items/show.json.jbuilder deleted file mode 100644 index d69cf5e2d3..0000000000 --- a/app/views/order_items/show.json.jbuilder +++ /dev/null @@ -1 +0,0 @@ -json.extract! @order_item, :id, :product_id, :order_id, :quantity, :created_at, :updated_at From bd5d95dd83020f96e6dbf590803b3b11163f585c Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 8 Dec 2015 15:57:25 -0800 Subject: [PATCH 022/299] Add photo_url validation to Product model --- app/models/order.rb | 1 - app/models/product.rb | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/order.rb b/app/models/order.rb index a9a17594a5..4b31051be0 100644 --- a/app/models/order.rb +++ b/app/models/order.rb @@ -3,5 +3,4 @@ class Order < ActiveRecord::Base validates_numericality_of :zip, :cc_num, allow_nil: true validates_length_of :zip, is: 5, allow_nil: true validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i }, allow_nil: true - end diff --git a/app/models/product.rb b/app/models/product.rb index 1fd6ed1688..629a357e12 100644 --- a/app/models/product.rb +++ b/app/models/product.rb @@ -7,4 +7,6 @@ class Product < ActiveRecord::Base validates :name, :price, presence: true validates :name, uniqueness: true validates_numericality_of :price, :greater_than => 0 + validates :photo_url, format: {with: /\.(png|jpg)\Z/i}, allow_nil: true + end From 467794bce526a2fd3803ebad03bffff4d09653b3 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 8 Dec 2015 18:01:47 -0800 Subject: [PATCH 023/299] generate rspec files --- .rspec | 2 + spec/rails_helper.rb | 57 +++++++++++++++++++++++++++ spec/spec_helper.rb | 92 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 .rspec create mode 100644 spec/rails_helper.rb create mode 100644 spec/spec_helper.rb diff --git a/.rspec b/.rspec new file mode 100644 index 0000000000..83e16f8044 --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--color +--require spec_helper diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb new file mode 100644 index 0000000000..6f1ab14638 --- /dev/null +++ b/spec/rails_helper.rb @@ -0,0 +1,57 @@ +# This file is copied to spec/ when you run 'rails generate rspec:install' +ENV['RAILS_ENV'] ||= 'test' +require File.expand_path('../../config/environment', __FILE__) +# Prevent database truncation if the environment is production +abort("The Rails environment is running in production mode!") if Rails.env.production? +require 'spec_helper' +require 'rspec/rails' +# Add additional requires below this line. Rails is not loaded until this point! + +# Requires supporting ruby files with custom matchers and macros, etc, in +# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are +# run as spec files by default. This means that files in spec/support that end +# in _spec.rb will both be required and run as specs, causing the specs to be +# run twice. It is recommended that you do not name files matching this glob to +# end with _spec.rb. You can configure this pattern with the --pattern +# option on the command line or in ~/.rspec, .rspec or `.rspec-local`. +# +# The following line is provided for convenience purposes. It has the downside +# of increasing the boot-up time by auto-requiring all files in the support +# directory. Alternatively, in the individual `*_spec.rb` files, manually +# require only the support files necessary. +# +# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } + +# Checks for pending migration and applies them before tests are run. +# If you are not using ActiveRecord, you can remove this line. +ActiveRecord::Migration.maintain_test_schema! + +RSpec.configure do |config| + # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures + config.fixture_path = "#{::Rails.root}/spec/fixtures" + + # If you're not using ActiveRecord, or you'd prefer not to run each of your + # examples within a transaction, remove the following line or assign false + # instead of true. + config.use_transactional_fixtures = true + + # RSpec Rails can automatically mix in different behaviours to your tests + # based on their file location, for example enabling you to call `get` and + # `post` in specs under `spec/controllers`. + # + # You can disable this behaviour by removing the line below, and instead + # explicitly tag your specs with their type, e.g.: + # + # RSpec.describe UsersController, :type => :controller do + # # ... + # end + # + # The different available types are documented in the features, such as in + # https://relishapp.com/rspec/rspec-rails/docs + config.infer_spec_type_from_file_location! + + # Filter lines from Rails gems in backtraces. + config.filter_rails_from_backtrace! + # arbitrary gems may also be filtered via: + # config.filter_gems_from_backtrace("gem name") +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000000..61e27385c3 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,92 @@ +# This file was generated by the `rails generate rspec:install` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# The `.rspec` file also contains a few flags that are not defaults but that +# users commonly want. +# +# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + +# The settings below are suggested to provide a good initial experience +# with RSpec, but feel free to customize to your heart's content. +=begin + # These two settings work together to allow you to limit a spec run + # to individual examples or groups you care about by tagging them with + # `:focus` metadata. When nothing is tagged with `:focus`, all examples + # get run. + config.filter_run :focus + config.run_all_when_everything_filtered = true + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + config.example_status_persistence_file_path = "spec/examples.txt" + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ + # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode + config.disable_monkey_patching! + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = 'doc' + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed +=end +end From f84bc5c0af1770e00d3c2b026d82cdb3ec14b225 Mon Sep 17 00:00:00 2001 From: Tammy Date: Tue, 8 Dec 2015 18:22:47 -0800 Subject: [PATCH 024/299] working in progress for CRUD to work with products and order_item --- app/controllers/users_controller.rb | 35 +++++++--------------------- app/views/order_items/_form.html.erb | 8 ------- app/views/order_items/show.html.erb | 4 ++-- app/views/products/index.html.erb | 2 +- app/views/users/index.json.jbuilder | 4 ---- app/views/users/show.html.erb | 1 + app/views/users/show.json.jbuilder | 1 - 7 files changed, 13 insertions(+), 42 deletions(-) delete mode 100644 app/views/users/index.json.jbuilder delete mode 100644 app/views/users/show.json.jbuilder diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index aafa784bb5..e92452df72 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,73 +1,56 @@ class UsersController < ApplicationController before_action :set_user, only: [:show, :edit, :update, :destroy] - # GET /users - # GET /users.json + def index @users = User.all end - # GET /users/1 - # GET /users/1.json + def show end - # GET /users/new def new @user = User.new end - # GET /users/1/edit + def edit end - # POST /users - # POST /users.json def create @user = User.new(user_params) - - respond_to do |format| - if @user.save - format.html { redirect_to @user, notice: 'User was successfully created.' } - format.json { render :show, status: :created, location: @user } - else - format.html { render :new } - format.json { render json: @user.errors, status: :unprocessable_entity } - end + if @user.save + format.html { redirect_to @user, notice: 'User was successfully created.' } + else + format.html { render :new } end end - # PATCH/PUT /users/1 - # PATCH/PUT /users/1.json def update respond_to do |format| if @user.update(user_params) format.html { redirect_to @user, notice: 'User was successfully updated.' } - format.json { render :show, status: :ok, location: @user } else format.html { render :edit } - format.json { render json: @user.errors, status: :unprocessable_entity } end end end - # DELETE /users/1 - # DELETE /users/1.json def destroy @user.destroy respond_to do |format| format.html { redirect_to users_url, notice: 'User was successfully destroyed.' } - format.json { head :no_content } end end private - # Use callbacks to share common setup or constraints between actions. + def set_user @user = User.find(params[:id]) end - # Never trust parameters from the scary internet, only allow the white list through. + def user_params params.require(:user).permit(:username, :email, :password_digest, :name) end diff --git a/app/views/order_items/_form.html.erb b/app/views/order_items/_form.html.erb index da9bce9fd6..47d9231acc 100644 --- a/app/views/order_items/_form.html.erb +++ b/app/views/order_items/_form.html.erb @@ -1,12 +1,4 @@ <%= form_for(@order_item) do |f| %> - -
<%= f.label :product_id %>
<%= f.number_field :product_id %> diff --git a/app/views/order_items/show.html.erb b/app/views/order_items/show.html.erb index da52746e2a..e49f9e28cd 100644 --- a/app/views/order_items/show.html.erb +++ b/app/views/order_items/show.html.erb @@ -15,5 +15,5 @@ <%= @order_item.quantity %>

-<%= link_to 'Edit', edit_order_item_path(@order_item) %> | -<%= link_to 'Back', order_items_path %> +<%= link_to 'Edit', edit_order_item_path(@order_item, @user, @order) %> | +<%= link_to 'Back', user_order_order_items_path(@user, @order) %> diff --git a/app/views/products/index.html.erb b/app/views/products/index.html.erb index 9f7fe66938..6e96aae578 100644 --- a/app/views/products/index.html.erb +++ b/app/views/products/index.html.erb @@ -26,7 +26,7 @@ <%= product.stock %> <%= product.description %> <%= product.active %> - <%= link_to 'Show', product %> + <%= link_to 'Show', user_product_path(product.id, product.user.id) %> <%= link_to 'Edit', edit_product_path(product) %> <%= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' } %> diff --git a/app/views/users/index.json.jbuilder b/app/views/users/index.json.jbuilder deleted file mode 100644 index 979b67b633..0000000000 --- a/app/views/users/index.json.jbuilder +++ /dev/null @@ -1,4 +0,0 @@ -json.array!(@users) do |user| - json.extract! user, :id, :username, :email, :password_digest, :name - json.url user_url(user, format: :json) -end diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index 7ecbc56eca..a12d61d1d6 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -22,3 +22,4 @@ <%= link_to 'Edit', edit_user_path(@user) %> | <%= link_to 'Back', users_path %> +<%= link_to 'Products', user_products_path(@user) %> diff --git a/app/views/users/show.json.jbuilder b/app/views/users/show.json.jbuilder deleted file mode 100644 index 0b2035bb10..0000000000 --- a/app/views/users/show.json.jbuilder +++ /dev/null @@ -1 +0,0 @@ -json.extract! @user, :id, :username, :email, :password_digest, :name, :created_at, :updated_at From c382d7d6e585186f08ff617df402730f5bf0a94f Mon Sep 17 00:00:00 2001 From: Tammy Date: Tue, 8 Dec 2015 18:57:55 -0800 Subject: [PATCH 025/299] products looking good --- app/views/products/index.html.erb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/products/index.html.erb b/app/views/products/index.html.erb index 6e96aae578..22f5d284b9 100644 --- a/app/views/products/index.html.erb +++ b/app/views/products/index.html.erb @@ -26,9 +26,9 @@ <%= product.stock %> <%= product.description %> <%= product.active %> - <%= link_to 'Show', user_product_path(product.id, product.user.id) %> - <%= link_to 'Edit', edit_product_path(product) %> - <%= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' } %> + <%= link_to 'Show', user_product_path(product.id, product.user_id) %> + <%= link_to 'Edit', edit_user_product_path(product.id, product.user_id) %> + <%= link_to 'Destroy', user_product_path(product.id, product.user_id), method: :delete, data: { confirm: 'Are you sure?' } %> <% end %> @@ -36,4 +36,4 @@
-<%= link_to 'New Product', new_product_path %> +<%= link_to 'New Product', new_user_product_path %> From 7b00a21837b4718322a124f1144c0769a1d6de3a Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Wed, 9 Dec 2015 08:48:30 -0800 Subject: [PATCH 026/299] remove name unique from product --- app/models/product.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/models/product.rb b/app/models/product.rb index 629a357e12..7f70eeafad 100644 --- a/app/models/product.rb +++ b/app/models/product.rb @@ -5,7 +5,6 @@ class Product < ActiveRecord::Base has_and_belongs_to_many :categories validates :name, :price, presence: true - validates :name, uniqueness: true validates_numericality_of :price, :greater_than => 0 validates :photo_url, format: {with: /\.(png|jpg)\Z/i}, allow_nil: true From cdba1ef34c8563b248f12e231964f6d5bba87d61 Mon Sep 17 00:00:00 2001 From: Tammy Date: Wed, 9 Dec 2015 08:48:57 -0800 Subject: [PATCH 027/299] commit to pull --- app/controllers/products_controller.rb | 25 +++--------------- app/controllers/reviews_controller.rb | 33 ++++++++++-------------- app/models/review.rb | 7 +++++ app/views/categories/index.html.erb | 2 +- app/views/categories/index.json.jbuilder | 4 --- app/views/categories/show.json.jbuilder | 1 - app/views/orders/index.html.erb | 8 +++--- app/views/orders/index.json.jbuilder | 4 --- app/views/orders/show.html.erb | 1 + app/views/orders/show.json.jbuilder | 1 - app/views/products/_form.html.erb | 2 +- app/views/products/edit.html.erb | 2 +- app/views/products/index.json.jbuilder | 4 --- app/views/products/new.html.erb | 2 +- app/views/products/show.html.erb | 5 ++-- app/views/products/show.json.jbuilder | 1 - app/views/reviews/edit.html.erb | 4 +-- app/views/reviews/index.html.erb | 8 +++--- app/views/reviews/index.json.jbuilder | 4 --- app/views/reviews/new.html.erb | 2 +- app/views/reviews/show.html.erb | 2 +- app/views/reviews/show.json.jbuilder | 1 - app/views/users/show.html.erb | 1 + 23 files changed, 45 insertions(+), 79 deletions(-) delete mode 100644 app/views/categories/index.json.jbuilder delete mode 100644 app/views/categories/show.json.jbuilder delete mode 100644 app/views/orders/index.json.jbuilder delete mode 100644 app/views/orders/show.json.jbuilder delete mode 100644 app/views/products/index.json.jbuilder delete mode 100644 app/views/products/show.json.jbuilder delete mode 100644 app/views/reviews/index.json.jbuilder delete mode 100644 app/views/reviews/show.json.jbuilder diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index aa0f1de53e..4c245f58eb 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -1,73 +1,56 @@ class ProductsController < ApplicationController before_action :set_product, only: [:show, :edit, :update, :destroy] - # GET /products - # GET /products.json def index @products = Product.all end - # GET /products/1 - # GET /products/1.json + def show end - # GET /products/new + def new @product = Product.new end - # GET /products/1/edit def edit end - # POST /products - # POST /products.json def create @product = Product.new(product_params) respond_to do |format| if @product.save format.html { redirect_to @product, notice: 'Product was successfully created.' } - format.json { render :show, status: :created, location: @product } else format.html { render :new } - format.json { render json: @product.errors, status: :unprocessable_entity } end end end - # PATCH/PUT /products/1 - # PATCH/PUT /products/1.json def update respond_to do |format| if @product.update(product_params) format.html { redirect_to @product, notice: 'Product was successfully updated.' } - format.json { render :show, status: :ok, location: @product } - else - format.html { render :edit } - format.json { render json: @product.errors, status: :unprocessable_entity } + end end end - # DELETE /products/1 - # DELETE /products/1.json def destroy @product.destroy respond_to do |format| format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' } - format.json { head :no_content } end end private - # Use callbacks to share common setup or constraints between actions. + def set_product @product = Product.find(params[:id]) end - # Never trust parameters from the scary internet, only allow the white list through. def product_params params.require(:product).permit(:name, :price, :user_id, :photo_url, :stock, :description, :active) end diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb index 95cad92e44..2d1bc60e2c 100644 --- a/app/controllers/reviews_controller.rb +++ b/app/controllers/reviews_controller.rb @@ -1,74 +1,67 @@ class ReviewsController < ApplicationController - before_action :set_review, only: [:show, :edit, :update, :destroy] + before_action :set_user, only: [:show, :edit, :update, :destroy] - # GET /reviews - # GET /reviews.json def index @reviews = Review.all end - # GET /reviews/1 - # GET /reviews/1.json + def show end - # GET /reviews/new def new @review = Review.new end - # GET /reviews/1/edit + def edit end - # POST /reviews - # POST /reviews.json + def create @review = Review.new(review_params) respond_to do |format| if @review.save format.html { redirect_to @review, notice: 'Review was successfully created.' } - format.json { render :show, status: :created, location: @review } else format.html { render :new } - format.json { render json: @review.errors, status: :unprocessable_entity } end end end - # PATCH/PUT /reviews/1 - # PATCH/PUT /reviews/1.json + def update respond_to do |format| if @review.update(review_params) format.html { redirect_to @review, notice: 'Review was successfully updated.' } - format.json { render :show, status: :ok, location: @review } else format.html { render :edit } - format.json { render json: @review.errors, status: :unprocessable_entity } end end end - # DELETE /reviews/1 - # DELETE /reviews/1.json + def destroy @review.destroy respond_to do |format| format.html { redirect_to reviews_url, notice: 'Review was successfully destroyed.' } - format.json { head :no_content } end end private - # Use callbacks to share common setup or constraints between actions. + def set_review @review = Review.find(params[:id]) end - # Never trust parameters from the scary internet, only allow the white list through. def review_params params.require(:review).permit(:rating, :product_id, :description) end + + def set_user + set_review + product = Product.find(@review.product_id) + @user = User.find(product.user_id) + end end diff --git a/app/models/review.rb b/app/models/review.rb index 2c8380ed4b..5e44c46856 100644 --- a/app/models/review.rb +++ b/app/models/review.rb @@ -3,4 +3,11 @@ class Review < ActiveRecord::Base validates :rating, presence: true validates :rating, numericality: { :greater_than => 0, less_than: 6 } + + + def self.find_user_id(review) + product = Product.find(review.product_id) + return User.find(product.user_id) + end + end diff --git a/app/views/categories/index.html.erb b/app/views/categories/index.html.erb index 84ab2e3b41..03e485fa56 100644 --- a/app/views/categories/index.html.erb +++ b/app/views/categories/index.html.erb @@ -16,7 +16,7 @@ <%= category.name %> <%= link_to 'Show', category %> <%= link_to 'Edit', edit_category_path(category) %> - <%= link_to 'Destroy', category, method: :delete, data: { confirm: 'Are you sure?' } %> + <%= link_to 'Destroy', category_path(category), method: :delete, data: { confirm: 'Are you sure?' } %> <% end %> diff --git a/app/views/categories/index.json.jbuilder b/app/views/categories/index.json.jbuilder deleted file mode 100644 index 997fe33a31..0000000000 --- a/app/views/categories/index.json.jbuilder +++ /dev/null @@ -1,4 +0,0 @@ -json.array!(@categories) do |category| - json.extract! category, :id, :name - json.url category_url(category, format: :json) -end diff --git a/app/views/categories/show.json.jbuilder b/app/views/categories/show.json.jbuilder deleted file mode 100644 index 19636d23c8..0000000000 --- a/app/views/categories/show.json.jbuilder +++ /dev/null @@ -1 +0,0 @@ -json.extract! @category, :id, :name, :created_at, :updated_at diff --git a/app/views/orders/index.html.erb b/app/views/orders/index.html.erb index 74a155cf74..2496383d66 100644 --- a/app/views/orders/index.html.erb +++ b/app/views/orders/index.html.erb @@ -30,9 +30,9 @@ <%= order.cc_exp %> <%= order.cc_cvv %> <%= order.cc_name %> - <%= link_to 'Show', order %> - <%= link_to 'Edit', edit_order_path(order) %> - <%= link_to 'Destroy', order, method: :delete, data: { confirm: 'Are you sure?' } %> + <%= link_to 'Show', user_order_path(order.user_id, order.id %> + <%= link_to 'Edit', edit_user_order(order.user_id, order.id) %> + <%= link_to 'Destroy', user_order_path(order.user_id, order.id), method: :delete, data: { confirm: 'Are you sure?' } %> <% end %> @@ -40,4 +40,4 @@
-<%= link_to 'New Order', new_order_path %> +<%= link_to 'New Order', new_user_order_path %> diff --git a/app/views/orders/index.json.jbuilder b/app/views/orders/index.json.jbuilder deleted file mode 100644 index d7ea427621..0000000000 --- a/app/views/orders/index.json.jbuilder +++ /dev/null @@ -1,4 +0,0 @@ -json.array!(@orders) do |order| - json.extract! order, :id, :email, :street, :city, :state, :zip, :cc_num, :cc_exp, :cc_cvv, :cc_name - json.url order_url(order, format: :json) -end diff --git a/app/views/orders/show.html.erb b/app/views/orders/show.html.erb index 3c72eac73f..aec9e89e40 100644 --- a/app/views/orders/show.html.erb +++ b/app/views/orders/show.html.erb @@ -47,3 +47,4 @@ <%= link_to 'Edit', edit_order_path(@order) %> | <%= link_to 'Back', orders_path %> +<%= link_to 'Order Item', user_order_order_items_path(@order.id, @order.user_id) %> diff --git a/app/views/orders/show.json.jbuilder b/app/views/orders/show.json.jbuilder deleted file mode 100644 index 486eceb4db..0000000000 --- a/app/views/orders/show.json.jbuilder +++ /dev/null @@ -1 +0,0 @@ -json.extract! @order, :id, :email, :street, :city, :state, :zip, :cc_num, :cc_exp, :cc_cvv, :cc_name, :created_at, :updated_at diff --git a/app/views/products/_form.html.erb b/app/views/products/_form.html.erb index ebfc42cfe5..b99f50f11f 100644 --- a/app/views/products/_form.html.erb +++ b/app/views/products/_form.html.erb @@ -1,4 +1,4 @@ -<%= form_for(@product) do |f| %> +<%= form_for @product do |f| %> <% if @product.errors.any? %>

<%= pluralize(@product.errors.count, "error") %> prohibited this product from being saved:

diff --git a/app/views/products/edit.html.erb b/app/views/products/edit.html.erb index 39f848b282..5d7a362da8 100644 --- a/app/views/products/edit.html.erb +++ b/app/views/products/edit.html.erb @@ -3,4 +3,4 @@ <%= render 'form' %> <%= link_to 'Show', @product %> | -<%= link_to 'Back', products_path %> +<%= link_to 'Back', user_products_path %> diff --git a/app/views/products/index.json.jbuilder b/app/views/products/index.json.jbuilder deleted file mode 100644 index daee3ccd95..0000000000 --- a/app/views/products/index.json.jbuilder +++ /dev/null @@ -1,4 +0,0 @@ -json.array!(@products) do |product| - json.extract! product, :id, :name, :price, :user_id, :photo_url, :stock, :description, :active - json.url product_url(product, format: :json) -end diff --git a/app/views/products/new.html.erb b/app/views/products/new.html.erb index 18db96a399..058db423a6 100644 --- a/app/views/products/new.html.erb +++ b/app/views/products/new.html.erb @@ -2,4 +2,4 @@ <%= render 'form' %> -<%= link_to 'Back', products_path %> +<%= link_to 'Back', user_products_path %> diff --git a/app/views/products/show.html.erb b/app/views/products/show.html.erb index 0dbbdb4d14..0157adee66 100644 --- a/app/views/products/show.html.erb +++ b/app/views/products/show.html.erb @@ -35,5 +35,6 @@ <%= @product.active %>

-<%= link_to 'Edit', edit_product_path(@product) %> | -<%= link_to 'Back', products_path %> +<%= link_to 'Edit', edit_user_product_path(@product.id, @product.user_id) %> | +<%= link_to 'Back', user_products_path(@product.user_id) %> +<%= link_to 'Rewiews', user_product_reviews_path(@product.id, @product.user_id) %> diff --git a/app/views/products/show.json.jbuilder b/app/views/products/show.json.jbuilder deleted file mode 100644 index c8f4238fc8..0000000000 --- a/app/views/products/show.json.jbuilder +++ /dev/null @@ -1 +0,0 @@ -json.extract! @product, :id, :name, :price, :user_id, :photo_url, :stock, :description, :active, :created_at, :updated_at diff --git a/app/views/reviews/edit.html.erb b/app/views/reviews/edit.html.erb index ad7d5091c8..5ff0b89e40 100644 --- a/app/views/reviews/edit.html.erb +++ b/app/views/reviews/edit.html.erb @@ -2,5 +2,5 @@ <%= render 'form' %> -<%= link_to 'Show', @review %> | -<%= link_to 'Back', reviews_path %> +<%= link_to 'Show', user_product_review_path(@review.product_id, @user.id) %> | +<%= link_to 'Back', user_product_reviews_path(@review.product_id, @user.id) %> diff --git a/app/views/reviews/index.html.erb b/app/views/reviews/index.html.erb index 0f61d6c7f5..319fd69b75 100644 --- a/app/views/reviews/index.html.erb +++ b/app/views/reviews/index.html.erb @@ -18,9 +18,9 @@ <%= review.rating %> <%= review.product_id %> <%= review.description %> - <%= link_to 'Show', review %> - <%= link_to 'Edit', edit_review_path(review) %> - <%= link_to 'Destroy', review, method: :delete, data: { confirm: 'Are you sure?' } %> + <%= link_to 'Show', user_product_review_path(review.product_id, Review.find_user_id(review)) %> + <%= link_to 'Edit', edit_user_product_review_path(review.product_id, Review.find_user_id(review)) %> + <%= link_to 'Destroy', user_product_review_path(review.product_id, Review.find_user_id(review)), method: :delete, data: { confirm: 'Are you sure?' } %> <% end %> @@ -28,4 +28,4 @@
-<%= link_to 'New Review', new_review_path %> +<%= link_to 'New Review', new_user_product_review_path(@review.product_id, @user.id) %> diff --git a/app/views/reviews/index.json.jbuilder b/app/views/reviews/index.json.jbuilder deleted file mode 100644 index eef6b1832e..0000000000 --- a/app/views/reviews/index.json.jbuilder +++ /dev/null @@ -1,4 +0,0 @@ -json.array!(@reviews) do |review| - json.extract! review, :id, :rating, :product_id, :description - json.url review_url(review, format: :json) -end diff --git a/app/views/reviews/new.html.erb b/app/views/reviews/new.html.erb index 3a07bf51f6..7d54550cdd 100644 --- a/app/views/reviews/new.html.erb +++ b/app/views/reviews/new.html.erb @@ -2,4 +2,4 @@ <%= render 'form' %> -<%= link_to 'Back', reviews_path %> +<%= link_to 'Back', user_product_reviews_path(@review.product_id, @user.id)%> diff --git a/app/views/reviews/show.html.erb b/app/views/reviews/show.html.erb index 26672e35f0..896995924f 100644 --- a/app/views/reviews/show.html.erb +++ b/app/views/reviews/show.html.erb @@ -16,4 +16,4 @@

<%= link_to 'Edit', edit_review_path(@review) %> | -<%= link_to 'Back', reviews_path %> +<%= link_to 'Back', user_product_reviews_path(@review.product_id, @user.id) %> diff --git a/app/views/reviews/show.json.jbuilder b/app/views/reviews/show.json.jbuilder deleted file mode 100644 index 5574aeb6cd..0000000000 --- a/app/views/reviews/show.json.jbuilder +++ /dev/null @@ -1 +0,0 @@ -json.extract! @review, :id, :rating, :product_id, :description, :created_at, :updated_at diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index a12d61d1d6..dbe58b71dc 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -23,3 +23,4 @@ <%= link_to 'Edit', edit_user_path(@user) %> | <%= link_to 'Back', users_path %> <%= link_to 'Products', user_products_path(@user) %> +<%= link_to 'Orders', user_orders_path(@user) %> From c4063408145266eaaa2b5b22d92698e5e91524e9 Mon Sep 17 00:00:00 2001 From: Kelly Date: Wed, 9 Dec 2015 09:02:23 -0800 Subject: [PATCH 028/299] Add back product name uniqueness --- app/models/product.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/product.rb b/app/models/product.rb index 7f70eeafad..629a357e12 100644 --- a/app/models/product.rb +++ b/app/models/product.rb @@ -5,6 +5,7 @@ class Product < ActiveRecord::Base has_and_belongs_to_many :categories validates :name, :price, presence: true + validates :name, uniqueness: true validates_numericality_of :price, :greater_than => 0 validates :photo_url, format: {with: /\.(png|jpg)\Z/i}, allow_nil: true From 6f20f03d2b8611b2340f94d748cc264383ddb8e9 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Wed, 9 Dec 2015 09:03:10 -0800 Subject: [PATCH 029/299] create unique names for products in seed file --- seeds_csvs/products.csv | 110 ++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/seeds_csvs/products.csv b/seeds_csvs/products.csv index 4bd9542ac7..a35f55a349 100644 --- a/seeds_csvs/products.csv +++ b/seeds_csvs/products.csv @@ -1,56 +1,56 @@ name,price,user_id,photo_url,stock,description,active -Dive Rings,599,1,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",9,Unbreakable rings stand up on the pool bottom for diving games. Set of 4., -Inflatable Water Wheel,3795,1,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,3,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended.", -Shark Goggles,1196,1,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,9,Made using the highest quality materials, -Swimming Fish Pool Toy,1399,1,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,10,, -Water Noodles,1143,1,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,11,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random., -Water Wings,690,1,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,5,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue, -Dive Rings,599,2,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",14,Unbreakable rings stand up on the pool bottom for diving games. Set of 4., -Dive Sticks,395,2,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,4,Sticks stand upright on pool bottom., -Dory Doll,3000,2,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,12,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll", -Inflatable Water Wheel,3795,2,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,1,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended.", -Swimming Fish Pool Toy,1399,2,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,1,, -Toypedo Bandits,615,2,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,11,Glides underwater up to 30 feet, -Water Noodles,1143,2,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,10,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random., -Water Wings,690,2,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,12,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue, -Dive Rings,599,3,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",1,Unbreakable rings stand up on the pool bottom for diving games. Set of 4., -Dive Sticks,395,3,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,8,Sticks stand upright on pool bottom., -Finding Nemo DVD,1996,3,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,1,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination.", -Inflatable Water Wheel,3795,3,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,2,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended.", -Puddle Jumper Life Jacket,1359,3,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,14,For children 30-50 lbs., -Shark Goggles,1196,3,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,15,Made using the highest quality materials, -Swimming Fish Pool Toy,1399,3,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,14,, -Toypedo Bandits,615,3,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,14,Glides underwater up to 30 feet, -Water Noodles,1143,3,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,1,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random., -Water Wings,690,3,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,13,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue, -Dive Sticks,395,4,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,9,Sticks stand upright on pool bottom., -Finding Nemo DVD,1996,4,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,5,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination.", -Inflatable Water Wheel,3795,4,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,5,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended.", -Puddle Jumper Life Jacket,1359,4,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,2,For children 30-50 lbs., -Shark Goggles,1196,4,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,5,Made using the highest quality materials, -Swimming Fish Pool Toy,1399,4,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,3,, -Water Wings,690,4,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,3,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue, -Dive Rings,599,5,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",3,Unbreakable rings stand up on the pool bottom for diving games. Set of 4., -Dory Doll,3000,5,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,6,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll", -Finding Nemo DVD,1996,5,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,1,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination.", -Dory Doll,3000,6,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,14,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll", -Finding Nemo DVD,1996,6,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,9,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination.", -Water Wings,690,6,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,3,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue, -Dive Sticks,395,7,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,4,Sticks stand upright on pool bottom., -Shark Goggles,1196,7,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,8,Made using the highest quality materials, -Toypedo Bandits,615,7,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,5,Glides underwater up to 30 feet, -Water Noodles,1143,7,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,9,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random., -Dive Sticks,395,8,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,14,Sticks stand upright on pool bottom., -Puddle Jumper Life Jacket,1359,8,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,4,For children 30-50 lbs., -Puddle Jumper Life Jacket,1359,9,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,12,For children 30-50 lbs., -Shark Goggles,1196,8,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,14,Made using the highest quality materials, -Toypedo Bandits,615,8,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,12,Glides underwater up to 30 feet, -Dive Rings,599,9,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",4,Unbreakable rings stand up on the pool bottom for diving games. Set of 4., -Dory Doll,3000,9,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,5,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll", -Inflatable Water Wheel,3795,9,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,14,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended.", -Water Noodles,1143,9,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,11,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random., -Dory Doll,3000,10,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,9,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll", -Finding Nemo DVD,1996,10,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,9,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination.", -Puddle Jumper Life Jacket,1359,10,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,4,For children 30-50 lbs., -Swimming Fish Pool Toy,1399,10,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,11,, -Toypedo Bandits,615,10,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,10,Glides underwater up to 30 feet, +Relieved Dive Rings,599,1,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",11,Unbreakable rings stand up on the pool bottom for diving games. Set of 4., +Heavenly Inflatable Water Wheel,3795,1,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,2,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended.", +Two Shark Goggles,1196,1,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,11,Made using the highest quality materials, +Curved Swimming Fish Pool Toy,1399,1,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,1,, +Lavish Water Noodles,1143,1,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,1,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random., +Pumped Water Wings,690,1,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,4,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue, +Bouncy Dive Rings,599,2,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",14,Unbreakable rings stand up on the pool bottom for diving games. Set of 4., +Steep Dive Sticks,395,2,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,4,Sticks stand upright on pool bottom., +Sore Dory Doll,3000,2,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,3,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll", +Talented Inflatable Water Wheel,3795,2,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,12,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended.", +Young Swimming Fish Pool Toy,1399,2,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,8,, +Moldy Toypedo Bandits,615,2,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,15,Glides underwater up to 30 feet, +Courageous Water Noodles,1143,2,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,7,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random., +Guarded Water Wings,690,2,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,8,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue, +Crooked Dive Rings,599,3,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",2,Unbreakable rings stand up on the pool bottom for diving games. Set of 4., +Efficacious Dive Sticks,395,3,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,13,Sticks stand upright on pool bottom., +Wrong Finding Nemo DVD,1996,3,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,10,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination.", +Easy Inflatable Water Wheel,3795,3,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,1,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended.", +Unwieldy Puddle Jumper Life Jacket,1359,3,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,3,For children 30-50 lbs., +Near Shark Goggles,1196,3,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,8,Made using the highest quality materials, +Uppity Swimming Fish Pool Toy,1399,3,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,5,, +Black Toypedo Bandits,615,3,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,13,Glides underwater up to 30 feet, +Necessary Water Noodles,1143,3,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,9,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random., +Piquant Water Wings,690,3,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,11,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue, +Ripe Dive Sticks,395,4,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,1,Sticks stand upright on pool bottom., +Wandering Finding Nemo DVD,1996,4,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,5,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination.", +Stereotyped Inflatable Water Wheel,3795,4,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,1,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended.", +Soft Puddle Jumper Life Jacket,1359,4,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,5,For children 30-50 lbs., +Abrupt Shark Goggles,1196,4,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,13,Made using the highest quality materials, +Womanly Swimming Fish Pool Toy,1399,4,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,10,, +Minor Water Wings,690,4,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,11,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue, +Grateful Dive Rings,599,5,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",10,Unbreakable rings stand up on the pool bottom for diving games. Set of 4., +Stale Dory Doll,3000,5,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,6,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll", +Thundering Finding Nemo DVD,1996,5,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,9,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination.", +Right Dory Doll,3000,6,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,5,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll", +Petite Finding Nemo DVD,1996,6,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,13,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination.", +Spotty Water Wings,690,6,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,3,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue, +Ubiquitous Dive Sticks,395,7,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,15,Sticks stand upright on pool bottom., +Bustling Shark Goggles,1196,7,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,9,Made using the highest quality materials, +Wry Toypedo Bandits,615,7,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,3,Glides underwater up to 30 feet, +Squealing Water Noodles,1143,7,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,4,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random., +Adhesive Dive Sticks,395,8,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,11,Sticks stand upright on pool bottom., +Hissing Puddle Jumper Life Jacket,1359,8,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,1,For children 30-50 lbs., +Sloppy Puddle Jumper Life Jacket,1359,9,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,12,For children 30-50 lbs., +Hanging Shark Goggles,1196,8,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,5,Made using the highest quality materials, +Fumbling Toypedo Bandits,615,8,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,7,Glides underwater up to 30 feet, +Brief Dive Rings,599,9,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",10,Unbreakable rings stand up on the pool bottom for diving games. Set of 4., +Lean Dory Doll,3000,9,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,6,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll", +Giant Inflatable Water Wheel,3795,9,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,5,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended.", +Lazy Water Noodles,1143,9,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,10,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random., +Animated Dory Doll,3000,10,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,7,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll", +Ethereal Finding Nemo DVD,1996,10,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,14,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination.", +Regular Puddle Jumper Life Jacket,1359,10,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,2,For children 30-50 lbs., +Dizzy Swimming Fish Pool Toy,1399,10,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,9,, +Medical Toypedo Bandits,615,10,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,11,Glides underwater up to 30 feet, From 28b7c5b70f60193a60540b532b2f408dd3f58c0a Mon Sep 17 00:00:00 2001 From: Tammy Date: Wed, 9 Dec 2015 09:30:45 -0800 Subject: [PATCH 030/299] still working on products --- app/views/products/_form.html.erb | 37 ++++++++----------------------- app/views/products/edit.html.erb | 2 +- 2 files changed, 10 insertions(+), 29 deletions(-) diff --git a/app/views/products/_form.html.erb b/app/views/products/_form.html.erb index b99f50f11f..18336e7e44 100644 --- a/app/views/products/_form.html.erb +++ b/app/views/products/_form.html.erb @@ -1,45 +1,26 @@ <%= form_for @product do |f| %> - <% if @product.errors.any? %> -
-

<%= pluralize(@product.errors.count, "error") %> prohibited this product from being saved:

- -
    - <% @product.errors.full_messages.each do |message| %> -
  • <%= message %>
  • - <% end %> -
-
- <% end %> - -
+ <%= f.label :name %>
<%= f.text_field :name %> -
-
+ <%= f.label :price %>
<%= f.number_field :price %> -
-
+ <%= f.label :user_id %>
<%= f.number_field :user_id %> -
-
+ <%= f.label :photo_url %>
<%= f.text_field :photo_url %> -
-
- <%= f.label :stock %>
+ + <%= f.label :stock %> <%= f.number_field :stock %> -
-
+ <%= f.label :description %>
<%= f.text_field :description %> -
-
+ <%= f.label :active %>
<%= f.check_box :active %> -
-
+ <%= f.submit %>
<% end %> diff --git a/app/views/products/edit.html.erb b/app/views/products/edit.html.erb index 5d7a362da8..9e000c1530 100644 --- a/app/views/products/edit.html.erb +++ b/app/views/products/edit.html.erb @@ -2,5 +2,5 @@ <%= render 'form' %> -<%= link_to 'Show', @product %> | +<%= link_to 'Show', user_product_path(@product.id, @product.user_id) %> | <%= link_to 'Back', user_products_path %> From 6e5c74464c1a780275efefa786a8942c7965b8e4 Mon Sep 17 00:00:00 2001 From: Kelly Date: Wed, 9 Dec 2015 09:31:01 -0800 Subject: [PATCH 031/299] Update review CRUD --- app/controllers/reviews_controller.rb | 2 +- app/models/review.rb | 10 +++++----- app/views/products/show.html.erb | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb index 2d1bc60e2c..bb34514d8c 100644 --- a/app/controllers/reviews_controller.rb +++ b/app/controllers/reviews_controller.rb @@ -56,7 +56,7 @@ def set_review end def review_params - params.require(:review).permit(:rating, :product_id, :description) + params.require(:review).permit(:rating, :description) end def set_user diff --git a/app/models/review.rb b/app/models/review.rb index 5e44c46856..4261e1fe37 100644 --- a/app/models/review.rb +++ b/app/models/review.rb @@ -4,10 +4,10 @@ class Review < ActiveRecord::Base validates :rating, presence: true validates :rating, numericality: { :greater_than => 0, less_than: 6 } - - def self.find_user_id(review) - product = Product.find(review.product_id) - return User.find(product.user_id) - end + # + # def self.find_user_id(review) + # product = Product.find(review.product_id) + # return User.find(product.user_id).id + # end end diff --git a/app/views/products/show.html.erb b/app/views/products/show.html.erb index 0157adee66..de48df7327 100644 --- a/app/views/products/show.html.erb +++ b/app/views/products/show.html.erb @@ -37,4 +37,4 @@ <%= link_to 'Edit', edit_user_product_path(@product.id, @product.user_id) %> | <%= link_to 'Back', user_products_path(@product.user_id) %> -<%= link_to 'Rewiews', user_product_reviews_path(@product.id, @product.user_id) %> +<%= link_to 'Reviews', user_product_reviews_path(@product.id, @product.user_id) %> From ac931d31abbf683c9b1ef745a826c9961165f70c Mon Sep 17 00:00:00 2001 From: Kelly Date: Wed, 9 Dec 2015 09:43:57 -0800 Subject: [PATCH 032/299] Update product edit and _form with user object --- app/views/products/_form.html.erb | 2 +- app/views/products/edit.html.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/products/_form.html.erb b/app/views/products/_form.html.erb index b99f50f11f..54e4f640b7 100644 --- a/app/views/products/_form.html.erb +++ b/app/views/products/_form.html.erb @@ -1,4 +1,4 @@ -<%= form_for @product do |f| %> +<%= form_for [@product.user, @product] do |f| %> <% if @product.errors.any? %>

<%= pluralize(@product.errors.count, "error") %> prohibited this product from being saved:

diff --git a/app/views/products/edit.html.erb b/app/views/products/edit.html.erb index 5d7a362da8..8131794ee9 100644 --- a/app/views/products/edit.html.erb +++ b/app/views/products/edit.html.erb @@ -2,5 +2,5 @@ <%= render 'form' %> -<%= link_to 'Show', @product %> | +<%= link_to 'Show', user_product_path(@product.user, @product) %> | <%= link_to 'Back', user_products_path %> From 914fc35505c30294d2090f56358e87e1a0e9960d Mon Sep 17 00:00:00 2001 From: Tammy Date: Wed, 9 Dec 2015 09:45:01 -0800 Subject: [PATCH 033/299] users CRUD looks good --- app/controllers/users_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index e92452df72..8317e0e718 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -32,7 +32,7 @@ def update if @user.update(user_params) format.html { redirect_to @user, notice: 'User was successfully updated.' } else - format.html { render :edit } + render "edit" end end end From dbde8ce1993d8f6f9508f575da6ef02d19b17dbe Mon Sep 17 00:00:00 2001 From: Tammy Date: Wed, 9 Dec 2015 09:47:54 -0800 Subject: [PATCH 034/299] fixed user issue --- app/controllers/users_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 8317e0e718..2f13e5beb6 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -23,7 +23,7 @@ def create if @user.save format.html { redirect_to @user, notice: 'User was successfully created.' } else - format.html { render :new } + render "new" end end From 4dc68eca3fb5bb5124b974fbd4ebd6a69e6da327 Mon Sep 17 00:00:00 2001 From: Kelly Date: Wed, 9 Dec 2015 09:59:10 -0800 Subject: [PATCH 035/299] Complete basic Review index method and view --- app/controllers/reviews_controller.rb | 1 + app/views/reviews/index.html.erb | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb index bb34514d8c..0c96de00bb 100644 --- a/app/controllers/reviews_controller.rb +++ b/app/controllers/reviews_controller.rb @@ -3,6 +3,7 @@ class ReviewsController < ApplicationController def index @reviews = Review.all + @product = Product.find(params[:product_id]) end diff --git a/app/views/reviews/index.html.erb b/app/views/reviews/index.html.erb index 319fd69b75..7a5d73b5c9 100644 --- a/app/views/reviews/index.html.erb +++ b/app/views/reviews/index.html.erb @@ -1,6 +1,6 @@

<%= notice %>

-

Listing Reviews

+

Listing Reviews for <%= @product.name %>

@@ -13,14 +13,14 @@ - <% @reviews.each do |review| %> + <% @product.reviews.each do |review| %> - - - + + + <% end %> @@ -28,4 +28,4 @@
-<%= link_to 'New Review', new_user_product_review_path(@review.product_id, @user.id) %> +<%= link_to 'New Review', new_user_product_review_path(@product.user, @product) %> From 42648b18a8ed5ac8eb9c731541535645aac0518b Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Wed, 9 Dec 2015 10:06:04 -0800 Subject: [PATCH 036/299] create categories_products table --- .../20151209180323_create_categories_and_products.rb | 8 ++++++++ db/schema.rb | 10 +++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20151209180323_create_categories_and_products.rb diff --git a/db/migrate/20151209180323_create_categories_and_products.rb b/db/migrate/20151209180323_create_categories_and_products.rb new file mode 100644 index 0000000000..70e8804f04 --- /dev/null +++ b/db/migrate/20151209180323_create_categories_and_products.rb @@ -0,0 +1,8 @@ +class CreateCategoriesAndProducts < ActiveRecord::Migration + def change + create_table :categories_products do |t| + t.belongs_to :category, index: true + t.belongs_to :product, index: true + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 8b04266991..62a2c11562 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20151208221927) do +ActiveRecord::Schema.define(version: 20151209180323) do create_table "categories", force: :cascade do |t| t.string "name" @@ -19,6 +19,14 @@ t.datetime "updated_at", null: false end + create_table "categories_products", force: :cascade do |t| + t.integer "category_id" + t.integer "product_id" + end + + add_index "categories_products", ["category_id"], name: "index_categories_products_on_category_id" + add_index "categories_products", ["product_id"], name: "index_categories_products_on_product_id" + create_table "order_items", force: :cascade do |t| t.integer "product_id" t.integer "order_id" From 03dfcfd02f3ed494a4f7645f7998545aca993ae9 Mon Sep 17 00:00:00 2001 From: Tammy Date: Wed, 9 Dec 2015 10:06:53 -0800 Subject: [PATCH 037/299] commit to pull a new table --- app/views/products/edit.html.erb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/views/products/edit.html.erb b/app/views/products/edit.html.erb index b5177386c9..33805822e2 100644 --- a/app/views/products/edit.html.erb +++ b/app/views/products/edit.html.erb @@ -2,9 +2,7 @@ <%= render 'form' %> -<<<<<<< HEAD -<%= link_to 'Show', user_product_path(@product.id, @product.user_id) %> | -======= + + <%= link_to 'Show', user_product_path(@product.user, @product) %> | ->>>>>>> ac931d31abbf683c9b1ef745a826c9961165f70c <%= link_to 'Back', user_products_path %> From 633335a4a5239a4ea9da15abaa5e441487626f7e Mon Sep 17 00:00:00 2001 From: Kelly Date: Wed, 9 Dec 2015 10:10:06 -0800 Subject: [PATCH 038/299] Update basic show method and view for Review model --- app/controllers/reviews_controller.rb | 1 + app/views/reviews/show.html.erb | 18 +++++------------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb index 0c96de00bb..7074aa1973 100644 --- a/app/controllers/reviews_controller.rb +++ b/app/controllers/reviews_controller.rb @@ -8,6 +8,7 @@ def index def show + @review = Review.find(params[:id]) end def new diff --git a/app/views/reviews/show.html.erb b/app/views/reviews/show.html.erb index 896995924f..9eb9cd1a00 100644 --- a/app/views/reviews/show.html.erb +++ b/app/views/reviews/show.html.erb @@ -1,19 +1,11 @@

<%= notice %>

- +

Review for <%= @review.product.name %>

- Rating: - <%= @review.rating %> + Rating: <%= @review.rating %>

- -

- Product: - <%= @review.product_id %> -

-

- Description: - <%= @review.description %> + Description: <%= @review.description %>

-<%= link_to 'Edit', edit_review_path(@review) %> | -<%= link_to 'Back', user_product_reviews_path(@review.product_id, @user.id) %> +<%= link_to 'Edit', edit_user_product_review_path(@review.product.user, @review.product, @review) %> | +<%= link_to 'Back', user_product_reviews_path(@review.product.user, @review.product) %> From c4e521ac146e97cdd4e3e2c8379afc3672465a0a Mon Sep 17 00:00:00 2001 From: Tammy Date: Wed, 9 Dec 2015 10:12:18 -0800 Subject: [PATCH 039/299] products looks good --- app/controllers/products_controller.rb | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index 4c245f58eb..4f31251250 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -19,29 +19,23 @@ def edit def create @product = Product.new(product_params) - - respond_to do |format| if @product.save format.html { redirect_to @product, notice: 'Product was successfully created.' } else format.html { render :new } end - end end def update - respond_to do |format| - if @product.update(product_params) - format.html { redirect_to @product, notice: 'Product was successfully updated.' } - - end + if @product.update(product_params) + format.html { redirect_to @product, notice: 'Product was successfully updated.' } end end def destroy @product.destroy respond_to do |format| - format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' } + format.html { redirect_to user_products_path, notice: 'Product was successfully destroyed.' } end end From 3df247fe745c3b3e08a4291be3a7b72da9d67849 Mon Sep 17 00:00:00 2001 From: Tammy Date: Wed, 9 Dec 2015 10:38:07 -0800 Subject: [PATCH 040/299] we can see the orders from user --- app/controllers/orders_controller.rb | 29 ++++++++++------------------ app/views/orders/index.html.erb | 7 +++---- app/views/users/index.html.erb | 1 + 3 files changed, 14 insertions(+), 23 deletions(-) diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index 1480125d8e..e3bdd17cb3 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -1,73 +1,64 @@ class OrdersController < ApplicationController before_action :set_order, only: [:show, :edit, :update, :destroy] - # GET /orders - # GET /orders.json def index @orders = Order.all + @user = User.find(params[:user_id]) end - # GET /orders/1 - # GET /orders/1.json + def show end - # GET /orders/new def new @order = Order.new end - # GET /orders/1/edit def edit end - # POST /orders - # POST /orders.json + def create @order = Order.new(order_params) respond_to do |format| if @order.save format.html { redirect_to @order, notice: 'Order was successfully created.' } - format.json { render :show, status: :created, location: @order } else format.html { render :new } - format.json { render json: @order.errors, status: :unprocessable_entity } end end end - # PATCH/PUT /orders/1 - # PATCH/PUT /orders/1.json + def update respond_to do |format| if @order.update(order_params) format.html { redirect_to @order, notice: 'Order was successfully updated.' } - format.json { render :show, status: :ok, location: @order } + else format.html { render :edit } - format.json { render json: @order.errors, status: :unprocessable_entity } + end end end - # DELETE /orders/1 - # DELETE /orders/1.json + def destroy @order.destroy respond_to do |format| format.html { redirect_to orders_url, notice: 'Order was successfully destroyed.' } - format.json { head :no_content } + end end private - # Use callbacks to share common setup or constraints between actions. + def set_order @order = Order.find(params[:id]) end - # Never trust parameters from the scary internet, only allow the white list through. + def order_params params.require(:order).permit(:email, :street, :city, :state, :zip, :cc_num, :cc_exp, :cc_cvv, :cc_name) end diff --git a/app/views/orders/index.html.erb b/app/views/orders/index.html.erb index 2496383d66..cfea60b99c 100644 --- a/app/views/orders/index.html.erb +++ b/app/views/orders/index.html.erb @@ -30,14 +30,13 @@
- - - + + + <% end %>
<%= review.rating %> <%= review.product_id %> <%= review.description %><%= link_to 'Show', user_product_review_path(review.product_id, Review.find_user_id(review)) %><%= link_to 'Edit', edit_user_product_review_path(review.product_id, Review.find_user_id(review)) %><%= link_to 'Destroy', user_product_review_path(review.product_id, Review.find_user_id(review)), method: :delete, data: { confirm: 'Are you sure?' } %><%= link_to 'Show', user_product_review_path(review.product.user, review.product, review) %><%= link_to 'Edit', edit_user_product_review_path(review.product.user, review.product, review) %><%= link_to 'Destroy', user_product_review_path(review.product.user, review.product, review), method: :delete, data: { confirm: 'Are you sure?' } %>
<%= order.cc_exp %> <%= order.cc_cvv %> <%= order.cc_name %><%= link_to 'Show', user_order_path(order.user_id, order.id %><%= link_to 'Edit', edit_user_order(order.user_id, order.id) %><%= link_to 'Destroy', user_order_path(order.user_id, order.id), method: :delete, data: { confirm: 'Are you sure?' } %><%= link_to 'Show', user_order_path(@user.id, order.id) %><%= link_to 'Edit', edit_user_order_path(@user.id, order.id) %><%= link_to 'Destroy', user_order_path(@user.id, order.id), method: :delete, data: { confirm: 'Are you sure?' } %>
-
<%= link_to 'New Order', new_user_order_path %> diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb index 45cb853dd7..ea5f6fc407 100644 --- a/app/views/users/index.html.erb +++ b/app/views/users/index.html.erb @@ -23,6 +23,7 @@ <%= link_to 'Show', user %> <%= link_to 'Edit', edit_user_path(user) %> <%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %> + <%= link_to 'view my orders', user_orders_path(user.id) %> <% end %> From abf884dffe60b2d24967316dd750122293995efe Mon Sep 17 00:00:00 2001 From: Kelly Date: Wed, 9 Dec 2015 10:45:18 -0800 Subject: [PATCH 041/299] complete basic CRUD for Review --- app/controllers/reviews_controller.rb | 42 +++++++++------------------ app/views/reviews/_form.html.erb | 8 ++--- app/views/reviews/edit.html.erb | 4 +-- app/views/reviews/index.html.erb | 2 -- app/views/reviews/new.html.erb | 2 +- 5 files changed, 19 insertions(+), 39 deletions(-) diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb index 7074aa1973..caa7443ddb 100644 --- a/app/controllers/reviews_controller.rb +++ b/app/controllers/reviews_controller.rb @@ -1,5 +1,6 @@ class ReviewsController < ApplicationController - before_action :set_user, only: [:show, :edit, :update, :destroy] + before_action :find_review, only: [:show, :edit, :update, :destroy] + before_action :find_product, only: [:new, :edit] def index @reviews = Review.all @@ -8,7 +9,6 @@ def index def show - @review = Review.find(params[:id]) end def new @@ -21,49 +21,35 @@ def edit def create - @review = Review.new(review_params) - - respond_to do |format| - if @review.save - format.html { redirect_to @review, notice: 'Review was successfully created.' } - else - format.html { render :new } - end + review = Review.create(review_params) do |r| + r.product_id = params[:product_id] end + redirect_to user_product_reviews_path(review.product.user, review.product, review) end def update - respond_to do |format| - if @review.update(review_params) - format.html { redirect_to @review, notice: 'Review was successfully updated.' } - else - format.html { render :edit } - end - end + @review.update(review_params) + redirect_to user_product_reviews_path(@review.product.user, @review.product, @review) end def destroy @review.destroy - respond_to do |format| - format.html { redirect_to reviews_url, notice: 'Review was successfully destroyed.' } - end + redirect_to user_product_reviews_path(@review.product.user, @review.product, @review) end private - def set_review - @review = Review.find(params[:id]) - end - def review_params params.require(:review).permit(:rating, :description) end - def set_user - set_review - product = Product.find(@review.product_id) - @user = User.find(product.user_id) + def find_review + @review = Review.find(params[:id]) + end + + def find_product + @product = Product.find(params[:product_id]) end end diff --git a/app/views/reviews/_form.html.erb b/app/views/reviews/_form.html.erb index 0523df239f..731391ed88 100644 --- a/app/views/reviews/_form.html.erb +++ b/app/views/reviews/_form.html.erb @@ -1,4 +1,4 @@ -<%= form_for(@review) do |f| %> +<%= form_for [@product.user, @product, @review] do |f| %> <% if @review.errors.any? %>

<%= pluralize(@review.errors.count, "error") %> prohibited this review from being saved:

@@ -12,13 +12,9 @@ <% end %>
- <%= f.label :rating %>
+ <%= f.label :rating, "Rating (1-5)" %>
<%= f.number_field :rating %>
-
- <%= f.label :product_id %>
- <%= f.number_field :product_id %> -
<%= f.label :description %>
<%= f.text_field :description %> diff --git a/app/views/reviews/edit.html.erb b/app/views/reviews/edit.html.erb index 5ff0b89e40..6d89f204c5 100644 --- a/app/views/reviews/edit.html.erb +++ b/app/views/reviews/edit.html.erb @@ -2,5 +2,5 @@ <%= render 'form' %> -<%= link_to 'Show', user_product_review_path(@review.product_id, @user.id) %> | -<%= link_to 'Back', user_product_reviews_path(@review.product_id, @user.id) %> +<%= link_to 'Show', user_product_review_path(@product.user, @product, @review) %> | +<%= link_to 'Back', user_product_reviews_path(@product.user, @product) %> diff --git a/app/views/reviews/index.html.erb b/app/views/reviews/index.html.erb index 7a5d73b5c9..eabfaca9ca 100644 --- a/app/views/reviews/index.html.erb +++ b/app/views/reviews/index.html.erb @@ -6,7 +6,6 @@ Rating - Product Description @@ -16,7 +15,6 @@ <% @product.reviews.each do |review| %> <%= review.rating %> - <%= review.product_id %> <%= review.description %> <%= link_to 'Show', user_product_review_path(review.product.user, review.product, review) %> <%= link_to 'Edit', edit_user_product_review_path(review.product.user, review.product, review) %> diff --git a/app/views/reviews/new.html.erb b/app/views/reviews/new.html.erb index 7d54550cdd..5fb495a92f 100644 --- a/app/views/reviews/new.html.erb +++ b/app/views/reviews/new.html.erb @@ -2,4 +2,4 @@ <%= render 'form' %> -<%= link_to 'Back', user_product_reviews_path(@review.product_id, @user.id)%> +<%= link_to 'Back', user_product_reviews_path(@product.user, @product) %> From 0d3f13dfcd08b8784f34dc0ab437ff04af6bfbdc Mon Sep 17 00:00:00 2001 From: Tammy Date: Wed, 9 Dec 2015 10:56:08 -0800 Subject: [PATCH 042/299] we can add a new order --- app/controllers/orders_controller.rb | 6 ++++-- app/views/orders/_form.html.erb | 2 +- app/views/orders/edit.html.erb | 4 ++-- app/views/orders/new.html.erb | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index e3bdd17cb3..2b9c67d244 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -11,10 +11,12 @@ def show end def new + @user = User.find(params[:user_id]) @order = Order.new end def edit + @user = User.find(params[:user_id]) end @@ -23,9 +25,9 @@ def create respond_to do |format| if @order.save - format.html { redirect_to @order, notice: 'Order was successfully created.' } + redirect_to user_orders_path else - format.html { render :new } + render "new" end end end diff --git a/app/views/orders/_form.html.erb b/app/views/orders/_form.html.erb index bb9519ad22..aa5db6d095 100644 --- a/app/views/orders/_form.html.erb +++ b/app/views/orders/_form.html.erb @@ -1,4 +1,4 @@ -<%= form_for(@order) do |f| %> +<%= form_for [@user, @order] do |f| %> <% if @order.errors.any? %>

<%= pluralize(@order.errors.count, "error") %> prohibited this order from being saved:

diff --git a/app/views/orders/edit.html.erb b/app/views/orders/edit.html.erb index c621bd2ac5..37f5975e16 100644 --- a/app/views/orders/edit.html.erb +++ b/app/views/orders/edit.html.erb @@ -2,5 +2,5 @@ <%= render 'form' %> -<%= link_to 'Show', @order %> | -<%= link_to 'Back', orders_path %> +<%= link_to 'Show', user_order(@order, @user) %> | +<%= link_to 'Back', user_orders(@order, @user) %> diff --git a/app/views/orders/new.html.erb b/app/views/orders/new.html.erb index a7214a026a..006bd0ff4a 100644 --- a/app/views/orders/new.html.erb +++ b/app/views/orders/new.html.erb @@ -2,4 +2,4 @@ <%= render 'form' %> -<%= link_to 'Back', orders_path %> +<%= link_to 'Back', user_orders_path(@user.id, @order.id) %> From 5fe8d8ca0e7dc67b6335285b909787089731ff58 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Wed, 9 Dec 2015 11:00:31 -0800 Subject: [PATCH 043/299] add route to view all products --- app/views/products/index.html.erb | 5 +---- config/routes.rb | 1 + 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/views/products/index.html.erb b/app/views/products/index.html.erb index 22f5d284b9..256347ca9e 100644 --- a/app/views/products/index.html.erb +++ b/app/views/products/index.html.erb @@ -27,13 +27,10 @@ <%= product.description %> <%= product.active %> <%= link_to 'Show', user_product_path(product.id, product.user_id) %> - <%= link_to 'Edit', edit_user_product_path(product.id, product.user_id) %> - <%= link_to 'Destroy', user_product_path(product.id, product.user_id), method: :delete, data: { confirm: 'Are you sure?' } %> + <% end %>
- -<%= link_to 'New Product', new_user_product_path %> diff --git a/config/routes.rb b/config/routes.rb index 98c9853232..8f35ae6a21 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -12,6 +12,7 @@ end end + get 'products/' => 'products#index', as: :products get 'login/' => 'sessions#new', as: :login post 'login/' => 'sessions#create' delete 'logout/' => 'sessions#destroy', as: :logout From ef2b8a0d1d2e6669651b13293ef28b667089ead1 Mon Sep 17 00:00:00 2001 From: Kelly Date: Wed, 9 Dec 2015 11:04:49 -0800 Subject: [PATCH 044/299] Add error messages to review edit/new form --- app/controllers/reviews_controller.rb | 10 +++++++--- app/models/review.rb | 9 +-------- app/views/reviews/_form.html.erb | 18 +++++++----------- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb index caa7443ddb..9e867f062a 100644 --- a/app/controllers/reviews_controller.rb +++ b/app/controllers/reviews_controller.rb @@ -1,6 +1,6 @@ class ReviewsController < ApplicationController before_action :find_review, only: [:show, :edit, :update, :destroy] - before_action :find_product, only: [:new, :edit] + before_action :find_product, only: [:new, :edit, :create] def index @reviews = Review.all @@ -21,10 +21,14 @@ def edit def create - review = Review.create(review_params) do |r| + @review = Review.create(review_params) do |r| r.product_id = params[:product_id] end - redirect_to user_product_reviews_path(review.product.user, review.product, review) + if @review.save + redirect_to user_product_reviews_path(@review.product.user, @review.product, @review) + else + render :new + end end diff --git a/app/models/review.rb b/app/models/review.rb index 4261e1fe37..c6956125da 100644 --- a/app/models/review.rb +++ b/app/models/review.rb @@ -2,12 +2,5 @@ class Review < ActiveRecord::Base belongs_to :product validates :rating, presence: true - validates :rating, numericality: { :greater_than => 0, less_than: 6 } - - # - # def self.find_user_id(review) - # product = Product.find(review.product_id) - # return User.find(product.user_id).id - # end - + validates :rating, numericality: { greater_than: 0, less_than: 6, message: "must be between 1 and 5" } end diff --git a/app/views/reviews/_form.html.erb b/app/views/reviews/_form.html.erb index 731391ed88..74aa43154e 100644 --- a/app/views/reviews/_form.html.erb +++ b/app/views/reviews/_form.html.erb @@ -1,16 +1,12 @@ -<%= form_for [@product.user, @product, @review] do |f| %> - <% if @review.errors.any? %> -
-

<%= pluralize(@review.errors.count, "error") %> prohibited this review from being saved:

- -
    - <% @review.errors.full_messages.each do |message| %> -
  • <%= message %>
  • - <% end %> -
-
+
    + <% @review.errors.each do |column, message| %> +
  • + <%= column.capitalize %> <%= message %> +
  • <% end %> +
+<%= form_for [@product.user, @product, @review] do |f| %>
<%= f.label :rating, "Rating (1-5)" %>
<%= f.number_field :rating %> From e488ed840be4acf297b2a4f7b191af6d132802c2 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Wed, 9 Dec 2015 13:59:02 -0800 Subject: [PATCH 045/299] fix product active default field --- seeds_csvs/products.csv | 112 ++++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/seeds_csvs/products.csv b/seeds_csvs/products.csv index a35f55a349..1bd78ed782 100644 --- a/seeds_csvs/products.csv +++ b/seeds_csvs/products.csv @@ -1,56 +1,56 @@ -name,price,user_id,photo_url,stock,description,active -Relieved Dive Rings,599,1,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",11,Unbreakable rings stand up on the pool bottom for diving games. Set of 4., -Heavenly Inflatable Water Wheel,3795,1,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,2,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended.", -Two Shark Goggles,1196,1,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,11,Made using the highest quality materials, -Curved Swimming Fish Pool Toy,1399,1,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,1,, -Lavish Water Noodles,1143,1,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,1,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random., -Pumped Water Wings,690,1,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,4,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue, -Bouncy Dive Rings,599,2,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",14,Unbreakable rings stand up on the pool bottom for diving games. Set of 4., -Steep Dive Sticks,395,2,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,4,Sticks stand upright on pool bottom., -Sore Dory Doll,3000,2,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,3,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll", -Talented Inflatable Water Wheel,3795,2,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,12,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended.", -Young Swimming Fish Pool Toy,1399,2,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,8,, -Moldy Toypedo Bandits,615,2,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,15,Glides underwater up to 30 feet, -Courageous Water Noodles,1143,2,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,7,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random., -Guarded Water Wings,690,2,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,8,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue, -Crooked Dive Rings,599,3,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",2,Unbreakable rings stand up on the pool bottom for diving games. Set of 4., -Efficacious Dive Sticks,395,3,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,13,Sticks stand upright on pool bottom., -Wrong Finding Nemo DVD,1996,3,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,10,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination.", -Easy Inflatable Water Wheel,3795,3,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,1,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended.", -Unwieldy Puddle Jumper Life Jacket,1359,3,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,3,For children 30-50 lbs., -Near Shark Goggles,1196,3,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,8,Made using the highest quality materials, -Uppity Swimming Fish Pool Toy,1399,3,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,5,, -Black Toypedo Bandits,615,3,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,13,Glides underwater up to 30 feet, -Necessary Water Noodles,1143,3,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,9,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random., -Piquant Water Wings,690,3,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,11,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue, -Ripe Dive Sticks,395,4,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,1,Sticks stand upright on pool bottom., -Wandering Finding Nemo DVD,1996,4,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,5,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination.", -Stereotyped Inflatable Water Wheel,3795,4,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,1,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended.", -Soft Puddle Jumper Life Jacket,1359,4,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,5,For children 30-50 lbs., -Abrupt Shark Goggles,1196,4,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,13,Made using the highest quality materials, -Womanly Swimming Fish Pool Toy,1399,4,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,10,, -Minor Water Wings,690,4,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,11,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue, -Grateful Dive Rings,599,5,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",10,Unbreakable rings stand up on the pool bottom for diving games. Set of 4., -Stale Dory Doll,3000,5,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,6,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll", -Thundering Finding Nemo DVD,1996,5,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,9,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination.", -Right Dory Doll,3000,6,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,5,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll", -Petite Finding Nemo DVD,1996,6,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,13,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination.", -Spotty Water Wings,690,6,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,3,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue, -Ubiquitous Dive Sticks,395,7,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,15,Sticks stand upright on pool bottom., -Bustling Shark Goggles,1196,7,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,9,Made using the highest quality materials, -Wry Toypedo Bandits,615,7,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,3,Glides underwater up to 30 feet, -Squealing Water Noodles,1143,7,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,4,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random., -Adhesive Dive Sticks,395,8,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,11,Sticks stand upright on pool bottom., -Hissing Puddle Jumper Life Jacket,1359,8,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,1,For children 30-50 lbs., -Sloppy Puddle Jumper Life Jacket,1359,9,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,12,For children 30-50 lbs., -Hanging Shark Goggles,1196,8,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,5,Made using the highest quality materials, -Fumbling Toypedo Bandits,615,8,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,7,Glides underwater up to 30 feet, -Brief Dive Rings,599,9,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",10,Unbreakable rings stand up on the pool bottom for diving games. Set of 4., -Lean Dory Doll,3000,9,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,6,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll", -Giant Inflatable Water Wheel,3795,9,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,5,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended.", -Lazy Water Noodles,1143,9,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,10,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random., -Animated Dory Doll,3000,10,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,7,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll", -Ethereal Finding Nemo DVD,1996,10,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,14,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination.", -Regular Puddle Jumper Life Jacket,1359,10,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,2,For children 30-50 lbs., -Dizzy Swimming Fish Pool Toy,1399,10,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,9,, -Medical Toypedo Bandits,615,10,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,11,Glides underwater up to 30 feet, +name,price,user_id,photo_url,stock,description +Relieved Dive Rings,599,1,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",12,Unbreakable rings stand up on the pool bottom for diving games. Set of 4. +Heavenly Inflatable Water Wheel,3795,1,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,6,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended." +Two Shark Goggles,1196,1,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,7,Made using the highest quality materials +Curved Swimming Fish Pool Toy,1399,1,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,5, +Lavish Water Noodles,1143,1,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,7,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random. +Pumped Water Wings,690,1,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,9,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue +Bouncy Dive Rings,599,2,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",4,Unbreakable rings stand up on the pool bottom for diving games. Set of 4. +Steep Dive Sticks,395,2,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,11,Sticks stand upright on pool bottom. +Sore Dory Doll,3000,2,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,13,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll" +Talented Inflatable Water Wheel,3795,2,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,9,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended." +Young Swimming Fish Pool Toy,1399,2,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,9, +Moldy Toypedo Bandits,615,2,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,3,Glides underwater up to 30 feet +Courageous Water Noodles,1143,2,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,7,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random. +Guarded Water Wings,690,2,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,5,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue +Crooked Dive Rings,599,3,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",4,Unbreakable rings stand up on the pool bottom for diving games. Set of 4. +Efficacious Dive Sticks,395,3,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,12,Sticks stand upright on pool bottom. +Wrong Finding Nemo DVD,1996,3,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,6,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination." +Easy Inflatable Water Wheel,3795,3,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,15,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended." +Unwieldy Puddle Jumper Life Jacket,1359,3,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,4,For children 30-50 lbs. +Near Shark Goggles,1196,3,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,10,Made using the highest quality materials +Uppity Swimming Fish Pool Toy,1399,3,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,7, +Black Toypedo Bandits,615,3,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,6,Glides underwater up to 30 feet +Necessary Water Noodles,1143,3,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,5,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random. +Piquant Water Wings,690,3,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,5,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue +Ripe Dive Sticks,395,4,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,5,Sticks stand upright on pool bottom. +Wandering Finding Nemo DVD,1996,4,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,11,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination." +Stereotyped Inflatable Water Wheel,3795,4,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,15,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended." +Soft Puddle Jumper Life Jacket,1359,4,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,1,For children 30-50 lbs. +Abrupt Shark Goggles,1196,4,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,1,Made using the highest quality materials +Womanly Swimming Fish Pool Toy,1399,4,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,5, +Minor Water Wings,690,4,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,1,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue +Grateful Dive Rings,599,5,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",13,Unbreakable rings stand up on the pool bottom for diving games. Set of 4. +Stale Dory Doll,3000,5,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,13,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll" +Thundering Finding Nemo DVD,1996,5,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,4,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination." +Right Dory Doll,3000,6,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,6,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll" +Petite Finding Nemo DVD,1996,6,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,8,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination." +Spotty Water Wings,690,6,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,11,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue +Ubiquitous Dive Sticks,395,7,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,14,Sticks stand upright on pool bottom. +Bustling Shark Goggles,1196,7,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,15,Made using the highest quality materials +Wry Toypedo Bandits,615,7,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,7,Glides underwater up to 30 feet +Squealing Water Noodles,1143,7,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,3,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random. +Adhesive Dive Sticks,395,8,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,9,Sticks stand upright on pool bottom. +Hissing Puddle Jumper Life Jacket,1359,8,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,13,For children 30-50 lbs. +Sloppy Puddle Jumper Life Jacket,1359,9,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,7,For children 30-50 lbs. +Hanging Shark Goggles,1196,8,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,15,Made using the highest quality materials +Fumbling Toypedo Bandits,615,8,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,15,Glides underwater up to 30 feet +Brief Dive Rings,599,9,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",12,Unbreakable rings stand up on the pool bottom for diving games. Set of 4. +Lean Dory Doll,3000,9,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,10,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll" +Giant Inflatable Water Wheel,3795,9,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,7,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended." +Lazy Water Noodles,1143,9,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,3,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random. +Animated Dory Doll,3000,10,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,1,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll" +Ethereal Finding Nemo DVD,1996,10,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,2,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination." +Regular Puddle Jumper Life Jacket,1359,10,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,8,For children 30-50 lbs. +Dizzy Swimming Fish Pool Toy,1399,10,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,9, +Medical Toypedo Bandits,615,10,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,15,Glides underwater up to 30 feet From 77b209e296b87775a8fca68fc358a01b1de4aedf Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Wed, 9 Dec 2015 14:05:52 -0800 Subject: [PATCH 046/299] change products index links --- app/views/products/index.html.erb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/views/products/index.html.erb b/app/views/products/index.html.erb index 256347ca9e..552a37cf5c 100644 --- a/app/views/products/index.html.erb +++ b/app/views/products/index.html.erb @@ -32,5 +32,4 @@ <% end %> -
From 3c78d54f5f514fb9937072116065e820913eddf3 Mon Sep 17 00:00:00 2001 From: Kelly Date: Wed, 9 Dec 2015 14:06:38 -0800 Subject: [PATCH 047/299] update category and product controller for CRUD functions --- app/controllers/categories_controller.rb | 1 - app/views/categories/index.html.erb | 2 +- app/views/products/index.html.erb | 10 ++++++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb index cb09790c0b..61be22439c 100644 --- a/app/controllers/categories_controller.rb +++ b/app/controllers/categories_controller.rb @@ -1,7 +1,6 @@ class CategoriesController < ApplicationController before_action :set_category, only: [:show, :edit, :update, :destroy] - def index @categories = Category.all end diff --git a/app/views/categories/index.html.erb b/app/views/categories/index.html.erb index 03e485fa56..f0e18cca21 100644 --- a/app/views/categories/index.html.erb +++ b/app/views/categories/index.html.erb @@ -1,6 +1,6 @@

<%= notice %>

-

Listing Categories

+

Categories

diff --git a/app/views/products/index.html.erb b/app/views/products/index.html.erb index 22f5d284b9..c12c16abf3 100644 --- a/app/views/products/index.html.erb +++ b/app/views/products/index.html.erb @@ -11,7 +11,7 @@ - + @@ -25,7 +25,13 @@ - + From d0a8d20eccaf59621676910ef506f312c387cf36 Mon Sep 17 00:00:00 2001 From: Tammy Date: Wed, 9 Dec 2015 14:31:53 -0800 Subject: [PATCH 048/299] we can see the order items for each order --- app/controllers/order_items_controller.rb | 1 + app/controllers/orders_controller.rb | 3 ++- app/views/order_items/index.html.erb | 5 ++--- app/views/orders/show.html.erb | 6 +++--- db/migrate/20151209220657_add_shipped_to_order_item.rb | 5 +++++ db/schema.rb | 3 ++- 6 files changed, 15 insertions(+), 8 deletions(-) create mode 100644 db/migrate/20151209220657_add_shipped_to_order_item.rb diff --git a/app/controllers/order_items_controller.rb b/app/controllers/order_items_controller.rb index 01c40f558d..3d5fa3fcf3 100644 --- a/app/controllers/order_items_controller.rb +++ b/app/controllers/order_items_controller.rb @@ -2,6 +2,7 @@ class OrderItemsController < ApplicationController before_action :set_order_item, only: [:show, :edit, :update, :destroy] def index + @user = User.find(params[:user_id]) @order_items = OrderItem.all end diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index 2b9c67d244..90a7450787 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -8,10 +8,11 @@ def index def show + @user = User.find(params[:user_id]) end def new - @user = User.find(params[:user_id]) + c @order = Order.new end diff --git a/app/views/order_items/index.html.erb b/app/views/order_items/index.html.erb index f7494f2d76..0fc0a0c03e 100644 --- a/app/views/order_items/index.html.erb +++ b/app/views/order_items/index.html.erb @@ -18,9 +18,8 @@ - - - + + <% end %> diff --git a/app/views/orders/show.html.erb b/app/views/orders/show.html.erb index aec9e89e40..3978e28da6 100644 --- a/app/views/orders/show.html.erb +++ b/app/views/orders/show.html.erb @@ -45,6 +45,6 @@ <%= @order.cc_name %>

-<%= link_to 'Edit', edit_order_path(@order) %> | -<%= link_to 'Back', orders_path %> -<%= link_to 'Order Item', user_order_order_items_path(@order.id, @order.user_id) %> +<%= link_to 'Edit', edit_user_order_path(@user.id, @order.id) %> | +<%= link_to 'Back', user_orders_path(@user.id, @order.id) %> +<%= link_to 'Order Item', user_order_order_items_path(@user.id, @order.id) %> diff --git a/db/migrate/20151209220657_add_shipped_to_order_item.rb b/db/migrate/20151209220657_add_shipped_to_order_item.rb new file mode 100644 index 0000000000..831e4f8967 --- /dev/null +++ b/db/migrate/20151209220657_add_shipped_to_order_item.rb @@ -0,0 +1,5 @@ +class AddShippedToOrderItem < ActiveRecord::Migration + def change + add_column :order_items, :shipped, :boolean + end +end diff --git a/db/schema.rb b/db/schema.rb index 62a2c11562..f660b556dd 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20151209180323) do +ActiveRecord::Schema.define(version: 20151209220657) do create_table "categories", force: :cascade do |t| t.string "name" @@ -33,6 +33,7 @@ t.integer "quantity" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.boolean "shipped", default: false end create_table "orders", force: :cascade do |t| From 3fb166ec105fbb0e66e91b59e2bfa095fc2292bf Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Wed, 9 Dec 2015 15:26:03 -0800 Subject: [PATCH 049/299] working on homepage --- app/assets/images/banner.jpg | Bin 0 -> 80710 bytes app/assets/javascripts/application.js | 7 +++ app/assets/stylesheets/application.scss | 54 ++++++++++++++++++++++++ app/controllers/welcome_controller.rb | 1 + app/views/layouts/application.html.erb | 7 +-- app/views/shared/_navbar.html.erb | 40 ++++++++++++++++++ app/views/welcome/index.html.erb | 50 +++++++++++++++++++++- 7 files changed, 154 insertions(+), 5 deletions(-) create mode 100644 app/assets/images/banner.jpg create mode 100644 app/views/shared/_navbar.html.erb diff --git a/app/assets/images/banner.jpg b/app/assets/images/banner.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1b8188c7e3dd88eeab2c92ec9fba884d2b189459 GIT binary patch literal 80710 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 - -<%= yield %> - +
+ <%= render 'shared/navbar' %> +
+ <%= yield %> diff --git a/app/views/shared/_navbar.html.erb b/app/views/shared/_navbar.html.erb new file mode 100644 index 0000000000..4c6573a1e1 --- /dev/null +++ b/app/views/shared/_navbar.html.erb @@ -0,0 +1,40 @@ + diff --git a/app/views/welcome/index.html.erb b/app/views/welcome/index.html.erb index 0a01a01efe..e7b54812e4 100644 --- a/app/views/welcome/index.html.erb +++ b/app/views/welcome/index.html.erb @@ -1,2 +1,48 @@ -

Welcome#index

-

Find me in app/views/welcome/index.html.erb

+
+

Wetsy Homepage

+
+
+

Find the Best Products for Fun Water Times

+ <%= link_to "Browse All Products", products_path, class: "text-center" %> +
+ <% count = 0 %> + <% @products.each do |product| %> + <% if count % 4 == 0 %> +
+ <% end %> +
+
+
+ <%= image_tag product.photo_url, alt: "product photo" %> + +
+
+

$<%= product.price %>

+

<%= link_to product.name, user_product_path(product.user_id, product.id) %> +

+

+ <% if !product.description.nil? %> + <%= product.description %> + <% else %> +
+ <% end %> +

+
+
+

<%= pluralize(product.reviews.count, "Review") %>

+

+ + + + + +

+
+
+
+ <% count += 1 %> + <% if count % 4 == 0 %> +
+ <% end %> + <% end %> +
From 576beee3539f55b386791fda3dc9041dbb722845 Mon Sep 17 00:00:00 2001 From: Tammy Date: Wed, 9 Dec 2015 15:26:53 -0800 Subject: [PATCH 050/299] can see an order item --- app/controllers/order_items_controller.rb | 1 + app/views/order_items/show.html.erb | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/controllers/order_items_controller.rb b/app/controllers/order_items_controller.rb index 3d5fa3fcf3..5175dbe275 100644 --- a/app/controllers/order_items_controller.rb +++ b/app/controllers/order_items_controller.rb @@ -7,6 +7,7 @@ def index end def show + @user = User.find(params[:user_id]) end def new diff --git a/app/views/order_items/show.html.erb b/app/views/order_items/show.html.erb index e49f9e28cd..84b0c421d5 100644 --- a/app/views/order_items/show.html.erb +++ b/app/views/order_items/show.html.erb @@ -15,5 +15,5 @@ <%= @order_item.quantity %>

-<%= link_to 'Edit', edit_order_item_path(@order_item, @user, @order) %> | -<%= link_to 'Back', user_order_order_items_path(@user, @order) %> +<%= link_to 'Edit', edit_user_order_order_item_path(@order_item.id, @user.id, @order_item.order_id) %> | +<%= link_to 'Back', user_order_order_items_path(@user.id, @order_item.order_id) %> From 2256a73168af1cddae40e0b55593e09815c5f7b2 Mon Sep 17 00:00:00 2001 From: Kelly Date: Wed, 9 Dec 2015 15:26:55 -0800 Subject: [PATCH 051/299] update user products routes --- app/controllers/users_controller.rb | 7 ++++++- app/views/users/index.html.erb | 2 -- app/views/users/show.html.erb | 1 - config/routes.rb | 2 ++ 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 2f13e5beb6..a4302cb05b 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,5 +1,5 @@ class UsersController < ApplicationController - before_action :set_user, only: [:show, :edit, :update, :destroy] + before_action :set_user, only: [:show, :edit, :update, :destroy, :products] def index @@ -14,6 +14,11 @@ def new @user = User.new end + def products + @products = @user.products + + end + def edit end diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb index ea5f6fc407..bb6342973b 100644 --- a/app/views/users/index.html.erb +++ b/app/views/users/index.html.erb @@ -7,7 +7,6 @@
- @@ -18,7 +17,6 @@ - diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index dbe58b71dc..5af6dd897b 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -22,5 +22,4 @@ <%= link_to 'Edit', edit_user_path(@user) %> | <%= link_to 'Back', users_path %> -<%= link_to 'Products', user_products_path(@user) %> <%= link_to 'Orders', user_orders_path(@user) %> diff --git a/config/routes.rb b/config/routes.rb index 8f35ae6a21..a7ec3930a2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,8 @@ Rails.application.routes.draw do root 'welcome#index' + get "/users/:id/products" => "users#products" + resources :categories resources :users do From c333d8faf6c83757d750f8aa2928021566d0c791 Mon Sep 17 00:00:00 2001 From: Tammy Date: Wed, 9 Dec 2015 15:38:04 -0800 Subject: [PATCH 052/299] I set a default value to shipped in order item --- app/controllers/order_items_controller.rb | 2 ++ app/views/order_items/_form.html.erb | 2 +- db/migrate/20151209220657_add_shipped_to_order_item.rb | 2 +- db/schema.rb | 6 +++--- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/controllers/order_items_controller.rb b/app/controllers/order_items_controller.rb index 5175dbe275..2e793002e7 100644 --- a/app/controllers/order_items_controller.rb +++ b/app/controllers/order_items_controller.rb @@ -12,9 +12,11 @@ def show def new @order_item = OrderItem.new + @user = User.find(params[:user_id]) end def edit + @user = User.find(params[:user_id]) end def create diff --git a/app/views/order_items/_form.html.erb b/app/views/order_items/_form.html.erb index 47d9231acc..6a18e75111 100644 --- a/app/views/order_items/_form.html.erb +++ b/app/views/order_items/_form.html.erb @@ -1,4 +1,4 @@ -<%= form_for(@order_item) do |f| %> +<%= form_for[@user, @order_item] do |f| %>
<%= f.label :product_id %>
<%= f.number_field :product_id %> diff --git a/db/migrate/20151209220657_add_shipped_to_order_item.rb b/db/migrate/20151209220657_add_shipped_to_order_item.rb index 831e4f8967..e05fef8555 100644 --- a/db/migrate/20151209220657_add_shipped_to_order_item.rb +++ b/db/migrate/20151209220657_add_shipped_to_order_item.rb @@ -1,5 +1,5 @@ class AddShippedToOrderItem < ActiveRecord::Migration def change - add_column :order_items, :shipped, :boolean + add_column :order_items, :shipped, :boolean, :default => 0 end end diff --git a/db/schema.rb b/db/schema.rb index f660b556dd..795cbc39b2 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -31,9 +31,9 @@ t.integer "product_id" t.integer "order_id" t.integer "quantity" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.boolean "shipped", default: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.boolean "shipped", default: false end create_table "orders", force: :cascade do |t| From 69ee8fabe115ad3e2a5f3ccfe4879de7de4aa7c3 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Wed, 9 Dec 2015 15:46:27 -0800 Subject: [PATCH 053/299] fix image resize and vertical centering --- app/assets/javascripts/application.js | 7 +++++++ app/assets/stylesheets/application.scss | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 452a884c40..b7483a4ce2 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -22,3 +22,10 @@ $(document).ready(function() { console.log(width); $('.img-container').css({ "height": width+"px" }); }); + +$(window).resize(function() { + var thumb = document.getElementsByClassName('thumbnail')[0]; + var width = thumb.clientWidth; + console.log(width); + $('.img-container').css({ "height": width+"px" }); +}); diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index f4e72d0275..fb3da2c6ec 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -31,6 +31,18 @@ .thumbnail img { width: 100%; + margin: auto; +} + +.img-container { + -webkit-transform-style: preserve-3d; + -moz-transform-style: preserve-3d; + transform-style: preserve-3d; + img { + position: relative; + top: 50%; + transform: translateY(-50%); + } } .ratings { From 4e5a98eb90225fcd6b7c70993eceb1ab4868f2bb Mon Sep 17 00:00:00 2001 From: Kelly Date: Wed, 9 Dec 2015 15:48:33 -0800 Subject: [PATCH 054/299] fixed product#index routes --- app/views/products/index.html.erb | 43 ++--------------------------- app/views/shared/_products.html.erb | 38 +++++++++++++++++++++++++ app/views/users/products.html.erb | 2 ++ app/views/users/show.html.erb | 6 +--- config/routes.rb | 4 +-- db/schema.rb | 2 +- 6 files changed, 46 insertions(+), 49 deletions(-) create mode 100644 app/views/shared/_products.html.erb create mode 100644 app/views/users/products.html.erb diff --git a/app/views/products/index.html.erb b/app/views/products/index.html.erb index 71d7410bd2..3b9847992f 100644 --- a/app/views/products/index.html.erb +++ b/app/views/products/index.html.erb @@ -1,41 +1,2 @@ -

<%= notice %>

- -

Listing Products

- -
Photo url Stock DescriptionActiveStatus
<%= product.photo_url %> <%= product.stock %> <%= product.description %><%= product.active %> + <% if product.active %> + Active + <% else %> + Retired + <% end %> + <%= link_to 'Show', user_product_path(product.id, product.user_id) %> <%= link_to 'Edit', edit_user_product_path(product.id, product.user_id) %> <%= link_to 'Destroy', user_product_path(product.id, product.user_id), method: :delete, data: { confirm: 'Are you sure?' } %><%= order_item.product_id %> <%= order_item.order_id %> <%= order_item.quantity %><%= link_to 'Show', user_order_order_item_path %><%= link_to 'Destroy', order_item, method: :delete, data: { confirm: 'Are you sure?' } %><%= link_to 'Show', user_order_order_item_path(order_item.id, @user.id, order_item.order) %><%= link_to 'Destroy', user_order_order_item_path(order_item.id, @user.id, order_item.order), method: :delete, data: { confirm: 'Are you sure?' } %>
Username EmailPassword digest Name
<%= user.username %> <%= user.email %><%= user.password_digest %> <%= user.name %> <%= link_to 'Show', user %> <%= link_to 'Edit', edit_user_path(user) %>
- - - - - - - - - - - - - - - <% @products.each do |product| %> - - - - - - - - - - - - <% end %> - -
NamePriceUserPhoto urlStockDescriptionStatus
<%= product.name %><%= product.price %><%= product.user_id %><%= product.photo_url %><%= product.stock %><%= product.description %> - <% if product.active %> - Active - <% else %> - Retired - <% end %> - <%= link_to 'Show', user_product_path(product.id, product.user_id) %>
-
+

All Products

+<%= render partial: 'shared/products' %> diff --git a/app/views/shared/_products.html.erb b/app/views/shared/_products.html.erb new file mode 100644 index 0000000000..aa3d823e2b --- /dev/null +++ b/app/views/shared/_products.html.erb @@ -0,0 +1,38 @@ +

<%= notice %>

+ + + + + + + + + + + + + + + + <% @products.each do |product| %> + + + + + + + + + + + + <% end %> + +
NamePriceUserPhoto urlStockDescriptionStatus
<%= product.name %><%= product.price %><%= product.name %><%= product.photo_url %><%= product.stock %><%= product.description %> + <% if product.active %> + Active + <% else %> + Retired + <% end %> + <%= link_to 'Show', user_product_path(product.id, product.user_id) %>
+
diff --git a/app/views/users/products.html.erb b/app/views/users/products.html.erb new file mode 100644 index 0000000000..f7c62ac7eb --- /dev/null +++ b/app/views/users/products.html.erb @@ -0,0 +1,2 @@ +

<%= @user.name %>'s Products

+<%= render partial: 'shared/products' %> diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index 5af6dd897b..7212ded20e 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -10,11 +10,6 @@ <%= @user.email %>

-

- Password digest: - <%= @user.password_digest %> -

-

Name: <%= @user.name %> @@ -23,3 +18,4 @@ <%= link_to 'Edit', edit_user_path(@user) %> | <%= link_to 'Back', users_path %> <%= link_to 'Orders', user_orders_path(@user) %> +<%= link_to "Products", user_products_path(@user) %> diff --git a/config/routes.rb b/config/routes.rb index a7ec3930a2..8c8febb87b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,7 @@ Rails.application.routes.draw do root 'welcome#index' - get "/users/:id/products" => "users#products" + get "/users/:id/products" => "users#products", as: :user_products resources :categories @@ -9,7 +9,7 @@ resources :orders do resources :order_items end - resources :products do + resources :products, except: :index do resources :reviews end end diff --git a/db/schema.rb b/db/schema.rb index f660b556dd..7b991de9f5 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -33,7 +33,7 @@ t.integer "quantity" t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.boolean "shipped", default: false + t.boolean "shipped" end create_table "orders", force: :cascade do |t| From a707283760038f27a57f10a38f4be38a26992c71 Mon Sep 17 00:00:00 2001 From: Tammy Date: Wed, 9 Dec 2015 15:53:15 -0800 Subject: [PATCH 055/299] we're in a good point --- app/views/order_items/_form.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/order_items/_form.html.erb b/app/views/order_items/_form.html.erb index 6a18e75111..ec7bff1664 100644 --- a/app/views/order_items/_form.html.erb +++ b/app/views/order_items/_form.html.erb @@ -1,4 +1,4 @@ -<%= form_for[@user, @order_item] do |f| %> +<%= form_for [@user, @order_item, @order_item.order] do |f| %>

<%= f.label :product_id %>
<%= f.number_field :product_id %> From e8e1433909acfc02b5f0de31cbeaba28de806a84 Mon Sep 17 00:00:00 2001 From: Tammy Date: Thu, 10 Dec 2015 08:43:55 -0800 Subject: [PATCH 056/299] add a link to order iteams inside list of orders --- app/views/orders/index.html.erb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/orders/index.html.erb b/app/views/orders/index.html.erb index cfea60b99c..b0d9c0da21 100644 --- a/app/views/orders/index.html.erb +++ b/app/views/orders/index.html.erb @@ -33,6 +33,7 @@ <%= link_to 'Show', user_order_path(@user.id, order.id) %> <%= link_to 'Edit', edit_user_order_path(@user.id, order.id) %> <%= link_to 'Destroy', user_order_path(@user.id, order.id), method: :delete, data: { confirm: 'Are you sure?' } %> + <%= link_to 'Order items', user_order_order_items_path(@user.id, order.id) %> <% end %> From 8ed7436158043f37142b04a47d8c29443907a48a Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 10 Dec 2015 09:00:45 -0800 Subject: [PATCH 057/299] add fonts to homepage --- app/assets/stylesheets/application.scss | 20 ++++++++++++++++++++ app/views/welcome/index.html.erb | 5 ++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index fb3da2c6ec..7e24fcf458 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -14,6 +14,26 @@ @import "bootstrap-sprockets"; @import "bootstrap"; + @import url(https://fonts.googleapis.com/css?family=Slabo+27px); + @import url(https://fonts.googleapis.com/css?family=Lato); + @import url(https://fonts.googleapis.com/css?family=Lora); + +$header_font: 'Slabo 27px', serif; +$small_header_font: 'Lora', serif; +$body-font: 'Lato', sans-serif; + +h1 { + font-family: $header_font; +} + +body { + font-family: $body-font; +} + +h5 { + font-family: $small_header_font; +} + .jumbotron { position: relative; diff --git a/app/views/welcome/index.html.erb b/app/views/welcome/index.html.erb index e7b54812e4..b4b2869fd3 100644 --- a/app/views/welcome/index.html.erb +++ b/app/views/welcome/index.html.erb @@ -14,11 +14,10 @@
<%= image_tag product.photo_url, alt: "product photo" %> -
-

$<%= product.price %>

-

<%= link_to product.name, user_product_path(product.user_id, product.id) %> +

$<%= product.price %>
+
<%= link_to product.name, user_product_path(product.user_id, product.id) %>

<% if !product.description.nil? %> From fda19f4fd54aa6f8bad79ac199b52a860225f019 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 10 Dec 2015 09:16:58 -0800 Subject: [PATCH 058/299] fix displaying dollars on the homepage --- app/helpers/application_helper.rb | 3 +++ app/views/welcome/index.html.erb | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index de6be7945c..d7cff93e87 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,2 +1,5 @@ module ApplicationHelper + def dollar_price(amount) + number_to_currency(amount / 100.0) + end end diff --git a/app/views/welcome/index.html.erb b/app/views/welcome/index.html.erb index b4b2869fd3..ac40a67526 100644 --- a/app/views/welcome/index.html.erb +++ b/app/views/welcome/index.html.erb @@ -16,7 +16,7 @@ <%= image_tag product.photo_url, alt: "product photo" %>

-
$<%= product.price %>
+
<%= dollar_price(product.price) %>
<%= link_to product.name, user_product_path(product.user_id, product.id) %>

From 2378b1c5ffd3514ab720a76fe627e6c07029344b Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 10 Dec 2015 09:27:32 -0800 Subject: [PATCH 059/299] add pagination to product lists --- Gemfile | 2 ++ Gemfile.lock | 2 ++ app/controllers/products_controller.rb | 2 +- app/controllers/users_controller.rb | 4 ++-- app/views/shared/_products.html.erb | 3 ++- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index fd91f07fa8..afe58860a8 100644 --- a/Gemfile +++ b/Gemfile @@ -29,6 +29,8 @@ gem 'bootstrap-sass', '~> 3.3.5' gem 'simplecov', :require => false, :group => :test +gem 'will_paginate' + # Use Unicorn as the app server # gem 'unicorn' diff --git a/Gemfile.lock b/Gemfile.lock index 6380fca4b2..c9418ea29b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -181,6 +181,7 @@ GEM binding_of_caller (>= 0.7.2) railties (>= 4.0) sprockets-rails (>= 2.0, < 4.0) + will_paginate (3.0.7) PLATFORMS ruby @@ -206,6 +207,7 @@ DEPENDENCIES turbolinks uglifier (>= 1.3.0) web-console (~> 2.0) + will_paginate BUNDLED WITH 1.10.6 diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index 4f31251250..43b38625cf 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -2,7 +2,7 @@ class ProductsController < ApplicationController before_action :set_product, only: [:show, :edit, :update, :destroy] def index - @products = Product.all + @products = Product.all.paginate(page: params[:page], per_page: 12) end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index a4302cb05b..6775411803 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -15,8 +15,8 @@ def new end def products - @products = @user.products - + @products = @user.products.paginate(page: params[:page], per_page: 12) + end diff --git a/app/views/shared/_products.html.erb b/app/views/shared/_products.html.erb index aa3d823e2b..c7543ff0ea 100644 --- a/app/views/shared/_products.html.erb +++ b/app/views/shared/_products.html.erb @@ -1,3 +1,4 @@ +<%= will_paginate @products %>

<%= notice %>

@@ -35,4 +36,4 @@ <% end %>
-
+<%= will_paginate @products %> From 5c3d9f62e13603a4e48e76380e10e259d7275606 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 10 Dec 2015 09:36:18 -0800 Subject: [PATCH 060/299] add user validation for lowercase email address --- app/models/user.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/user.rb b/app/models/user.rb index 251f26d9a1..30b7843a23 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -2,6 +2,8 @@ class User < ActiveRecord::Base has_many :products has_secure_password + before_save { self.email = email.downcase } # ensures emails are all lowercase + validates :username, :email, presence: true validates :username, :email, uniqueness: true validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i } From f704d1d4c5eb109a0f7f04e9b84edfef59ab2932 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 10 Dec 2015 11:36:11 -0800 Subject: [PATCH 061/299] refactor homepage to use groups for rows --- app/views/welcome/index.html.erb | 66 +++++++++++++++----------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/app/views/welcome/index.html.erb b/app/views/welcome/index.html.erb index ac40a67526..edd48344e8 100644 --- a/app/views/welcome/index.html.erb +++ b/app/views/welcome/index.html.erb @@ -5,43 +5,39 @@

Find the Best Products for Fun Water Times

<%= link_to "Browse All Products", products_path, class: "text-center" %>
- <% count = 0 %> - <% @products.each do |product| %> - <% if count % 4 == 0 %> + <% @products.to_ary.in_groups_of(4, false) do |group| %>
- <% end %> -
-
-
- <%= image_tag product.photo_url, alt: "product photo" %> -
-
-
<%= dollar_price(product.price) %>
-
<%= link_to product.name, user_product_path(product.user_id, product.id) %> -
-

- <% if !product.description.nil? %> - <%= product.description %> - <% else %> -
- <% end %> -

-
-
-

<%= pluralize(product.reviews.count, "Review") %>

-

- - - - - -

+ <% group.each do |product| %> +
+
+
+ <%= image_tag product.photo_url, alt: "product photo" %> +
+
+
<%= dollar_price(product.price) %>
+
<%= link_to product.name, user_product_path(product.user_id, product.id) %> +
+

+ <% if !product.description.nil? %> + <%= product.description %> + <% else %> +
+ <% end %> +

+
+
+

<%= pluralize(product.reviews.count, "Review") %>

+

+ + + + + +

+
-
-
- <% count += 1 %> - <% if count % 4 == 0 %> +
+ <% end %>
<% end %> - <% end %>
From b7cc6f1884db84eb18613194d3bfdf8392b70086 Mon Sep 17 00:00:00 2001 From: Tammy Date: Thu, 10 Dec 2015 11:40:08 -0800 Subject: [PATCH 062/299] can create new order --- app/controllers/order_items_controller.rb | 4 +++- app/views/order_items/_form.html.erb | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/controllers/order_items_controller.rb b/app/controllers/order_items_controller.rb index 2e793002e7..b154380fa5 100644 --- a/app/controllers/order_items_controller.rb +++ b/app/controllers/order_items_controller.rb @@ -12,6 +12,7 @@ def show def new @order_item = OrderItem.new + @order = Order.find(params[:order_id]) @user = User.find(params[:user_id]) end @@ -20,9 +21,10 @@ def edit end def create + @user = User.find(params[:user_id]) @order_item = OrderItem.new(order_item_params) if @order_item.save - redirect_to user_order_order_items_path + redirect_to user_order_order_items_path(@user, @user.order) else render "new" end diff --git a/app/views/order_items/_form.html.erb b/app/views/order_items/_form.html.erb index ec7bff1664..c70c72631e 100644 --- a/app/views/order_items/_form.html.erb +++ b/app/views/order_items/_form.html.erb @@ -1,4 +1,4 @@ -<%= form_for [@user, @order_item, @order_item.order] do |f| %> +<%= form_for [@user,@order, @order_item] do |f| %>
<%= f.label :product_id %>
<%= f.number_field :product_id %> From 34b5245d992f4b466f83621e0e6226b9b61a0f15 Mon Sep 17 00:00:00 2001 From: Tammy Date: Thu, 10 Dec 2015 11:49:52 -0800 Subject: [PATCH 063/299] create new order item --- app/controllers/order_items_controller.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/controllers/order_items_controller.rb b/app/controllers/order_items_controller.rb index b154380fa5..3bccc4d855 100644 --- a/app/controllers/order_items_controller.rb +++ b/app/controllers/order_items_controller.rb @@ -22,9 +22,10 @@ def edit def create @user = User.find(params[:user_id]) + @order = Order.find(params[:order_id]) @order_item = OrderItem.new(order_item_params) if @order_item.save - redirect_to user_order_order_items_path(@user, @user.order) + redirect_to user_order_order_items_path(@user,@order.id) else render "new" end From 4e0c82d50e3c8d75f9ab755012cfbaf5df249cc8 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 10 Dec 2015 11:55:56 -0800 Subject: [PATCH 064/299] edit user products view page --- app/assets/stylesheets/application.scss | 9 ++++ app/views/shared/_products.html.erb | 67 ++++++++++++------------- app/views/welcome/index.html.erb | 2 + 3 files changed, 42 insertions(+), 36 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 7e24fcf458..fffa67374b 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -75,6 +75,15 @@ h5 { padding: 0; } +.caption { + height: 130px; + overflow: hidden; +} + +.caption h4 { + white-space: nowrap; +} + .thumbnail .caption-full { padding: 9px; color: #333; diff --git a/app/views/shared/_products.html.erb b/app/views/shared/_products.html.erb index c7543ff0ea..1a71f0a1c1 100644 --- a/app/views/shared/_products.html.erb +++ b/app/views/shared/_products.html.erb @@ -1,39 +1,34 @@ <%= will_paginate @products %> -

<%= notice %>

- - - - - - - - - - - - - +
+ <% @products.to_ary.in_groups_of(4, false) do |group| %> +
+ <% group.each do |product| %> +
+
+
+ <%= image_tag product.photo_url, alt: "product photo" %> +
+
+
<%= dollar_price(product.price) %>
+
<%= link_to product.name, user_product_path(product.user_id, product.id) %> +
+

+ <% if !product.description.nil? %> + <%= product.description %> + <% else %> +
+ <% end %> +

+

<%= product.stock %> Available

+

+ <%= link_to "Edit item", edit_user_product_path(product.user.id, product.id) %> +

+

<%= link_to "View Reviews", user_product_reviews_path(product.user.id, product.id) %>

+
+
+
+ <% end %> +
+ <% end %> -
- <% @products.each do |product| %> - - - - - - - - - - - - <% end %> - -
NamePriceUserPhoto urlStockDescriptionStatus
<%= product.name %><%= product.price %><%= product.name %><%= product.photo_url %><%= product.stock %><%= product.description %> - <% if product.active %> - Active - <% else %> - Retired - <% end %> - <%= link_to 'Show', user_product_path(product.id, product.user_id) %>
<%= will_paginate @products %> diff --git a/app/views/welcome/index.html.erb b/app/views/welcome/index.html.erb index edd48344e8..da1aebf980 100644 --- a/app/views/welcome/index.html.erb +++ b/app/views/welcome/index.html.erb @@ -24,6 +24,7 @@
<% end %>

+

<%= product.stock %> Available

<%= pluralize(product.reviews.count, "Review") %>

@@ -35,6 +36,7 @@

+
<% end %> From 58d821384934f8998b6a2ee735bd7cd42ce9908d Mon Sep 17 00:00:00 2001 From: Tammy Date: Thu, 10 Dec 2015 11:57:01 -0800 Subject: [PATCH 065/299] completed CRUD for order items --- app/controllers/order_items_controller.rb | 6 +++++- app/views/order_items/index.html.erb | 4 ++-- app/views/order_items/show.html.erb | 2 +- db/schema.rb | 3 --- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/controllers/order_items_controller.rb b/app/controllers/order_items_controller.rb index 3bccc4d855..1099037bbb 100644 --- a/app/controllers/order_items_controller.rb +++ b/app/controllers/order_items_controller.rb @@ -18,6 +18,8 @@ def new def edit @user = User.find(params[:user_id]) + @order = Order.find(params[:order_id]) + @user = User.find(params[:user_id]) end def create @@ -37,8 +39,10 @@ def update end def destroy + @user = User.find(params[:user_id]) + @order = Order.find(params[:order_id]) @order_item.destroy - redirect_to user_order_order_items_path + redirect_to user_order_order_items_path(@user, @order) end private diff --git a/app/views/order_items/index.html.erb b/app/views/order_items/index.html.erb index 0fc0a0c03e..af17e45fc5 100644 --- a/app/views/order_items/index.html.erb +++ b/app/views/order_items/index.html.erb @@ -18,8 +18,8 @@ <%= order_item.product_id %> <%= order_item.order_id %> <%= order_item.quantity %> - <%= link_to 'Show', user_order_order_item_path(order_item.id, @user.id, order_item.order) %> - <%= link_to 'Destroy', user_order_order_item_path(order_item.id, @user.id, order_item.order), method: :delete, data: { confirm: 'Are you sure?' } %> + <%= link_to 'Show', user_order_order_item_path(@user.id, order_item.order, order_item.id) %> + <%= link_to 'Destroy', user_order_order_item_path(@user.id, order_item.order, order_item.id), method: :delete, data: { confirm: 'Are you sure?' } %> <% end %> diff --git a/app/views/order_items/show.html.erb b/app/views/order_items/show.html.erb index 84b0c421d5..0f26c96879 100644 --- a/app/views/order_items/show.html.erb +++ b/app/views/order_items/show.html.erb @@ -15,5 +15,5 @@ <%= @order_item.quantity %>

-<%= link_to 'Edit', edit_user_order_order_item_path(@order_item.id, @user.id, @order_item.order_id) %> | +<%= link_to 'Edit', edit_user_order_order_item_path(@user.id, @order_item.order_id, @order_item.id) %> | <%= link_to 'Back', user_order_order_items_path(@user.id, @order_item.order_id) %> diff --git a/db/schema.rb b/db/schema.rb index 97ae3f7cc0..795cbc39b2 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -31,9 +31,6 @@ t.integer "product_id" t.integer "order_id" t.integer "quantity" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.boolean "shipped" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.boolean "shipped", default: false From af2b46129fc4623c62ca49c7360245510ba6f65c Mon Sep 17 00:00:00 2001 From: Kelly Date: Thu, 10 Dec 2015 12:18:17 -0800 Subject: [PATCH 066/299] Update product#new and product#create --- app/controllers/products_controller.rb | 19 ++++++++++++------- app/views/products/_form.html.erb | 18 ++++++------------ app/views/products/new.html.erb | 2 +- app/views/shared/_products.html.erb | 4 +--- app/views/users/products.html.erb | 1 + 5 files changed, 21 insertions(+), 23 deletions(-) diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index 43b38625cf..7f24790b5d 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -12,18 +12,23 @@ def show def new @product = Product.new + @user = User.find(params[:user_id]) end def edit + @user = User.find(params[:user_id]) end def create - @product = Product.new(product_params) - if @product.save - format.html { redirect_to @product, notice: 'Product was successfully created.' } - else - format.html { render :new } - end + @user = User.find(params[:user_id]) + @product = Product.create(product_params) do |p| + p.user_id = @user.id + end + if @product.save + redirect_to user_products_path(@product.user) + else + render :new + end end def update @@ -46,6 +51,6 @@ def set_product end def product_params - params.require(:product).permit(:name, :price, :user_id, :photo_url, :stock, :description, :active) + params.require(:product).permit(:name, :price, :photo_url, :stock, :description, :active) end end diff --git a/app/views/products/_form.html.erb b/app/views/products/_form.html.erb index f5e6581263..f85fb94c42 100644 --- a/app/views/products/_form.html.erb +++ b/app/views/products/_form.html.erb @@ -1,9 +1,6 @@ - -<%= form_for [@product.user, @product] do |f| %> +<%= form_for [@user, @product] do |f| %> <% if @product.errors.any? %>
-

<%= pluralize(@product.errors.count, "error") %> prohibited this product from being saved:

-
    <% @product.errors.full_messages.each do |message| %>
  • <%= message %>
  • @@ -14,25 +11,22 @@
    - <%= f.label :name %>
    + <%= f.label :name %> <%= f.text_field :name %> - <%= f.label :price %>
    + <%= f.label :price %> <%= f.number_field :price %> - <%= f.label :user_id %>
    - <%= f.number_field :user_id %> - - <%= f.label :photo_url %>
    + <%= f.label :photo_url %> <%= f.text_field :photo_url %> <%= f.label :stock %> <%= f.number_field :stock %> - <%= f.label :description %>
    + <%= f.label :description %> <%= f.text_field :description %> - <%= f.label :active %>
    + <%= f.label :active %> <%= f.check_box :active %> <%= f.submit %> diff --git a/app/views/products/new.html.erb b/app/views/products/new.html.erb index 058db423a6..60c4a84a61 100644 --- a/app/views/products/new.html.erb +++ b/app/views/products/new.html.erb @@ -2,4 +2,4 @@ <%= render 'form' %> -<%= link_to 'Back', user_products_path %> +<%= link_to 'Back', user_products_path(@user) %> diff --git a/app/views/shared/_products.html.erb b/app/views/shared/_products.html.erb index c7543ff0ea..4b46f31bb4 100644 --- a/app/views/shared/_products.html.erb +++ b/app/views/shared/_products.html.erb @@ -5,7 +5,6 @@ Name Price - User Photo url Stock Description @@ -19,7 +18,6 @@ <%= product.name %> <%= product.price %> - <%= product.name %> <%= product.photo_url %> <%= product.stock %> <%= product.description %> @@ -30,7 +28,7 @@ Retired <% end %> - <%= link_to 'Show', user_product_path(product.id, product.user_id) %> + <%= link_to 'Show', user_product_path(product.user_id, product.id) %> <% end %> diff --git a/app/views/users/products.html.erb b/app/views/users/products.html.erb index f7c62ac7eb..65e7cdadee 100644 --- a/app/views/users/products.html.erb +++ b/app/views/users/products.html.erb @@ -1,2 +1,3 @@

    <%= @user.name %>'s Products

    <%= render partial: 'shared/products' %> +<%= link_to "Add a Product", new_user_product_path(@user) %> From 1471548cb80a0625d2ef018f94e951cae568e44b Mon Sep 17 00:00:00 2001 From: Kelly Date: Thu, 10 Dec 2015 12:23:04 -0800 Subject: [PATCH 067/299] resolve merge conflicts take 2 --- app/views/shared/_products.html.erb | 35 ----------------------------- 1 file changed, 35 deletions(-) diff --git a/app/views/shared/_products.html.erb b/app/views/shared/_products.html.erb index 53d3206dd7..1a71f0a1c1 100644 --- a/app/views/shared/_products.html.erb +++ b/app/views/shared/_products.html.erb @@ -1,39 +1,4 @@ <%= will_paginate @products %> -

    <%= notice %>

    - - - - - - - - - - - - - - - <% @products.each do |product| %> - - - - - - - - - - - <% end %> - -
    NamePricePhoto urlStockDescriptionStatus
    <%= product.name %><%= product.price %><%= product.photo_url %><%= product.stock %><%= product.description %> - <% if product.active %> - Active - <% else %> - Retired - <% end %> - <%= link_to 'Show', user_product_path(product.user_id, product.id) %>
    <% @products.to_ary.in_groups_of(4, false) do |group| %>
    From c27a85c3ce4544967ad99e375d09b47fefbbfe70 Mon Sep 17 00:00:00 2001 From: Tammy Date: Thu, 10 Dec 2015 12:27:27 -0800 Subject: [PATCH 068/299] we can reate new user --- app/controllers/users_controller.rb | 6 +++--- app/views/products/edit.html.erb | 1 - app/views/users/_form.html.erb | 8 ++++++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 6775411803..7caf7525db 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -26,7 +26,7 @@ def edit def create @user = User.new(user_params) if @user.save - format.html { redirect_to @user, notice: 'User was successfully created.' } + redirect_to users_path else render "new" end @@ -35,7 +35,7 @@ def create def update respond_to do |format| if @user.update(user_params) - format.html { redirect_to @user, notice: 'User was successfully updated.' } + redirect_to users_path else render "edit" end @@ -57,6 +57,6 @@ def set_user def user_params - params.require(:user).permit(:username, :email, :password_digest, :name) + params.require(:user).permit(:username, :email, :password, :password_confirmation, :name) end end diff --git a/app/views/products/edit.html.erb b/app/views/products/edit.html.erb index 33805822e2..1cd7ea216f 100644 --- a/app/views/products/edit.html.erb +++ b/app/views/products/edit.html.erb @@ -3,6 +3,5 @@ <%= render 'form' %> - <%= link_to 'Show', user_product_path(@product.user, @product) %> | <%= link_to 'Back', user_products_path %> diff --git a/app/views/users/_form.html.erb b/app/views/users/_form.html.erb index 949f83d224..43be5ea943 100644 --- a/app/views/users/_form.html.erb +++ b/app/views/users/_form.html.erb @@ -20,8 +20,12 @@ <%= f.text_field :email %>
    - <%= f.label :password_digest %>
    - <%= f.text_field :password_digest %> + <%= f.label :password %>
    + <%= f.text_field :password %> +
    +
    + <%= f.label :password_confirmation %>
    + <%= f.text_field :password_confirmation %>
    <%= f.label :name %>
    From 3ff3de746257289f842e3d3ac65ddfad4479a52c Mon Sep 17 00:00:00 2001 From: Kelly Date: Thu, 10 Dec 2015 12:27:48 -0800 Subject: [PATCH 069/299] Fix path parameters --- app/controllers/products_controller.rb | 2 +- app/views/products/show.html.erb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index 7f24790b5d..2e88e5f4d6 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -16,7 +16,7 @@ def new end def edit - @user = User.find(params[:user_id]) + @user = @product.user end def create diff --git a/app/views/products/show.html.erb b/app/views/products/show.html.erb index de48df7327..9e2b3a1a5e 100644 --- a/app/views/products/show.html.erb +++ b/app/views/products/show.html.erb @@ -35,6 +35,6 @@ <%= @product.active %>

    -<%= link_to 'Edit', edit_user_product_path(@product.id, @product.user_id) %> | +<%= link_to 'Edit', edit_user_product_path(@product.user_id, @product.id) %> | <%= link_to 'Back', user_products_path(@product.user_id) %> -<%= link_to 'Reviews', user_product_reviews_path(@product.id, @product.user_id) %> +<%= link_to 'Reviews', user_product_reviews_path(@product.user_id, @product.id) %> From 84f0d010b209e40ef1565b635e45c34bda0d304c Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 10 Dec 2015 12:32:02 -0800 Subject: [PATCH 070/299] refactor homepage with BUG on products page --- app/views/shared/_display_products.html.erb | 37 +++++++++++++++++++ app/views/shared/_navbar.html.erb | 2 +- app/views/welcome/index.html.erb | 39 +-------------------- 3 files changed, 39 insertions(+), 39 deletions(-) create mode 100644 app/views/shared/_display_products.html.erb diff --git a/app/views/shared/_display_products.html.erb b/app/views/shared/_display_products.html.erb new file mode 100644 index 0000000000..0872be5bc6 --- /dev/null +++ b/app/views/shared/_display_products.html.erb @@ -0,0 +1,37 @@ +<% @products.to_ary.in_groups_of(4, false) do |group| %> +
    + <% group.each do |product| %> +
    +
    +
    + <%= image_tag product.photo_url, alt: "product photo" %> +
    +
    +
    <%= dollar_price(product.price) %>
    +
    <%= link_to product.name, user_product_path(product.user_id, product.id) %> +
    +

    + <% if !product.description.nil? %> + <%= product.description %> + <% else %> +
    + <% end %> +

    +

    <%= product.stock %> Available

    +
    +
    +

    <%= pluralize(product.reviews.count, "Review") %>

    +

    + + + + + +

    +
    + +
    +
    + <% end %> +
    +<% end %> diff --git a/app/views/shared/_navbar.html.erb b/app/views/shared/_navbar.html.erb index 4c6573a1e1..d8955843f5 100644 --- a/app/views/shared/_navbar.html.erb +++ b/app/views/shared/_navbar.html.erb @@ -18,7 +18,7 @@ diff --git a/app/views/welcome/index.html.erb b/app/views/welcome/index.html.erb index da1aebf980..66ba53f0a4 100644 --- a/app/views/welcome/index.html.erb +++ b/app/views/welcome/index.html.erb @@ -3,43 +3,6 @@

    Find the Best Products for Fun Water Times

    - <%= link_to "Browse All Products", products_path, class: "text-center" %>
    - <% @products.to_ary.in_groups_of(4, false) do |group| %> -
    - <% group.each do |product| %> -
    -
    -
    - <%= image_tag product.photo_url, alt: "product photo" %> -
    -
    -
    <%= dollar_price(product.price) %>
    -
    <%= link_to product.name, user_product_path(product.user_id, product.id) %> -
    -

    - <% if !product.description.nil? %> - <%= product.description %> - <% else %> -
    - <% end %> -

    -

    <%= product.stock %> Available

    -
    -
    -

    <%= pluralize(product.reviews.count, "Review") %>

    -

    - - - - - -

    -
    - -
    -
    - <% end %> -
    - <% end %> + <%= render 'shared/display_products' %>
    From b9483878edf1af548c78db94ab5ea62aef1cdf76 Mon Sep 17 00:00:00 2001 From: Kelly Date: Thu, 10 Dec 2015 12:35:06 -0800 Subject: [PATCH 071/299] Fix producs#update and reviews#update --- app/controllers/products_controller.rb | 8 ++++++-- app/controllers/reviews_controller.rb | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index 2e88e5f4d6..9990e26c4d 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -32,8 +32,12 @@ def create end def update - if @product.update(product_params) - format.html { redirect_to @product, notice: 'Product was successfully updated.' } + @product.update(product_params) + @user = @product.user + if @product.save + redirect_to user_products_path(@product.user) + else + render :edit end end diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb index 9e867f062a..ad0877caad 100644 --- a/app/controllers/reviews_controller.rb +++ b/app/controllers/reviews_controller.rb @@ -1,6 +1,6 @@ class ReviewsController < ApplicationController before_action :find_review, only: [:show, :edit, :update, :destroy] - before_action :find_product, only: [:new, :edit, :create] + before_action :find_product, only: [:new, :edit, :update, :create] def index @reviews = Review.all @@ -34,7 +34,11 @@ def create def update @review.update(review_params) - redirect_to user_product_reviews_path(@review.product.user, @review.product, @review) + if @review.save + redirect_to user_product_reviews_path(@review.product.user, @review.product, @review) + else + render :edit + end end From 5f80fa28324a4d4297c327659fc0f6f19e9c3914 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 10 Dec 2015 13:17:05 -0800 Subject: [PATCH 072/299] update navbar links --- app/views/shared/_navbar.html.erb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/views/shared/_navbar.html.erb b/app/views/shared/_navbar.html.erb index d8955843f5..b6b1977221 100644 --- a/app/views/shared/_navbar.html.erb +++ b/app/views/shared/_navbar.html.erb @@ -17,14 +17,14 @@ -
  • Register
  • -
  • Log In
  • -
  • Log Out
  • +
  • <%= link_to "Register", new_user_path %>
  • +
  • <%= link_to "Log In", login_path %>
  • +
  • <%= link_to "Log Out", logout_path %>
  • My Cart
From bcab2fadeb05ff2ea83865b4ca8923440bbf24b9 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 10 Dec 2015 13:32:59 -0800 Subject: [PATCH 073/299] style new user registration form --- app/views/users/_form.html.erb | 72 ++++++++++++++++++---------------- app/views/users/new.html.erb | 9 ++--- 2 files changed, 42 insertions(+), 39 deletions(-) diff --git a/app/views/users/_form.html.erb b/app/views/users/_form.html.erb index 43be5ea943..db025564ef 100644 --- a/app/views/users/_form.html.erb +++ b/app/views/users/_form.html.erb @@ -1,37 +1,41 @@ -<%= form_for(@user) do |f| %> - <% if @user.errors.any? %> -
-

<%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:

+
+
+ <%= form_for(@user, class: "form-group") do |f| %> + <% if @user.errors.any? %> +
+

<%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:

-
    - <% @user.errors.full_messages.each do |message| %> -
  • <%= message %>
  • +
      + <% @user.errors.full_messages.each do |message| %> +
    • <%= message %>
    • + <% end %> +
    +
<% end %> - -
- <% end %> - -
- <%= f.label :username %>
- <%= f.text_field :username %> -
-
- <%= f.label :email %>
- <%= f.text_field :email %> -
-
- <%= f.label :password %>
- <%= f.text_field :password %> -
-
- <%= f.label :password_confirmation %>
- <%= f.text_field :password_confirmation %> -
-
- <%= f.label :name %>
- <%= f.text_field :name %> -
-
- <%= f.submit %> +
+ <%= f.label :name %>
+ <%= f.text_field :name, class: 'form-control' %> +
+
+ <%= f.label :username %>
+ <%= f.text_field :username, class: 'form-control', :required => true %> +
+
+ <%= f.label :email %>
+ <%= f.email_field :email, class: 'form-control', :required => true %> +
+
+ <%= f.label :password %>
+ <%= f.password_field :password, class: 'form-control', :required => true %> +
+
+ <%= f.label :password_confirmation %>
+ <%= f.password_field :password_confirmation, class: 'form-control', :required => true %> +
+
+
+ <%= f.submit value: "Create My Account", class: "btn btn-primary" %> +
+ <% end %>
-<% end %> +
diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb index 4854d9e9e4..526469f064 100644 --- a/app/views/users/new.html.erb +++ b/app/views/users/new.html.erb @@ -1,5 +1,4 @@ -

New User

- -<%= render 'form' %> - -<%= link_to 'Back', users_path %> +
+

New User

+ <%= render 'form' %> +
From 342f55a4847cad6fb77c3db9cc069d01d4032d26 Mon Sep 17 00:00:00 2001 From: Tammy Date: Thu, 10 Dec 2015 13:34:23 -0800 Subject: [PATCH 074/299] you can create, edit and destroy a user --- app/controllers/users_controller.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 7caf7525db..1518e8b9c1 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -33,13 +33,12 @@ def create end def update - respond_to do |format| if @user.update(user_params) redirect_to users_path else render "edit" end - end + end def destroy From ff42a86b57d68351c2555e9c79d61a7928c715f3 Mon Sep 17 00:00:00 2001 From: Kelly Date: Thu, 10 Dec 2015 13:39:09 -0800 Subject: [PATCH 075/299] removed product#destroy --- app/controllers/products_controller.rb | 7 ------- config/routes.rb | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index 9990e26c4d..79cf597887 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -41,13 +41,6 @@ def update end end - def destroy - @product.destroy - respond_to do |format| - format.html { redirect_to user_products_path, notice: 'Product was successfully destroyed.' } - end - end - private def set_product diff --git a/config/routes.rb b/config/routes.rb index 8c8febb87b..ace19ab005 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -9,7 +9,7 @@ resources :orders do resources :order_items end - resources :products, except: :index do + resources :products, except: [:index, :destroy] do resources :reviews end end From 4663dee45e5f98e8bf0038fdfeacc24d4604337b Mon Sep 17 00:00:00 2001 From: Kelly Date: Thu, 10 Dec 2015 13:44:16 -0800 Subject: [PATCH 076/299] Add before_action to product controller --- app/controllers/products_controller.rb | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index 79cf597887..cc8294af55 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -1,5 +1,6 @@ class ProductsController < ApplicationController - before_action :set_product, only: [:show, :edit, :update, :destroy] + before_action :find_product, only: [:show, :edit, :update, :destroy] + before_action :find_user, only: [:new, :edit, :create, :update] def index @products = Product.all.paginate(page: params[:page], per_page: 12) @@ -12,15 +13,12 @@ def show def new @product = Product.new - @user = User.find(params[:user_id]) end def edit - @user = @product.user end def create - @user = User.find(params[:user_id]) @product = Product.create(product_params) do |p| p.user_id = @user.id end @@ -33,7 +31,6 @@ def create def update @product.update(product_params) - @user = @product.user if @product.save redirect_to user_products_path(@product.user) else @@ -43,10 +40,14 @@ def update private - def set_product + def find_product @product = Product.find(params[:id]) end + def find_user + @user = User.find(params[:user_id]) + end + def product_params params.require(:product).permit(:name, :price, :photo_url, :stock, :description, :active) end From edbeac6f3140716350ee5e632c2618ad360e1f8b Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 10 Dec 2015 13:52:48 -0800 Subject: [PATCH 077/299] add formatting to forms for reviews and users --- app/views/reviews/_form.html.erb | 23 +++++++++++------------ app/views/reviews/edit.html.erb | 13 +++++++------ app/views/reviews/new.html.erb | 11 ++++++----- app/views/users/_form.html.erb | 2 +- app/views/users/edit.html.erb | 12 ++++++------ app/views/users/new.html.erb | 2 +- 6 files changed, 32 insertions(+), 31 deletions(-) diff --git a/app/views/reviews/_form.html.erb b/app/views/reviews/_form.html.erb index 74aa43154e..88d2caf062 100644 --- a/app/views/reviews/_form.html.erb +++ b/app/views/reviews/_form.html.erb @@ -6,16 +6,15 @@ <% end %> -<%= form_for [@product.user, @product, @review] do |f| %> -
- <%= f.label :rating, "Rating (1-5)" %>
- <%= f.number_field :rating %> +
+
+ <%= form_for [@product.user, @product, @review], class: "form-group" do |f| %> + <%= f.label :rating, "Rating (1-5)" %>
+ <%= f.number_field :rating, class: 'form-control', :required => true%> + <%= f.label :description %>
+ <%= f.text_field :description, class: 'form-control' %> +
+ <%= f.submit value: "Save My Review", class: "btn btn-primary" %> + <% end %>
-
- <%= f.label :description %>
- <%= f.text_field :description %> -
-
- <%= f.submit %> -
-<% end %> +
diff --git a/app/views/reviews/edit.html.erb b/app/views/reviews/edit.html.erb index 6d89f204c5..af1b2054d7 100644 --- a/app/views/reviews/edit.html.erb +++ b/app/views/reviews/edit.html.erb @@ -1,6 +1,7 @@ -

Editing Review

- -<%= render 'form' %> - -<%= link_to 'Show', user_product_review_path(@product.user, @product, @review) %> | -<%= link_to 'Back', user_product_reviews_path(@product.user, @product) %> +
+

Edit Review

+ <%= render 'form' %> +
+ + <%= link_to 'Back to all Reviews', user_product_reviews_path(@product.user, @product), class: "btn btn-primary" %> +
diff --git a/app/views/reviews/new.html.erb b/app/views/reviews/new.html.erb index 5fb495a92f..ee9d89a708 100644 --- a/app/views/reviews/new.html.erb +++ b/app/views/reviews/new.html.erb @@ -1,5 +1,6 @@ -

New Review

- -<%= render 'form' %> - -<%= link_to 'Back', user_product_reviews_path(@product.user, @product) %> +
+

New Review

+ <%= render 'form' %> +
+ <%= link_to 'Back', user_product_reviews_path(@product.user, @product), class: "btn btn-primary" %> +
diff --git a/app/views/users/_form.html.erb b/app/views/users/_form.html.erb index db025564ef..3b81581576 100644 --- a/app/views/users/_form.html.erb +++ b/app/views/users/_form.html.erb @@ -34,7 +34,7 @@

- <%= f.submit value: "Create My Account", class: "btn btn-primary" %> + <%= f.submit value: "#{submit_text}", class: "btn btn-primary" %>
<% end %>
diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb index d87b2f57d8..d4a005c8ed 100644 --- a/app/views/users/edit.html.erb +++ b/app/views/users/edit.html.erb @@ -1,6 +1,6 @@ -

Editing User

- -<%= render 'form' %> - -<%= link_to 'Show', @user %> | -<%= link_to 'Back', users_path %> +
+

Update Your Profile

+ <%= render partial: 'form', locals: { submit_text: "Update My Profile" } %> +
+ <%= link_to 'Cancel', @user, class: "btn btn-primary" %> +
diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb index 526469f064..58ae321665 100644 --- a/app/views/users/new.html.erb +++ b/app/views/users/new.html.erb @@ -1,4 +1,4 @@

New User

- <%= render 'form' %> + <%= render partial: 'form', locals: {submit_text: "Create My Account"} %>
From 79c32344f7ee8cebc15a7080904cbefa562c6c90 Mon Sep 17 00:00:00 2001 From: Tammy Date: Thu, 10 Dec 2015 14:10:29 -0800 Subject: [PATCH 078/299] comment out all the rspecs --- .../controllers/categories_controller_spec.rb | 318 +++++++++--------- .../order_items_controller_spec.rb | 318 +++++++++--------- spec/controllers/orders_controller_spec.rb | 318 +++++++++--------- spec/controllers/products_controller_spec.rb | 318 +++++++++--------- spec/controllers/reviews_controller_spec.rb | 318 +++++++++--------- spec/controllers/users_controller_spec.rb | 291 ++++++++-------- spec/controllers/welcome_controller_spec.rb | 24 +- spec/helpers/categories_helper_spec.rb | 26 +- spec/helpers/order_items_helper_spec.rb | 26 +- spec/helpers/orders_helper_spec.rb | 26 +- spec/helpers/products_helper_spec.rb | 26 +- spec/helpers/reviews_helper_spec.rb | 26 +- spec/helpers/sessions_helper_spec.rb | 26 +- spec/helpers/users_helper_spec.rb | 26 +- spec/helpers/welcome_helper_spec.rb | 26 +- spec/models/category_spec.rb | 10 +- spec/models/order_item_spec.rb | 10 +- spec/models/order_spec.rb | 10 +- spec/models/product_spec.rb | 10 +- spec/models/review_spec.rb | 10 +- spec/models/user_spec.rb | 10 +- spec/rails_helper.rb | 110 +++--- spec/requests/categories_spec.rb | 20 +- spec/requests/order_items_spec.rb | 20 +- spec/requests/orders_spec.rb | 20 +- spec/requests/products_spec.rb | 20 +- spec/requests/reviews_spec.rb | 20 +- spec/requests/users_spec.rb | 20 +- spec/routing/categories_routing_spec.rb | 78 ++--- spec/routing/order_items_routing_spec.rb | 78 ++--- spec/routing/orders_routing_spec.rb | 78 ++--- spec/routing/products_routing_spec.rb | 78 ++--- spec/routing/reviews_routing_spec.rb | 78 ++--- spec/routing/users_routing_spec.rb | 78 ++--- spec/spec_helper.rb | 178 +++++----- 35 files changed, 1524 insertions(+), 1525 deletions(-) diff --git a/spec/controllers/categories_controller_spec.rb b/spec/controllers/categories_controller_spec.rb index e273ded83a..563674b47f 100644 --- a/spec/controllers/categories_controller_spec.rb +++ b/spec/controllers/categories_controller_spec.rb @@ -1,159 +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) { - skip("Add a hash of attributes valid for your model") - } - - let(:invalid_attributes) { - skip("Add a hash of attributes invalid for your model") - } - - # 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, {}, 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, {:id => category.to_param}, valid_session - expect(assigns(:category)).to eq(category) - end - end - - describe "GET #new" do - it "assigns a new category as @category" do - get :new, {}, 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, {:id => category.to_param}, 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, {:category => valid_attributes}, valid_session - }.to change(Category, :count).by(1) - end - - it "assigns a newly created category as @category" do - post :create, {:category => valid_attributes}, 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, {:category => valid_attributes}, 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, {:category => invalid_attributes}, valid_session - expect(assigns(:category)).to be_a_new(Category) - end - - it "re-renders the 'new' template" do - post :create, {:category => invalid_attributes}, valid_session - expect(response).to render_template("new") - end - end - end - - describe "PUT #update" do - context "with valid params" do - let(:new_attributes) { - skip("Add a hash of attributes valid for your model") - } - - it "updates the requested category" do - category = Category.create! valid_attributes - put :update, {:id => category.to_param, :category => new_attributes}, valid_session - category.reload - skip("Add assertions for updated state") - end - - it "assigns the requested category as @category" do - category = Category.create! valid_attributes - put :update, {:id => category.to_param, :category => valid_attributes}, valid_session - expect(assigns(:category)).to eq(category) - end - - it "redirects to the category" do - category = Category.create! valid_attributes - put :update, {:id => category.to_param, :category => valid_attributes}, 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, {:id => category.to_param, :category => invalid_attributes}, valid_session - expect(assigns(:category)).to eq(category) - end - - it "re-renders the 'edit' template" do - category = Category.create! valid_attributes - put :update, {:id => category.to_param, :category => invalid_attributes}, 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, {:id => category.to_param}, valid_session - }.to change(Category, :count).by(-1) - end - - it "redirects to the categories list" do - category = Category.create! valid_attributes - delete :destroy, {:id => category.to_param}, valid_session - expect(response).to redirect_to(categories_url) - end - end - -end +# 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) { +# skip("Add a hash of attributes valid for your model") +# } +# +# let(:invalid_attributes) { +# skip("Add a hash of attributes invalid for your model") +# } +# +# # 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, {}, 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, {:id => category.to_param}, valid_session +# expect(assigns(:category)).to eq(category) +# end +# end +# +# describe "GET #new" do +# it "assigns a new category as @category" do +# get :new, {}, 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, {:id => category.to_param}, 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, {:category => valid_attributes}, valid_session +# }.to change(Category, :count).by(1) +# end +# +# it "assigns a newly created category as @category" do +# post :create, {:category => valid_attributes}, 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, {:category => valid_attributes}, 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, {:category => invalid_attributes}, valid_session +# expect(assigns(:category)).to be_a_new(Category) +# end +# +# it "re-renders the 'new' template" do +# post :create, {:category => invalid_attributes}, valid_session +# expect(response).to render_template("new") +# end +# end +# end +# +# describe "PUT #update" do +# context "with valid params" do +# let(:new_attributes) { +# skip("Add a hash of attributes valid for your model") +# } +# +# it "updates the requested category" do +# category = Category.create! valid_attributes +# put :update, {:id => category.to_param, :category => new_attributes}, valid_session +# category.reload +# skip("Add assertions for updated state") +# end +# +# it "assigns the requested category as @category" do +# category = Category.create! valid_attributes +# put :update, {:id => category.to_param, :category => valid_attributes}, valid_session +# expect(assigns(:category)).to eq(category) +# end +# +# it "redirects to the category" do +# category = Category.create! valid_attributes +# put :update, {:id => category.to_param, :category => valid_attributes}, 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, {:id => category.to_param, :category => invalid_attributes}, valid_session +# expect(assigns(:category)).to eq(category) +# end +# +# it "re-renders the 'edit' template" do +# category = Category.create! valid_attributes +# put :update, {:id => category.to_param, :category => invalid_attributes}, 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, {:id => category.to_param}, valid_session +# }.to change(Category, :count).by(-1) +# end +# +# it "redirects to the categories list" do +# category = Category.create! valid_attributes +# delete :destroy, {:id => category.to_param}, valid_session +# expect(response).to redirect_to(categories_url) +# end +# end +# +# end diff --git a/spec/controllers/order_items_controller_spec.rb b/spec/controllers/order_items_controller_spec.rb index e931a11594..88c72283d3 100644 --- a/spec/controllers/order_items_controller_spec.rb +++ b/spec/controllers/order_items_controller_spec.rb @@ -1,159 +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 OrderItemsController, type: :controller do - - # This should return the minimal set of attributes required to create a valid - # OrderItem. As you add validations to OrderItem, be sure to - # adjust the attributes here as well. - let(:valid_attributes) { - skip("Add a hash of attributes valid for your model") - } - - let(:invalid_attributes) { - skip("Add a hash of attributes invalid for your model") - } - - # 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 - # OrderItemsController. Be sure to keep this updated too. - let(:valid_session) { {} } - - describe "GET #index" do - it "assigns all order_items as @order_items" do - order_item = OrderItem.create! valid_attributes - get :index, {}, valid_session - expect(assigns(:order_items)).to eq([order_item]) - end - end - - describe "GET #show" do - it "assigns the requested order_item as @order_item" do - order_item = OrderItem.create! valid_attributes - get :show, {:id => order_item.to_param}, valid_session - expect(assigns(:order_item)).to eq(order_item) - end - end - - describe "GET #new" do - it "assigns a new order_item as @order_item" do - get :new, {}, valid_session - expect(assigns(:order_item)).to be_a_new(OrderItem) - end - end - - describe "GET #edit" do - it "assigns the requested order_item as @order_item" do - order_item = OrderItem.create! valid_attributes - get :edit, {:id => order_item.to_param}, valid_session - expect(assigns(:order_item)).to eq(order_item) - end - end - - describe "POST #create" do - context "with valid params" do - it "creates a new OrderItem" do - expect { - post :create, {:order_item => valid_attributes}, valid_session - }.to change(OrderItem, :count).by(1) - end - - it "assigns a newly created order_item as @order_item" do - post :create, {:order_item => valid_attributes}, valid_session - expect(assigns(:order_item)).to be_a(OrderItem) - expect(assigns(:order_item)).to be_persisted - end - - it "redirects to the created order_item" do - post :create, {:order_item => valid_attributes}, valid_session - expect(response).to redirect_to(OrderItem.last) - end - end - - context "with invalid params" do - it "assigns a newly created but unsaved order_item as @order_item" do - post :create, {:order_item => invalid_attributes}, valid_session - expect(assigns(:order_item)).to be_a_new(OrderItem) - end - - it "re-renders the 'new' template" do - post :create, {:order_item => invalid_attributes}, valid_session - expect(response).to render_template("new") - end - end - end - - describe "PUT #update" do - context "with valid params" do - let(:new_attributes) { - skip("Add a hash of attributes valid for your model") - } - - it "updates the requested order_item" do - order_item = OrderItem.create! valid_attributes - put :update, {:id => order_item.to_param, :order_item => new_attributes}, valid_session - order_item.reload - skip("Add assertions for updated state") - end - - it "assigns the requested order_item as @order_item" do - order_item = OrderItem.create! valid_attributes - put :update, {:id => order_item.to_param, :order_item => valid_attributes}, valid_session - expect(assigns(:order_item)).to eq(order_item) - end - - it "redirects to the order_item" do - order_item = OrderItem.create! valid_attributes - put :update, {:id => order_item.to_param, :order_item => valid_attributes}, valid_session - expect(response).to redirect_to(order_item) - end - end - - context "with invalid params" do - it "assigns the order_item as @order_item" do - order_item = OrderItem.create! valid_attributes - put :update, {:id => order_item.to_param, :order_item => invalid_attributes}, valid_session - expect(assigns(:order_item)).to eq(order_item) - end - - it "re-renders the 'edit' template" do - order_item = OrderItem.create! valid_attributes - put :update, {:id => order_item.to_param, :order_item => invalid_attributes}, valid_session - expect(response).to render_template("edit") - end - end - end - - describe "DELETE #destroy" do - it "destroys the requested order_item" do - order_item = OrderItem.create! valid_attributes - expect { - delete :destroy, {:id => order_item.to_param}, valid_session - }.to change(OrderItem, :count).by(-1) - end - - it "redirects to the order_items list" do - order_item = OrderItem.create! valid_attributes - delete :destroy, {:id => order_item.to_param}, valid_session - expect(response).to redirect_to(order_items_url) - end - end - -end +# 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 OrderItemsController, type: :controller do +# +# # This should return the minimal set of attributes required to create a valid +# # OrderItem. As you add validations to OrderItem, be sure to +# # adjust the attributes here as well. +# let(:valid_attributes) { +# skip("Add a hash of attributes valid for your model") +# } +# +# let(:invalid_attributes) { +# skip("Add a hash of attributes invalid for your model") +# } +# +# # 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 +# # OrderItemsController. Be sure to keep this updated too. +# let(:valid_session) { {} } +# +# describe "GET #index" do +# it "assigns all order_items as @order_items" do +# order_item = OrderItem.create! valid_attributes +# get :index, {}, valid_session +# expect(assigns(:order_items)).to eq([order_item]) +# end +# end +# +# describe "GET #show" do +# it "assigns the requested order_item as @order_item" do +# order_item = OrderItem.create! valid_attributes +# get :show, {:id => order_item.to_param}, valid_session +# expect(assigns(:order_item)).to eq(order_item) +# end +# end +# +# describe "GET #new" do +# it "assigns a new order_item as @order_item" do +# get :new, {}, valid_session +# expect(assigns(:order_item)).to be_a_new(OrderItem) +# end +# end +# +# describe "GET #edit" do +# it "assigns the requested order_item as @order_item" do +# order_item = OrderItem.create! valid_attributes +# get :edit, {:id => order_item.to_param}, valid_session +# expect(assigns(:order_item)).to eq(order_item) +# end +# end +# +# describe "POST #create" do +# context "with valid params" do +# it "creates a new OrderItem" do +# expect { +# post :create, {:order_item => valid_attributes}, valid_session +# }.to change(OrderItem, :count).by(1) +# end +# +# it "assigns a newly created order_item as @order_item" do +# post :create, {:order_item => valid_attributes}, valid_session +# expect(assigns(:order_item)).to be_a(OrderItem) +# expect(assigns(:order_item)).to be_persisted +# end +# +# it "redirects to the created order_item" do +# post :create, {:order_item => valid_attributes}, valid_session +# expect(response).to redirect_to(OrderItem.last) +# end +# end +# +# context "with invalid params" do +# it "assigns a newly created but unsaved order_item as @order_item" do +# post :create, {:order_item => invalid_attributes}, valid_session +# expect(assigns(:order_item)).to be_a_new(OrderItem) +# end +# +# it "re-renders the 'new' template" do +# post :create, {:order_item => invalid_attributes}, valid_session +# expect(response).to render_template("new") +# end +# end +# end +# +# describe "PUT #update" do +# context "with valid params" do +# let(:new_attributes) { +# skip("Add a hash of attributes valid for your model") +# } +# +# it "updates the requested order_item" do +# order_item = OrderItem.create! valid_attributes +# put :update, {:id => order_item.to_param, :order_item => new_attributes}, valid_session +# order_item.reload +# skip("Add assertions for updated state") +# end +# +# it "assigns the requested order_item as @order_item" do +# order_item = OrderItem.create! valid_attributes +# put :update, {:id => order_item.to_param, :order_item => valid_attributes}, valid_session +# expect(assigns(:order_item)).to eq(order_item) +# end +# +# it "redirects to the order_item" do +# order_item = OrderItem.create! valid_attributes +# put :update, {:id => order_item.to_param, :order_item => valid_attributes}, valid_session +# expect(response).to redirect_to(order_item) +# end +# end +# +# context "with invalid params" do +# it "assigns the order_item as @order_item" do +# order_item = OrderItem.create! valid_attributes +# put :update, {:id => order_item.to_param, :order_item => invalid_attributes}, valid_session +# expect(assigns(:order_item)).to eq(order_item) +# end +# +# it "re-renders the 'edit' template" do +# order_item = OrderItem.create! valid_attributes +# put :update, {:id => order_item.to_param, :order_item => invalid_attributes}, valid_session +# expect(response).to render_template("edit") +# end +# end +# end +# +# describe "DELETE #destroy" do +# it "destroys the requested order_item" do +# order_item = OrderItem.create! valid_attributes +# expect { +# delete :destroy, {:id => order_item.to_param}, valid_session +# }.to change(OrderItem, :count).by(-1) +# end +# +# it "redirects to the order_items list" do +# order_item = OrderItem.create! valid_attributes +# delete :destroy, {:id => order_item.to_param}, valid_session +# expect(response).to redirect_to(order_items_url) +# end +# end +# +# end diff --git a/spec/controllers/orders_controller_spec.rb b/spec/controllers/orders_controller_spec.rb index 0c9b109e05..6e3907463e 100644 --- a/spec/controllers/orders_controller_spec.rb +++ b/spec/controllers/orders_controller_spec.rb @@ -1,159 +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 OrdersController, type: :controller do - - # This should return the minimal set of attributes required to create a valid - # Order. As you add validations to Order, be sure to - # adjust the attributes here as well. - let(:valid_attributes) { - skip("Add a hash of attributes valid for your model") - } - - let(:invalid_attributes) { - skip("Add a hash of attributes invalid for your model") - } - - # 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 - # OrdersController. Be sure to keep this updated too. - let(:valid_session) { {} } - - describe "GET #index" do - it "assigns all orders as @orders" do - order = Order.create! valid_attributes - get :index, {}, valid_session - expect(assigns(:orders)).to eq([order]) - end - end - - describe "GET #show" do - it "assigns the requested order as @order" do - order = Order.create! valid_attributes - get :show, {:id => order.to_param}, valid_session - expect(assigns(:order)).to eq(order) - end - end - - describe "GET #new" do - it "assigns a new order as @order" do - get :new, {}, valid_session - expect(assigns(:order)).to be_a_new(Order) - end - end - - describe "GET #edit" do - it "assigns the requested order as @order" do - order = Order.create! valid_attributes - get :edit, {:id => order.to_param}, valid_session - expect(assigns(:order)).to eq(order) - end - end - - describe "POST #create" do - context "with valid params" do - it "creates a new Order" do - expect { - post :create, {:order => valid_attributes}, valid_session - }.to change(Order, :count).by(1) - end - - it "assigns a newly created order as @order" do - post :create, {:order => valid_attributes}, valid_session - expect(assigns(:order)).to be_a(Order) - expect(assigns(:order)).to be_persisted - end - - it "redirects to the created order" do - post :create, {:order => valid_attributes}, valid_session - expect(response).to redirect_to(Order.last) - end - end - - context "with invalid params" do - it "assigns a newly created but unsaved order as @order" do - post :create, {:order => invalid_attributes}, valid_session - expect(assigns(:order)).to be_a_new(Order) - end - - it "re-renders the 'new' template" do - post :create, {:order => invalid_attributes}, valid_session - expect(response).to render_template("new") - end - end - end - - describe "PUT #update" do - context "with valid params" do - let(:new_attributes) { - skip("Add a hash of attributes valid for your model") - } - - it "updates the requested order" do - order = Order.create! valid_attributes - put :update, {:id => order.to_param, :order => new_attributes}, valid_session - order.reload - skip("Add assertions for updated state") - end - - it "assigns the requested order as @order" do - order = Order.create! valid_attributes - put :update, {:id => order.to_param, :order => valid_attributes}, valid_session - expect(assigns(:order)).to eq(order) - end - - it "redirects to the order" do - order = Order.create! valid_attributes - put :update, {:id => order.to_param, :order => valid_attributes}, valid_session - expect(response).to redirect_to(order) - end - end - - context "with invalid params" do - it "assigns the order as @order" do - order = Order.create! valid_attributes - put :update, {:id => order.to_param, :order => invalid_attributes}, valid_session - expect(assigns(:order)).to eq(order) - end - - it "re-renders the 'edit' template" do - order = Order.create! valid_attributes - put :update, {:id => order.to_param, :order => invalid_attributes}, valid_session - expect(response).to render_template("edit") - end - end - end - - describe "DELETE #destroy" do - it "destroys the requested order" do - order = Order.create! valid_attributes - expect { - delete :destroy, {:id => order.to_param}, valid_session - }.to change(Order, :count).by(-1) - end - - it "redirects to the orders list" do - order = Order.create! valid_attributes - delete :destroy, {:id => order.to_param}, valid_session - expect(response).to redirect_to(orders_url) - end - end - -end +# 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 OrdersController, type: :controller do +# +# # This should return the minimal set of attributes required to create a valid +# # Order. As you add validations to Order, be sure to +# # adjust the attributes here as well. +# let(:valid_attributes) { +# skip("Add a hash of attributes valid for your model") +# } +# +# let(:invalid_attributes) { +# skip("Add a hash of attributes invalid for your model") +# } +# +# # 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 +# # OrdersController. Be sure to keep this updated too. +# let(:valid_session) { {} } +# +# describe "GET #index" do +# it "assigns all orders as @orders" do +# order = Order.create! valid_attributes +# get :index, {}, valid_session +# expect(assigns(:orders)).to eq([order]) +# end +# end +# +# describe "GET #show" do +# it "assigns the requested order as @order" do +# order = Order.create! valid_attributes +# get :show, {:id => order.to_param}, valid_session +# expect(assigns(:order)).to eq(order) +# end +# end +# +# describe "GET #new" do +# it "assigns a new order as @order" do +# get :new, {}, valid_session +# expect(assigns(:order)).to be_a_new(Order) +# end +# end +# +# describe "GET #edit" do +# it "assigns the requested order as @order" do +# order = Order.create! valid_attributes +# get :edit, {:id => order.to_param}, valid_session +# expect(assigns(:order)).to eq(order) +# end +# end +# +# describe "POST #create" do +# context "with valid params" do +# it "creates a new Order" do +# expect { +# post :create, {:order => valid_attributes}, valid_session +# }.to change(Order, :count).by(1) +# end +# +# it "assigns a newly created order as @order" do +# post :create, {:order => valid_attributes}, valid_session +# expect(assigns(:order)).to be_a(Order) +# expect(assigns(:order)).to be_persisted +# end +# +# it "redirects to the created order" do +# post :create, {:order => valid_attributes}, valid_session +# expect(response).to redirect_to(Order.last) +# end +# end +# +# context "with invalid params" do +# it "assigns a newly created but unsaved order as @order" do +# post :create, {:order => invalid_attributes}, valid_session +# expect(assigns(:order)).to be_a_new(Order) +# end +# +# it "re-renders the 'new' template" do +# post :create, {:order => invalid_attributes}, valid_session +# expect(response).to render_template("new") +# end +# end +# end +# +# describe "PUT #update" do +# context "with valid params" do +# let(:new_attributes) { +# skip("Add a hash of attributes valid for your model") +# } +# +# it "updates the requested order" do +# order = Order.create! valid_attributes +# put :update, {:id => order.to_param, :order => new_attributes}, valid_session +# order.reload +# skip("Add assertions for updated state") +# end +# +# it "assigns the requested order as @order" do +# order = Order.create! valid_attributes +# put :update, {:id => order.to_param, :order => valid_attributes}, valid_session +# expect(assigns(:order)).to eq(order) +# end +# +# it "redirects to the order" do +# order = Order.create! valid_attributes +# put :update, {:id => order.to_param, :order => valid_attributes}, valid_session +# expect(response).to redirect_to(order) +# end +# end +# +# context "with invalid params" do +# it "assigns the order as @order" do +# order = Order.create! valid_attributes +# put :update, {:id => order.to_param, :order => invalid_attributes}, valid_session +# expect(assigns(:order)).to eq(order) +# end +# +# it "re-renders the 'edit' template" do +# order = Order.create! valid_attributes +# put :update, {:id => order.to_param, :order => invalid_attributes}, valid_session +# expect(response).to render_template("edit") +# end +# end +# end +# +# describe "DELETE #destroy" do +# it "destroys the requested order" do +# order = Order.create! valid_attributes +# expect { +# delete :destroy, {:id => order.to_param}, valid_session +# }.to change(Order, :count).by(-1) +# end +# +# it "redirects to the orders list" do +# order = Order.create! valid_attributes +# delete :destroy, {:id => order.to_param}, valid_session +# expect(response).to redirect_to(orders_url) +# end +# end +# +# end diff --git a/spec/controllers/products_controller_spec.rb b/spec/controllers/products_controller_spec.rb index 21530babc7..0ce390873b 100644 --- a/spec/controllers/products_controller_spec.rb +++ b/spec/controllers/products_controller_spec.rb @@ -1,159 +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 ProductsController, type: :controller do - - # This should return the minimal set of attributes required to create a valid - # Product. As you add validations to Product, be sure to - # adjust the attributes here as well. - let(:valid_attributes) { - skip("Add a hash of attributes valid for your model") - } - - let(:invalid_attributes) { - skip("Add a hash of attributes invalid for your model") - } - - # 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 - # ProductsController. Be sure to keep this updated too. - let(:valid_session) { {} } - - describe "GET #index" do - it "assigns all products as @products" do - product = Product.create! valid_attributes - get :index, {}, valid_session - expect(assigns(:products)).to 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 - expect(assigns(:product)).to eq(product) - end - end - - describe "GET #new" do - it "assigns a new product as @product" do - get :new, {}, valid_session - expect(assigns(:product)).to 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 - expect(assigns(:product)).to eq(product) - end - end - - describe "POST #create" do - context "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 - expect(assigns(:product)).to be_a(Product) - expect(assigns(:product)).to be_persisted - end - - it "redirects to the created product" do - post :create, {:product => valid_attributes}, valid_session - expect(response).to redirect_to(Product.last) - end - end - - context "with invalid params" do - it "assigns a newly created but unsaved product as @product" do - post :create, {:product => invalid_attributes}, valid_session - expect(assigns(:product)).to be_a_new(Product) - end - - it "re-renders the 'new' template" do - post :create, {:product => invalid_attributes}, valid_session - expect(response).to render_template("new") - end - end - end - - describe "PUT #update" do - context "with valid params" do - let(:new_attributes) { - skip("Add a hash of attributes valid for your model") - } - - it "updates the requested product" do - product = Product.create! valid_attributes - put :update, {:id => product.to_param, :product => new_attributes}, valid_session - product.reload - skip("Add assertions for updated state") - 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 - expect(assigns(:product)).to 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 - expect(response).to redirect_to(product) - end - end - - context "with invalid params" do - it "assigns the product as @product" do - product = Product.create! valid_attributes - put :update, {:id => product.to_param, :product => invalid_attributes}, valid_session - expect(assigns(:product)).to eq(product) - end - - it "re-renders the 'edit' template" do - product = Product.create! valid_attributes - put :update, {:id => product.to_param, :product => invalid_attributes}, valid_session - expect(response).to 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 - expect(response).to redirect_to(products_url) - end - end - -end +# 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 ProductsController, type: :controller do +# +# # This should return the minimal set of attributes required to create a valid +# # Product. As you add validations to Product, be sure to +# # adjust the attributes here as well. +# let(:valid_attributes) { +# skip("Add a hash of attributes valid for your model") +# } +# +# let(:invalid_attributes) { +# skip("Add a hash of attributes invalid for your model") +# } +# +# # 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 +# # ProductsController. Be sure to keep this updated too. +# let(:valid_session) { {} } +# +# describe "GET #index" do +# it "assigns all products as @products" do +# product = Product.create! valid_attributes +# get :index, {}, valid_session +# expect(assigns(:products)).to 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 +# expect(assigns(:product)).to eq(product) +# end +# end +# +# describe "GET #new" do +# it "assigns a new product as @product" do +# get :new, {}, valid_session +# expect(assigns(:product)).to 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 +# expect(assigns(:product)).to eq(product) +# end +# end +# +# describe "POST #create" do +# context "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 +# expect(assigns(:product)).to be_a(Product) +# expect(assigns(:product)).to be_persisted +# end +# +# it "redirects to the created product" do +# post :create, {:product => valid_attributes}, valid_session +# expect(response).to redirect_to(Product.last) +# end +# end +# +# context "with invalid params" do +# it "assigns a newly created but unsaved product as @product" do +# post :create, {:product => invalid_attributes}, valid_session +# expect(assigns(:product)).to be_a_new(Product) +# end +# +# it "re-renders the 'new' template" do +# post :create, {:product => invalid_attributes}, valid_session +# expect(response).to render_template("new") +# end +# end +# end +# +# describe "PUT #update" do +# context "with valid params" do +# let(:new_attributes) { +# skip("Add a hash of attributes valid for your model") +# } +# +# it "updates the requested product" do +# product = Product.create! valid_attributes +# put :update, {:id => product.to_param, :product => new_attributes}, valid_session +# product.reload +# skip("Add assertions for updated state") +# 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 +# expect(assigns(:product)).to 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 +# expect(response).to redirect_to(product) +# end +# end +# +# context "with invalid params" do +# it "assigns the product as @product" do +# product = Product.create! valid_attributes +# put :update, {:id => product.to_param, :product => invalid_attributes}, valid_session +# expect(assigns(:product)).to eq(product) +# end +# +# it "re-renders the 'edit' template" do +# product = Product.create! valid_attributes +# put :update, {:id => product.to_param, :product => invalid_attributes}, valid_session +# expect(response).to 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 +# expect(response).to redirect_to(products_url) +# end +# end +# +# end diff --git a/spec/controllers/reviews_controller_spec.rb b/spec/controllers/reviews_controller_spec.rb index 2be4c113c4..b6a992e02a 100644 --- a/spec/controllers/reviews_controller_spec.rb +++ b/spec/controllers/reviews_controller_spec.rb @@ -1,159 +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 ReviewsController, type: :controller do - - # This should return the minimal set of attributes required to create a valid - # Review. As you add validations to Review, be sure to - # adjust the attributes here as well. - let(:valid_attributes) { - skip("Add a hash of attributes valid for your model") - } - - let(:invalid_attributes) { - skip("Add a hash of attributes invalid for your model") - } - - # 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 - # ReviewsController. Be sure to keep this updated too. - let(:valid_session) { {} } - - describe "GET #index" do - it "assigns all reviews as @reviews" do - review = Review.create! valid_attributes - get :index, {}, valid_session - expect(assigns(:reviews)).to eq([review]) - end - end - - describe "GET #show" do - it "assigns the requested review as @review" do - review = Review.create! valid_attributes - get :show, {:id => review.to_param}, valid_session - expect(assigns(:review)).to eq(review) - end - end - - describe "GET #new" do - it "assigns a new review as @review" do - get :new, {}, valid_session - expect(assigns(:review)).to be_a_new(Review) - end - end - - describe "GET #edit" do - it "assigns the requested review as @review" do - review = Review.create! valid_attributes - get :edit, {:id => review.to_param}, valid_session - expect(assigns(:review)).to eq(review) - end - end - - describe "POST #create" do - context "with valid params" do - it "creates a new Review" do - expect { - post :create, {:review => valid_attributes}, valid_session - }.to change(Review, :count).by(1) - end - - it "assigns a newly created review as @review" do - post :create, {:review => valid_attributes}, valid_session - expect(assigns(:review)).to be_a(Review) - expect(assigns(:review)).to be_persisted - end - - it "redirects to the created review" do - post :create, {:review => valid_attributes}, valid_session - expect(response).to redirect_to(Review.last) - end - end - - context "with invalid params" do - it "assigns a newly created but unsaved review as @review" do - post :create, {:review => invalid_attributes}, valid_session - expect(assigns(:review)).to be_a_new(Review) - end - - it "re-renders the 'new' template" do - post :create, {:review => invalid_attributes}, valid_session - expect(response).to render_template("new") - end - end - end - - describe "PUT #update" do - context "with valid params" do - let(:new_attributes) { - skip("Add a hash of attributes valid for your model") - } - - it "updates the requested review" do - review = Review.create! valid_attributes - put :update, {:id => review.to_param, :review => new_attributes}, valid_session - review.reload - skip("Add assertions for updated state") - end - - it "assigns the requested review as @review" do - review = Review.create! valid_attributes - put :update, {:id => review.to_param, :review => valid_attributes}, valid_session - expect(assigns(:review)).to eq(review) - end - - it "redirects to the review" do - review = Review.create! valid_attributes - put :update, {:id => review.to_param, :review => valid_attributes}, valid_session - expect(response).to redirect_to(review) - end - end - - context "with invalid params" do - it "assigns the review as @review" do - review = Review.create! valid_attributes - put :update, {:id => review.to_param, :review => invalid_attributes}, valid_session - expect(assigns(:review)).to eq(review) - end - - it "re-renders the 'edit' template" do - review = Review.create! valid_attributes - put :update, {:id => review.to_param, :review => invalid_attributes}, valid_session - expect(response).to render_template("edit") - end - end - end - - describe "DELETE #destroy" do - it "destroys the requested review" do - review = Review.create! valid_attributes - expect { - delete :destroy, {:id => review.to_param}, valid_session - }.to change(Review, :count).by(-1) - end - - it "redirects to the reviews list" do - review = Review.create! valid_attributes - delete :destroy, {:id => review.to_param}, valid_session - expect(response).to redirect_to(reviews_url) - end - end - -end +# 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 ReviewsController, type: :controller do +# +# # This should return the minimal set of attributes required to create a valid +# # Review. As you add validations to Review, be sure to +# # adjust the attributes here as well. +# let(:valid_attributes) { +# skip("Add a hash of attributes valid for your model") +# } +# +# let(:invalid_attributes) { +# skip("Add a hash of attributes invalid for your model") +# } +# +# # 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 +# # ReviewsController. Be sure to keep this updated too. +# let(:valid_session) { {} } +# +# describe "GET #index" do +# it "assigns all reviews as @reviews" do +# review = Review.create! valid_attributes +# get :index, {}, valid_session +# expect(assigns(:reviews)).to eq([review]) +# end +# end +# +# describe "GET #show" do +# it "assigns the requested review as @review" do +# review = Review.create! valid_attributes +# get :show, {:id => review.to_param}, valid_session +# expect(assigns(:review)).to eq(review) +# end +# end +# +# describe "GET #new" do +# it "assigns a new review as @review" do +# get :new, {}, valid_session +# expect(assigns(:review)).to be_a_new(Review) +# end +# end +# +# describe "GET #edit" do +# it "assigns the requested review as @review" do +# review = Review.create! valid_attributes +# get :edit, {:id => review.to_param}, valid_session +# expect(assigns(:review)).to eq(review) +# end +# end +# +# describe "POST #create" do +# context "with valid params" do +# it "creates a new Review" do +# expect { +# post :create, {:review => valid_attributes}, valid_session +# }.to change(Review, :count).by(1) +# end +# +# it "assigns a newly created review as @review" do +# post :create, {:review => valid_attributes}, valid_session +# expect(assigns(:review)).to be_a(Review) +# expect(assigns(:review)).to be_persisted +# end +# +# it "redirects to the created review" do +# post :create, {:review => valid_attributes}, valid_session +# expect(response).to redirect_to(Review.last) +# end +# end +# +# context "with invalid params" do +# it "assigns a newly created but unsaved review as @review" do +# post :create, {:review => invalid_attributes}, valid_session +# expect(assigns(:review)).to be_a_new(Review) +# end +# +# it "re-renders the 'new' template" do +# post :create, {:review => invalid_attributes}, valid_session +# expect(response).to render_template("new") +# end +# end +# end +# +# describe "PUT #update" do +# context "with valid params" do +# let(:new_attributes) { +# skip("Add a hash of attributes valid for your model") +# } +# +# it "updates the requested review" do +# review = Review.create! valid_attributes +# put :update, {:id => review.to_param, :review => new_attributes}, valid_session +# review.reload +# skip("Add assertions for updated state") +# end +# +# it "assigns the requested review as @review" do +# review = Review.create! valid_attributes +# put :update, {:id => review.to_param, :review => valid_attributes}, valid_session +# expect(assigns(:review)).to eq(review) +# end +# +# it "redirects to the review" do +# review = Review.create! valid_attributes +# put :update, {:id => review.to_param, :review => valid_attributes}, valid_session +# expect(response).to redirect_to(review) +# end +# end +# +# context "with invalid params" do +# it "assigns the review as @review" do +# review = Review.create! valid_attributes +# put :update, {:id => review.to_param, :review => invalid_attributes}, valid_session +# expect(assigns(:review)).to eq(review) +# end +# +# it "re-renders the 'edit' template" do +# review = Review.create! valid_attributes +# put :update, {:id => review.to_param, :review => invalid_attributes}, valid_session +# expect(response).to render_template("edit") +# end +# end +# end +# +# describe "DELETE #destroy" do +# it "destroys the requested review" do +# review = Review.create! valid_attributes +# expect { +# delete :destroy, {:id => review.to_param}, valid_session +# }.to change(Review, :count).by(-1) +# end +# +# it "redirects to the reviews list" do +# review = Review.create! valid_attributes +# delete :destroy, {:id => review.to_param}, valid_session +# expect(response).to redirect_to(reviews_url) +# end +# end +# +# end diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index ecb1a8143d..b9b2373ea1 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -1,159 +1,158 @@ 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 UsersController, type: :controller do # This should return the minimal set of attributes required to create a valid # User. As you add validations to User, be sure to # adjust the attributes here as well. - let(:valid_attributes) { - skip("Add a hash of attributes valid for your model") - } - - let(:invalid_attributes) { - skip("Add a hash of attributes invalid for your model") - } - - # 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 - # UsersController. Be sure to keep this updated too. - let(:valid_session) { {} } - - describe "GET #index" do - it "assigns all users as @users" do - user = User.create! valid_attributes - get :index, {}, valid_session - expect(assigns(:users)).to eq([user]) - end - end - - describe "GET #show" do - it "assigns the requested user as @user" do - user = User.create! valid_attributes - get :show, {:id => user.to_param}, valid_session - expect(assigns(:user)).to eq(user) - end - end - - describe "GET #new" do - it "assigns a new user as @user" do - get :new, {}, valid_session - expect(assigns(:user)).to be_a_new(User) - end - end - - describe "GET #edit" do - it "assigns the requested user as @user" do - user = User.create! valid_attributes - get :edit, {:id => user.to_param}, valid_session - expect(assigns(:user)).to eq(user) - end - end - - describe "POST #create" do - context "with valid params" do - it "creates a new User" do - expect { - post :create, {:user => valid_attributes}, valid_session - }.to change(User, :count).by(1) - end - - it "assigns a newly created user as @user" do - post :create, {:user => valid_attributes}, valid_session - expect(assigns(:user)).to be_a(User) - expect(assigns(:user)).to be_persisted - end - - it "redirects to the created user" do - post :create, {:user => valid_attributes}, valid_session - expect(response).to redirect_to(User.last) - end - end - - context "with invalid params" do - it "assigns a newly created but unsaved user as @user" do - post :create, {:user => invalid_attributes}, valid_session - expect(assigns(:user)).to be_a_new(User) - end - - it "re-renders the 'new' template" do - post :create, {:user => invalid_attributes}, valid_session - expect(response).to render_template("new") + RSpec.describe UsersController, type: :controller do + describe "GET 'index'" do + it "is successful" do + get :index + expect(response.status).to eq 200 end end end - describe "PUT #update" do - context "with valid params" do - let(:new_attributes) { - skip("Add a hash of attributes valid for your model") - } - - it "updates the requested user" do - user = User.create! valid_attributes - put :update, {:id => user.to_param, :user => new_attributes}, valid_session - user.reload - skip("Add assertions for updated state") - end - it "assigns the requested user as @user" do - user = User.create! valid_attributes - put :update, {:id => user.to_param, :user => valid_attributes}, valid_session - expect(assigns(:user)).to eq(user) - end + # let(:valid_attributes) + # { + # user: { + # username: "Nemo1", + # email: "nemo@gmail.com", + # name: "Nemo", + # password: "Nemo123", + # password_confirmation: "Nemo123" + # } + # } - it "redirects to the user" do - user = User.create! valid_attributes - put :update, {:id => user.to_param, :user => valid_attributes}, valid_session - expect(response).to redirect_to(user) - end - end + # let(:invalid_attributes) { + # skip("Add a hash of attributes invalid for your model") + # } - context "with invalid params" do - it "assigns the user as @user" do - user = User.create! valid_attributes - put :update, {:id => user.to_param, :user => invalid_attributes}, valid_session - expect(assigns(:user)).to eq(user) - end - - it "re-renders the 'edit' template" do - user = User.create! valid_attributes - put :update, {:id => user.to_param, :user => invalid_attributes}, valid_session - expect(response).to render_template("edit") - end - end - end - - describe "DELETE #destroy" do - it "destroys the requested user" do - user = User.create! valid_attributes - expect { - delete :destroy, {:id => user.to_param}, valid_session - }.to change(User, :count).by(-1) - end - - it "redirects to the users list" do - user = User.create! valid_attributes - delete :destroy, {:id => user.to_param}, valid_session - expect(response).to redirect_to(users_url) - end - end - -end + # 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 + # UsersController. Be sure to keep this updated too. +# let(:valid_session) { {} } +# +# describe "GET #index" do +# it "assigns all users as @users" do +# user = User.create! valid_attributes +# get :index, {}, valid_session +# expect(assigns(:users)).to eq([user]) +# end +# end +# end +# +# describe "GET #show" do +# it "assigns the requested user as @user" do +# user = User.create! valid_attributes +# get :show, {:id => user.to_param}, valid_session +# expect(assigns(:user)).to eq(user) +# end +# end +# +# describe "GET #new" do +# it "assigns a new user as @user" do +# get :new, {}, valid_session +# expect(assigns(:user)).to be_a_new(User) +# end +# end +# +# describe "GET #edit" do +# it "assigns the requested user as @user" do +# user = User.create! valid_attributes +# get :edit, {:id => user.to_param}, valid_session +# expect(assigns(:user)).to eq(user) +# end +# end +# +# describe "POST #create" do +# context "with valid params" do +# it "creates a new User" do +# expect { +# post :create, {:user => valid_attributes}, valid_session +# }.to change(User, :count).by(1) +# end +# +# it "assigns a newly created user as @user" do +# post :create, {:user => valid_attributes}, valid_session +# expect(assigns(:user)).to be_a(User) +# expect(assigns(:user)).to be_persisted +# end +# +# it "redirects to the created user" do +# post :create, {:user => valid_attributes}, valid_session +# expect(response).to redirect_to(User.last) +# end +# end +# +# context "with invalid params" do +# it "assigns a newly created but unsaved user as @user" do +# post :create, {:user => invalid_attributes}, valid_session +# expect(assigns(:user)).to be_a_new(User) +# end +# +# it "re-renders the 'new' template" do +# post :create, {:user => invalid_attributes}, valid_session +# expect(response).to render_template("new") +# end +# end +# end +# +# describe "PUT #update" do +# context "with valid params" do +# let(:new_attributes) { +# skip("Add a hash of attributes valid for your model") +# } +# +# it "updates the requested user" do +# user = User.create! valid_attributes +# put :update, {:id => user.to_param, :user => new_attributes}, valid_session +# user.reload +# skip("Add assertions for updated state") +# end +# +# it "assigns the requested user as @user" do +# user = User.create! valid_attributes +# put :update, {:id => user.to_param, :user => valid_attributes}, valid_session +# expect(assigns(:user)).to eq(user) +# end +# +# it "redirects to the user" do +# user = User.create! valid_attributes +# put :update, {:id => user.to_param, :user => valid_attributes}, valid_session +# expect(response).to redirect_to(user) +# end +# end +# +# context "with invalid params" do +# it "assigns the user as @user" do +# user = User.create! valid_attributes +# put :update, {:id => user.to_param, :user => invalid_attributes}, valid_session +# expect(assigns(:user)).to eq(user) +# end +# +# it "re-renders the 'edit' template" do +# user = User.create! valid_attributes +# put :update, {:id => user.to_param, :user => invalid_attributes}, valid_session +# expect(response).to render_template("edit") +# end +# end +# end +# +# describe "DELETE #destroy" do +# it "destroys the requested user" do +# user = User.create! valid_attributes +# expect { +# delete :destroy, {:id => user.to_param}, valid_session +# }.to change(User, :count).by(-1) +# end +# +# it "redirects to the users list" do +# user = User.create! valid_attributes +# delete :destroy, {:id => user.to_param}, valid_session +# expect(response).to redirect_to(users_url) +# end +# end +# +# end diff --git a/spec/controllers/welcome_controller_spec.rb b/spec/controllers/welcome_controller_spec.rb index 133f9e71ec..d77cd0e594 100644 --- a/spec/controllers/welcome_controller_spec.rb +++ b/spec/controllers/welcome_controller_spec.rb @@ -1,12 +1,12 @@ -require 'rails_helper' - -RSpec.describe WelcomeController, type: :controller do - - describe "GET #index" do - it "returns http success" do - get :index - expect(response).to have_http_status(:success) - end - end - -end +# require 'rails_helper' +# +# RSpec.describe WelcomeController, type: :controller do +# +# describe "GET #index" do +# it "returns http success" do +# get :index +# expect(response).to have_http_status(:success) +# end +# end +# +# end diff --git a/spec/helpers/categories_helper_spec.rb b/spec/helpers/categories_helper_spec.rb index e717765aea..270d950770 100644 --- a/spec/helpers/categories_helper_spec.rb +++ b/spec/helpers/categories_helper_spec.rb @@ -1,15 +1,15 @@ -require 'rails_helper' - -# Specs in this file have access to a helper object that includes -# the CategoriesHelper. For example: +# require 'rails_helper' # -# describe CategoriesHelper do -# describe "string concat" do -# it "concats two strings with spaces" do -# expect(helper.concat_strings("this","that")).to eq("this that") -# end -# end +# # Specs in this file have access to a helper object that includes +# # the CategoriesHelper. For example: +# # +# # describe CategoriesHelper do +# # describe "string concat" do +# # it "concats two strings with spaces" do +# # expect(helper.concat_strings("this","that")).to eq("this that") +# # end +# # end +# # end +# RSpec.describe CategoriesHelper, type: :helper do +# pending "add some examples to (or delete) #{__FILE__}" # end -RSpec.describe CategoriesHelper, type: :helper do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/helpers/order_items_helper_spec.rb b/spec/helpers/order_items_helper_spec.rb index 21e1eaf98b..3384e17e75 100644 --- a/spec/helpers/order_items_helper_spec.rb +++ b/spec/helpers/order_items_helper_spec.rb @@ -1,15 +1,15 @@ -require 'rails_helper' - -# Specs in this file have access to a helper object that includes -# the OrderItemsHelper. For example: +# require 'rails_helper' # -# describe OrderItemsHelper do -# describe "string concat" do -# it "concats two strings with spaces" do -# expect(helper.concat_strings("this","that")).to eq("this that") -# end -# end +# # Specs in this file have access to a helper object that includes +# # the OrderItemsHelper. For example: +# # +# # describe OrderItemsHelper do +# # describe "string concat" do +# # it "concats two strings with spaces" do +# # expect(helper.concat_strings("this","that")).to eq("this that") +# # end +# # end +# # end +# RSpec.describe OrderItemsHelper, type: :helper do +# pending "add some examples to (or delete) #{__FILE__}" # end -RSpec.describe OrderItemsHelper, type: :helper do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/helpers/orders_helper_spec.rb b/spec/helpers/orders_helper_spec.rb index 6ba135076e..18db3a6599 100644 --- a/spec/helpers/orders_helper_spec.rb +++ b/spec/helpers/orders_helper_spec.rb @@ -1,15 +1,15 @@ -require 'rails_helper' - -# Specs in this file have access to a helper object that includes -# the OrdersHelper. For example: +# require 'rails_helper' # -# describe OrdersHelper do -# describe "string concat" do -# it "concats two strings with spaces" do -# expect(helper.concat_strings("this","that")).to eq("this that") -# end -# end +# # Specs in this file have access to a helper object that includes +# # the OrdersHelper. For example: +# # +# # describe OrdersHelper do +# # describe "string concat" do +# # it "concats two strings with spaces" do +# # expect(helper.concat_strings("this","that")).to eq("this that") +# # end +# # end +# # end +# RSpec.describe OrdersHelper, type: :helper do +# pending "add some examples to (or delete) #{__FILE__}" # end -RSpec.describe OrdersHelper, type: :helper do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/helpers/products_helper_spec.rb b/spec/helpers/products_helper_spec.rb index 40a13ae055..7439ee87bd 100644 --- a/spec/helpers/products_helper_spec.rb +++ b/spec/helpers/products_helper_spec.rb @@ -1,15 +1,15 @@ -require 'rails_helper' - -# Specs in this file have access to a helper object that includes -# the ProductsHelper. For example: +# require 'rails_helper' # -# describe ProductsHelper do -# describe "string concat" do -# it "concats two strings with spaces" do -# expect(helper.concat_strings("this","that")).to eq("this that") -# end -# end +# # Specs in this file have access to a helper object that includes +# # the ProductsHelper. For example: +# # +# # describe ProductsHelper do +# # describe "string concat" do +# # it "concats two strings with spaces" do +# # expect(helper.concat_strings("this","that")).to eq("this that") +# # end +# # end +# # end +# RSpec.describe ProductsHelper, type: :helper do +# pending "add some examples to (or delete) #{__FILE__}" # end -RSpec.describe ProductsHelper, type: :helper do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/helpers/reviews_helper_spec.rb b/spec/helpers/reviews_helper_spec.rb index 7139af6bbf..2b8e0b2363 100644 --- a/spec/helpers/reviews_helper_spec.rb +++ b/spec/helpers/reviews_helper_spec.rb @@ -1,15 +1,15 @@ -require 'rails_helper' - -# Specs in this file have access to a helper object that includes -# the ReviewsHelper. For example: +# require 'rails_helper' # -# describe ReviewsHelper do -# describe "string concat" do -# it "concats two strings with spaces" do -# expect(helper.concat_strings("this","that")).to eq("this that") -# end -# end +# # Specs in this file have access to a helper object that includes +# # the ReviewsHelper. For example: +# # +# # describe ReviewsHelper do +# # describe "string concat" do +# # it "concats two strings with spaces" do +# # expect(helper.concat_strings("this","that")).to eq("this that") +# # end +# # end +# # end +# RSpec.describe ReviewsHelper, type: :helper do +# pending "add some examples to (or delete) #{__FILE__}" # end -RSpec.describe ReviewsHelper, type: :helper do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/helpers/sessions_helper_spec.rb b/spec/helpers/sessions_helper_spec.rb index 9484198350..78426771aa 100644 --- a/spec/helpers/sessions_helper_spec.rb +++ b/spec/helpers/sessions_helper_spec.rb @@ -1,15 +1,15 @@ -require 'rails_helper' - -# Specs in this file have access to a helper object that includes -# the SessionsHelper. For example: +# require 'rails_helper' # -# describe SessionsHelper do -# describe "string concat" do -# it "concats two strings with spaces" do -# expect(helper.concat_strings("this","that")).to eq("this that") -# end -# end +# # Specs in this file have access to a helper object that includes +# # the SessionsHelper. For example: +# # +# # describe SessionsHelper do +# # describe "string concat" do +# # it "concats two strings with spaces" do +# # expect(helper.concat_strings("this","that")).to eq("this that") +# # end +# # end +# # end +# RSpec.describe SessionsHelper, type: :helper do +# pending "add some examples to (or delete) #{__FILE__}" # end -RSpec.describe SessionsHelper, type: :helper do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/helpers/users_helper_spec.rb b/spec/helpers/users_helper_spec.rb index b2e34440ef..f2eaab1e65 100644 --- a/spec/helpers/users_helper_spec.rb +++ b/spec/helpers/users_helper_spec.rb @@ -1,15 +1,15 @@ -require 'rails_helper' - -# Specs in this file have access to a helper object that includes -# the UsersHelper. For example: +# require 'rails_helper' # -# describe UsersHelper do -# describe "string concat" do -# it "concats two strings with spaces" do -# expect(helper.concat_strings("this","that")).to eq("this that") -# end -# end +# # Specs in this file have access to a helper object that includes +# # the UsersHelper. For example: +# # +# # describe UsersHelper do +# # describe "string concat" do +# # it "concats two strings with spaces" do +# # expect(helper.concat_strings("this","that")).to eq("this that") +# # end +# # end +# # end +# RSpec.describe UsersHelper, type: :helper do +# pending "add some examples to (or delete) #{__FILE__}" # end -RSpec.describe UsersHelper, type: :helper do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/helpers/welcome_helper_spec.rb b/spec/helpers/welcome_helper_spec.rb index a899852950..0184d6e26e 100644 --- a/spec/helpers/welcome_helper_spec.rb +++ b/spec/helpers/welcome_helper_spec.rb @@ -1,15 +1,15 @@ -require 'rails_helper' - -# Specs in this file have access to a helper object that includes -# the WelcomeHelper. For example: +# require 'rails_helper' # -# describe WelcomeHelper do -# describe "string concat" do -# it "concats two strings with spaces" do -# expect(helper.concat_strings("this","that")).to eq("this that") -# end -# end +# # Specs in this file have access to a helper object that includes +# # the WelcomeHelper. For example: +# # +# # describe WelcomeHelper do +# # describe "string concat" do +# # it "concats two strings with spaces" do +# # expect(helper.concat_strings("this","that")).to eq("this that") +# # end +# # end +# # end +# RSpec.describe WelcomeHelper, type: :helper do +# pending "add some examples to (or delete) #{__FILE__}" # end -RSpec.describe WelcomeHelper, type: :helper do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/models/category_spec.rb b/spec/models/category_spec.rb index 0c9fefae09..9db915c575 100644 --- a/spec/models/category_spec.rb +++ b/spec/models/category_spec.rb @@ -1,5 +1,5 @@ -require 'rails_helper' - -RSpec.describe Category, type: :model do - pending "add some examples to (or delete) #{__FILE__}" -end +# require 'rails_helper' +# +# RSpec.describe Category, type: :model do +# pending "add some examples to (or delete) #{__FILE__}" +# end diff --git a/spec/models/order_item_spec.rb b/spec/models/order_item_spec.rb index 3b4241223a..05dae62b2b 100644 --- a/spec/models/order_item_spec.rb +++ b/spec/models/order_item_spec.rb @@ -1,5 +1,5 @@ -require 'rails_helper' - -RSpec.describe OrderItem, type: :model do - pending "add some examples to (or delete) #{__FILE__}" -end +# require 'rails_helper' +# +# RSpec.describe OrderItem, type: :model do +# pending "add some examples to (or delete) #{__FILE__}" +# end diff --git a/spec/models/order_spec.rb b/spec/models/order_spec.rb index f48229a01b..412f61c081 100644 --- a/spec/models/order_spec.rb +++ b/spec/models/order_spec.rb @@ -1,5 +1,5 @@ -require 'rails_helper' - -RSpec.describe Order, type: :model do - pending "add some examples to (or delete) #{__FILE__}" -end +# require 'rails_helper' +# +# RSpec.describe Order, type: :model do +# pending "add some examples to (or delete) #{__FILE__}" +# end diff --git a/spec/models/product_spec.rb b/spec/models/product_spec.rb index f22fbfdd36..3ed2123666 100644 --- a/spec/models/product_spec.rb +++ b/spec/models/product_spec.rb @@ -1,5 +1,5 @@ -require 'rails_helper' - -RSpec.describe Product, type: :model do - pending "add some examples to (or delete) #{__FILE__}" -end +# require 'rails_helper' +# +# RSpec.describe Product, type: :model do +# pending "add some examples to (or delete) #{__FILE__}" +# end diff --git a/spec/models/review_spec.rb b/spec/models/review_spec.rb index 8fc758155e..fec60888bd 100644 --- a/spec/models/review_spec.rb +++ b/spec/models/review_spec.rb @@ -1,5 +1,5 @@ -require 'rails_helper' - -RSpec.describe Review, type: :model do - pending "add some examples to (or delete) #{__FILE__}" -end +# require 'rails_helper' +# +# RSpec.describe Review, type: :model do +# pending "add some examples to (or delete) #{__FILE__}" +# end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 47a31bb435..7608427118 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1,5 +1,5 @@ -require 'rails_helper' - -RSpec.describe User, type: :model do - pending "add some examples to (or delete) #{__FILE__}" -end +# require 'rails_helper' +# +# RSpec.describe User, type: :model do +# pending "add some examples to (or delete) #{__FILE__}" +# end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 6f1ab14638..d832eac2ef 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -1,57 +1,57 @@ -# This file is copied to spec/ when you run 'rails generate rspec:install' -ENV['RAILS_ENV'] ||= 'test' -require File.expand_path('../../config/environment', __FILE__) -# Prevent database truncation if the environment is production -abort("The Rails environment is running in production mode!") if Rails.env.production? -require 'spec_helper' -require 'rspec/rails' -# Add additional requires below this line. Rails is not loaded until this point! - -# Requires supporting ruby files with custom matchers and macros, etc, in -# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are -# run as spec files by default. This means that files in spec/support that end -# in _spec.rb will both be required and run as specs, causing the specs to be -# run twice. It is recommended that you do not name files matching this glob to -# end with _spec.rb. You can configure this pattern with the --pattern -# option on the command line or in ~/.rspec, .rspec or `.rspec-local`. +# # This file is copied to spec/ when you run 'rails generate rspec:install' +# ENV['RAILS_ENV'] ||= 'test' +# require File.expand_path('../../config/environment', __FILE__) +# # Prevent database truncation if the environment is production +# abort("The Rails environment is running in production mode!") if Rails.env.production? +# require 'spec_helper' +# require 'rspec/rails' +# # Add additional requires below this line. Rails is not loaded until this point! # -# The following line is provided for convenience purposes. It has the downside -# of increasing the boot-up time by auto-requiring all files in the support -# directory. Alternatively, in the individual `*_spec.rb` files, manually -# require only the support files necessary. +# # Requires supporting ruby files with custom matchers and macros, etc, in +# # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are +# # run as spec files by default. This means that files in spec/support that end +# # in _spec.rb will both be required and run as specs, causing the specs to be +# # run twice. It is recommended that you do not name files matching this glob to +# # end with _spec.rb. You can configure this pattern with the --pattern +# # option on the command line or in ~/.rspec, .rspec or `.rspec-local`. +# # +# # The following line is provided for convenience purposes. It has the downside +# # of increasing the boot-up time by auto-requiring all files in the support +# # directory. Alternatively, in the individual `*_spec.rb` files, manually +# # require only the support files necessary. +# # +# # Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } # -# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } - -# Checks for pending migration and applies them before tests are run. -# If you are not using ActiveRecord, you can remove this line. -ActiveRecord::Migration.maintain_test_schema! - -RSpec.configure do |config| - # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures - config.fixture_path = "#{::Rails.root}/spec/fixtures" - - # If you're not using ActiveRecord, or you'd prefer not to run each of your - # examples within a transaction, remove the following line or assign false - # instead of true. - config.use_transactional_fixtures = true - - # RSpec Rails can automatically mix in different behaviours to your tests - # based on their file location, for example enabling you to call `get` and - # `post` in specs under `spec/controllers`. - # - # You can disable this behaviour by removing the line below, and instead - # explicitly tag your specs with their type, e.g.: - # - # RSpec.describe UsersController, :type => :controller do - # # ... - # end - # - # The different available types are documented in the features, such as in - # https://relishapp.com/rspec/rspec-rails/docs - config.infer_spec_type_from_file_location! - - # Filter lines from Rails gems in backtraces. - config.filter_rails_from_backtrace! - # arbitrary gems may also be filtered via: - # config.filter_gems_from_backtrace("gem name") -end +# # Checks for pending migration and applies them before tests are run. +# # If you are not using ActiveRecord, you can remove this line. +# ActiveRecord::Migration.maintain_test_schema! +# +# RSpec.configure do |config| +# # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures +# config.fixture_path = "#{::Rails.root}/spec/fixtures" +# +# # If you're not using ActiveRecord, or you'd prefer not to run each of your +# # examples within a transaction, remove the following line or assign false +# # instead of true. +# config.use_transactional_fixtures = true +# +# # RSpec Rails can automatically mix in different behaviours to your tests +# # based on their file location, for example enabling you to call `get` and +# # `post` in specs under `spec/controllers`. +# # +# # You can disable this behaviour by removing the line below, and instead +# # explicitly tag your specs with their type, e.g.: +# # +# # RSpec.describe UsersController, :type => :controller do +# # # ... +# # end +# # +# # The different available types are documented in the features, such as in +# # https://relishapp.com/rspec/rspec-rails/docs +# config.infer_spec_type_from_file_location! +# +# # Filter lines from Rails gems in backtraces. +# config.filter_rails_from_backtrace! +# # arbitrary gems may also be filtered via: +# # config.filter_gems_from_backtrace("gem name") +# end diff --git a/spec/requests/categories_spec.rb b/spec/requests/categories_spec.rb index c5bdce0e1f..f5f62b7d64 100644 --- a/spec/requests/categories_spec.rb +++ b/spec/requests/categories_spec.rb @@ -1,10 +1,10 @@ -require 'rails_helper' - -RSpec.describe "Categories", type: :request do - describe "GET /categories" do - it "works! (now write some real specs)" do - get categories_path - expect(response).to have_http_status(200) - end - end -end +# require 'rails_helper' +# +# RSpec.describe "Categories", type: :request do +# describe "GET /categories" do +# it "works! (now write some real specs)" do +# get categories_path +# expect(response).to have_http_status(200) +# end +# end +# end diff --git a/spec/requests/order_items_spec.rb b/spec/requests/order_items_spec.rb index effbfdda3e..04b851dcf7 100644 --- a/spec/requests/order_items_spec.rb +++ b/spec/requests/order_items_spec.rb @@ -1,10 +1,10 @@ -require 'rails_helper' - -RSpec.describe "OrderItems", type: :request do - describe "GET /order_items" do - it "works! (now write some real specs)" do - get order_items_path - expect(response).to have_http_status(200) - end - end -end +# require 'rails_helper' +# +# RSpec.describe "OrderItems", type: :request do +# describe "GET /order_items" do +# it "works! (now write some real specs)" do +# get order_items_path +# expect(response).to have_http_status(200) +# end +# end +# end diff --git a/spec/requests/orders_spec.rb b/spec/requests/orders_spec.rb index 72550885ca..2430704d8c 100644 --- a/spec/requests/orders_spec.rb +++ b/spec/requests/orders_spec.rb @@ -1,10 +1,10 @@ -require 'rails_helper' - -RSpec.describe "Orders", type: :request do - describe "GET /orders" do - it "works! (now write some real specs)" do - get orders_path - expect(response).to have_http_status(200) - end - end -end +# require 'rails_helper' +# +# RSpec.describe "Orders", type: :request do +# describe "GET /orders" do +# it "works! (now write some real specs)" do +# get orders_path +# expect(response).to have_http_status(200) +# end +# end +# end diff --git a/spec/requests/products_spec.rb b/spec/requests/products_spec.rb index 314ad3de73..c00305b5f1 100644 --- a/spec/requests/products_spec.rb +++ b/spec/requests/products_spec.rb @@ -1,10 +1,10 @@ -require 'rails_helper' - -RSpec.describe "Products", type: :request do - describe "GET /products" do - it "works! (now write some real specs)" do - get products_path - expect(response).to have_http_status(200) - end - end -end +# require 'rails_helper' +# +# RSpec.describe "Products", type: :request do +# describe "GET /products" do +# it "works! (now write some real specs)" do +# get products_path +# expect(response).to have_http_status(200) +# end +# end +# end diff --git a/spec/requests/reviews_spec.rb b/spec/requests/reviews_spec.rb index 6e4dbbd063..8fa381cf52 100644 --- a/spec/requests/reviews_spec.rb +++ b/spec/requests/reviews_spec.rb @@ -1,10 +1,10 @@ -require 'rails_helper' - -RSpec.describe "Reviews", type: :request do - describe "GET /reviews" do - it "works! (now write some real specs)" do - get reviews_path - expect(response).to have_http_status(200) - end - end -end +# require 'rails_helper' +# +# RSpec.describe "Reviews", type: :request do +# describe "GET /reviews" do +# it "works! (now write some real specs)" do +# get reviews_path +# expect(response).to have_http_status(200) +# end +# end +# end diff --git a/spec/requests/users_spec.rb b/spec/requests/users_spec.rb index 8d6a01c5f4..c119547e0c 100644 --- a/spec/requests/users_spec.rb +++ b/spec/requests/users_spec.rb @@ -1,10 +1,10 @@ -require 'rails_helper' - -RSpec.describe "Users", type: :request do - describe "GET /users" do - it "works! (now write some real specs)" do - get users_path - expect(response).to have_http_status(200) - end - end -end +# require 'rails_helper' +# +# RSpec.describe "Users", type: :request do +# describe "GET /users" do +# it "works! (now write some real specs)" do +# get users_path +# expect(response).to have_http_status(200) +# end +# end +# end diff --git a/spec/routing/categories_routing_spec.rb b/spec/routing/categories_routing_spec.rb index 162e5d1397..f8ceb9caed 100644 --- a/spec/routing/categories_routing_spec.rb +++ b/spec/routing/categories_routing_spec.rb @@ -1,39 +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 +# 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/routing/order_items_routing_spec.rb b/spec/routing/order_items_routing_spec.rb index d6c77511f8..6299e81ea4 100644 --- a/spec/routing/order_items_routing_spec.rb +++ b/spec/routing/order_items_routing_spec.rb @@ -1,39 +1,39 @@ -require "rails_helper" - -RSpec.describe OrderItemsController, type: :routing do - describe "routing" do - - it "routes to #index" do - expect(:get => "/order_items").to route_to("order_items#index") - end - - it "routes to #new" do - expect(:get => "/order_items/new").to route_to("order_items#new") - end - - it "routes to #show" do - expect(:get => "/order_items/1").to route_to("order_items#show", :id => "1") - end - - it "routes to #edit" do - expect(:get => "/order_items/1/edit").to route_to("order_items#edit", :id => "1") - end - - it "routes to #create" do - expect(:post => "/order_items").to route_to("order_items#create") - end - - it "routes to #update via PUT" do - expect(:put => "/order_items/1").to route_to("order_items#update", :id => "1") - end - - it "routes to #update via PATCH" do - expect(:patch => "/order_items/1").to route_to("order_items#update", :id => "1") - end - - it "routes to #destroy" do - expect(:delete => "/order_items/1").to route_to("order_items#destroy", :id => "1") - end - - end -end +# require "rails_helper" +# +# RSpec.describe OrderItemsController, type: :routing do +# describe "routing" do +# +# it "routes to #index" do +# expect(:get => "/order_items").to route_to("order_items#index") +# end +# +# it "routes to #new" do +# expect(:get => "/order_items/new").to route_to("order_items#new") +# end +# +# it "routes to #show" do +# expect(:get => "/order_items/1").to route_to("order_items#show", :id => "1") +# end +# +# it "routes to #edit" do +# expect(:get => "/order_items/1/edit").to route_to("order_items#edit", :id => "1") +# end +# +# it "routes to #create" do +# expect(:post => "/order_items").to route_to("order_items#create") +# end +# +# it "routes to #update via PUT" do +# expect(:put => "/order_items/1").to route_to("order_items#update", :id => "1") +# end +# +# it "routes to #update via PATCH" do +# expect(:patch => "/order_items/1").to route_to("order_items#update", :id => "1") +# end +# +# it "routes to #destroy" do +# expect(:delete => "/order_items/1").to route_to("order_items#destroy", :id => "1") +# end +# +# end +# end diff --git a/spec/routing/orders_routing_spec.rb b/spec/routing/orders_routing_spec.rb index 2e44550636..50a42377ba 100644 --- a/spec/routing/orders_routing_spec.rb +++ b/spec/routing/orders_routing_spec.rb @@ -1,39 +1,39 @@ -require "rails_helper" - -RSpec.describe OrdersController, type: :routing do - describe "routing" do - - it "routes to #index" do - expect(:get => "/orders").to route_to("orders#index") - end - - it "routes to #new" do - expect(:get => "/orders/new").to route_to("orders#new") - end - - it "routes to #show" do - expect(:get => "/orders/1").to route_to("orders#show", :id => "1") - end - - it "routes to #edit" do - expect(:get => "/orders/1/edit").to route_to("orders#edit", :id => "1") - end - - it "routes to #create" do - expect(:post => "/orders").to route_to("orders#create") - end - - it "routes to #update via PUT" do - expect(:put => "/orders/1").to route_to("orders#update", :id => "1") - end - - it "routes to #update via PATCH" do - expect(:patch => "/orders/1").to route_to("orders#update", :id => "1") - end - - it "routes to #destroy" do - expect(:delete => "/orders/1").to route_to("orders#destroy", :id => "1") - end - - end -end +# require "rails_helper" +# +# RSpec.describe OrdersController, type: :routing do +# describe "routing" do +# +# it "routes to #index" do +# expect(:get => "/orders").to route_to("orders#index") +# end +# +# it "routes to #new" do +# expect(:get => "/orders/new").to route_to("orders#new") +# end +# +# it "routes to #show" do +# expect(:get => "/orders/1").to route_to("orders#show", :id => "1") +# end +# +# it "routes to #edit" do +# expect(:get => "/orders/1/edit").to route_to("orders#edit", :id => "1") +# end +# +# it "routes to #create" do +# expect(:post => "/orders").to route_to("orders#create") +# end +# +# it "routes to #update via PUT" do +# expect(:put => "/orders/1").to route_to("orders#update", :id => "1") +# end +# +# it "routes to #update via PATCH" do +# expect(:patch => "/orders/1").to route_to("orders#update", :id => "1") +# end +# +# it "routes to #destroy" do +# expect(:delete => "/orders/1").to route_to("orders#destroy", :id => "1") +# end +# +# end +# end diff --git a/spec/routing/products_routing_spec.rb b/spec/routing/products_routing_spec.rb index e9f99d4b23..c076930c87 100644 --- a/spec/routing/products_routing_spec.rb +++ b/spec/routing/products_routing_spec.rb @@ -1,39 +1,39 @@ -require "rails_helper" - -RSpec.describe ProductsController, type: :routing do - describe "routing" do - - it "routes to #index" do - expect(:get => "/products").to route_to("products#index") - end - - it "routes to #new" do - expect(:get => "/products/new").to route_to("products#new") - end - - it "routes to #show" do - expect(:get => "/products/1").to route_to("products#show", :id => "1") - end - - it "routes to #edit" do - expect(:get => "/products/1/edit").to route_to("products#edit", :id => "1") - end - - it "routes to #create" do - expect(:post => "/products").to route_to("products#create") - end - - it "routes to #update via PUT" do - expect(:put => "/products/1").to route_to("products#update", :id => "1") - end - - it "routes to #update via PATCH" do - expect(:patch => "/products/1").to route_to("products#update", :id => "1") - end - - it "routes to #destroy" do - expect(:delete => "/products/1").to route_to("products#destroy", :id => "1") - end - - end -end +# require "rails_helper" +# +# RSpec.describe ProductsController, type: :routing do +# describe "routing" do +# +# it "routes to #index" do +# expect(:get => "/products").to route_to("products#index") +# end +# +# it "routes to #new" do +# expect(:get => "/products/new").to route_to("products#new") +# end +# +# it "routes to #show" do +# expect(:get => "/products/1").to route_to("products#show", :id => "1") +# end +# +# it "routes to #edit" do +# expect(:get => "/products/1/edit").to route_to("products#edit", :id => "1") +# end +# +# it "routes to #create" do +# expect(:post => "/products").to route_to("products#create") +# end +# +# it "routes to #update via PUT" do +# expect(:put => "/products/1").to route_to("products#update", :id => "1") +# end +# +# it "routes to #update via PATCH" do +# expect(:patch => "/products/1").to route_to("products#update", :id => "1") +# end +# +# it "routes to #destroy" do +# expect(:delete => "/products/1").to route_to("products#destroy", :id => "1") +# end +# +# end +# end diff --git a/spec/routing/reviews_routing_spec.rb b/spec/routing/reviews_routing_spec.rb index 24fa514090..2430082833 100644 --- a/spec/routing/reviews_routing_spec.rb +++ b/spec/routing/reviews_routing_spec.rb @@ -1,39 +1,39 @@ -require "rails_helper" - -RSpec.describe ReviewsController, type: :routing do - describe "routing" do - - it "routes to #index" do - expect(:get => "/reviews").to route_to("reviews#index") - end - - it "routes to #new" do - expect(:get => "/reviews/new").to route_to("reviews#new") - end - - it "routes to #show" do - expect(:get => "/reviews/1").to route_to("reviews#show", :id => "1") - end - - it "routes to #edit" do - expect(:get => "/reviews/1/edit").to route_to("reviews#edit", :id => "1") - end - - it "routes to #create" do - expect(:post => "/reviews").to route_to("reviews#create") - end - - it "routes to #update via PUT" do - expect(:put => "/reviews/1").to route_to("reviews#update", :id => "1") - end - - it "routes to #update via PATCH" do - expect(:patch => "/reviews/1").to route_to("reviews#update", :id => "1") - end - - it "routes to #destroy" do - expect(:delete => "/reviews/1").to route_to("reviews#destroy", :id => "1") - end - - end -end +# require "rails_helper" +# +# RSpec.describe ReviewsController, type: :routing do +# describe "routing" do +# +# it "routes to #index" do +# expect(:get => "/reviews").to route_to("reviews#index") +# end +# +# it "routes to #new" do +# expect(:get => "/reviews/new").to route_to("reviews#new") +# end +# +# it "routes to #show" do +# expect(:get => "/reviews/1").to route_to("reviews#show", :id => "1") +# end +# +# it "routes to #edit" do +# expect(:get => "/reviews/1/edit").to route_to("reviews#edit", :id => "1") +# end +# +# it "routes to #create" do +# expect(:post => "/reviews").to route_to("reviews#create") +# end +# +# it "routes to #update via PUT" do +# expect(:put => "/reviews/1").to route_to("reviews#update", :id => "1") +# end +# +# it "routes to #update via PATCH" do +# expect(:patch => "/reviews/1").to route_to("reviews#update", :id => "1") +# end +# +# it "routes to #destroy" do +# expect(:delete => "/reviews/1").to route_to("reviews#destroy", :id => "1") +# end +# +# end +# end diff --git a/spec/routing/users_routing_spec.rb b/spec/routing/users_routing_spec.rb index f6794fe925..ba55426e16 100644 --- a/spec/routing/users_routing_spec.rb +++ b/spec/routing/users_routing_spec.rb @@ -1,39 +1,39 @@ -require "rails_helper" - -RSpec.describe UsersController, type: :routing do - describe "routing" do - - it "routes to #index" do - expect(:get => "/users").to route_to("users#index") - end - - it "routes to #new" do - expect(:get => "/users/new").to route_to("users#new") - end - - it "routes to #show" do - expect(:get => "/users/1").to route_to("users#show", :id => "1") - end - - it "routes to #edit" do - expect(:get => "/users/1/edit").to route_to("users#edit", :id => "1") - end - - it "routes to #create" do - expect(:post => "/users").to route_to("users#create") - end - - it "routes to #update via PUT" do - expect(:put => "/users/1").to route_to("users#update", :id => "1") - end - - it "routes to #update via PATCH" do - expect(:patch => "/users/1").to route_to("users#update", :id => "1") - end - - it "routes to #destroy" do - expect(:delete => "/users/1").to route_to("users#destroy", :id => "1") - end - - end -end +# require "rails_helper" +# +# RSpec.describe UsersController, type: :routing do +# describe "routing" do +# +# it "routes to #index" do +# expect(:get => "/users").to route_to("users#index") +# end +# +# it "routes to #new" do +# expect(:get => "/users/new").to route_to("users#new") +# end +# +# it "routes to #show" do +# expect(:get => "/users/1").to route_to("users#show", :id => "1") +# end +# +# it "routes to #edit" do +# expect(:get => "/users/1/edit").to route_to("users#edit", :id => "1") +# end +# +# it "routes to #create" do +# expect(:post => "/users").to route_to("users#create") +# end +# +# it "routes to #update via PUT" do +# expect(:put => "/users/1").to route_to("users#update", :id => "1") +# end +# +# it "routes to #update via PATCH" do +# expect(:patch => "/users/1").to route_to("users#update", :id => "1") +# end +# +# it "routes to #destroy" do +# expect(:delete => "/users/1").to route_to("users#destroy", :id => "1") +# end +# +# end +# end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 61e27385c3..50f54eb442 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,92 +1,92 @@ -# This file was generated by the `rails generate rspec:install` command. Conventionally, all -# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. -# The generated `.rspec` file contains `--require spec_helper` which will cause -# this file to always be loaded, without a need to explicitly require it in any -# files. +# # This file was generated by the `rails generate rspec:install` command. Conventionally, all +# # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# # The generated `.rspec` file contains `--require spec_helper` which will cause +# # this file to always be loaded, without a need to explicitly require it in any +# # files. +# # +# # Given that it is always loaded, you are encouraged to keep this file as +# # light-weight as possible. Requiring heavyweight dependencies from this file +# # will add to the boot time of your test suite on EVERY test run, even for an +# # individual file that may not need all of that loaded. Instead, consider making +# # a separate helper file that requires the additional dependencies and performs +# # the additional setup, and require it from the spec files that actually need +# # it. +# # +# # The `.rspec` file also contains a few flags that are not defaults but that +# # users commonly want. +# # +# # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +# RSpec.configure do |config| +# # rspec-expectations config goes here. You can use an alternate +# # assertion/expectation library such as wrong or the stdlib/minitest +# # assertions if you prefer. +# config.expect_with :rspec do |expectations| +# # This option will default to `true` in RSpec 4. It makes the `description` +# # and `failure_message` of custom matchers include text for helper methods +# # defined using `chain`, e.g.: +# # be_bigger_than(2).and_smaller_than(4).description +# # # => "be bigger than 2 and smaller than 4" +# # ...rather than: +# # # => "be bigger than 2" +# expectations.include_chain_clauses_in_custom_matcher_descriptions = true +# end # -# Given that it is always loaded, you are encouraged to keep this file as -# light-weight as possible. Requiring heavyweight dependencies from this file -# will add to the boot time of your test suite on EVERY test run, even for an -# individual file that may not need all of that loaded. Instead, consider making -# a separate helper file that requires the additional dependencies and performs -# the additional setup, and require it from the spec files that actually need -# it. +# # rspec-mocks config goes here. You can use an alternate test double +# # library (such as bogus or mocha) by changing the `mock_with` option here. +# config.mock_with :rspec do |mocks| +# # Prevents you from mocking or stubbing a method that does not exist on +# # a real object. This is generally recommended, and will default to +# # `true` in RSpec 4. +# mocks.verify_partial_doubles = true +# end # -# The `.rspec` file also contains a few flags that are not defaults but that -# users commonly want. +# # The settings below are suggested to provide a good initial experience +# # with RSpec, but feel free to customize to your heart's content. +# =begin +# # These two settings work together to allow you to limit a spec run +# # to individual examples or groups you care about by tagging them with +# # `:focus` metadata. When nothing is tagged with `:focus`, all examples +# # get run. +# config.filter_run :focus +# config.run_all_when_everything_filtered = true # -# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration -RSpec.configure do |config| - # rspec-expectations config goes here. You can use an alternate - # assertion/expectation library such as wrong or the stdlib/minitest - # assertions if you prefer. - config.expect_with :rspec do |expectations| - # This option will default to `true` in RSpec 4. It makes the `description` - # and `failure_message` of custom matchers include text for helper methods - # defined using `chain`, e.g.: - # be_bigger_than(2).and_smaller_than(4).description - # # => "be bigger than 2 and smaller than 4" - # ...rather than: - # # => "be bigger than 2" - expectations.include_chain_clauses_in_custom_matcher_descriptions = true - end - - # rspec-mocks config goes here. You can use an alternate test double - # library (such as bogus or mocha) by changing the `mock_with` option here. - config.mock_with :rspec do |mocks| - # Prevents you from mocking or stubbing a method that does not exist on - # a real object. This is generally recommended, and will default to - # `true` in RSpec 4. - mocks.verify_partial_doubles = true - end - -# The settings below are suggested to provide a good initial experience -# with RSpec, but feel free to customize to your heart's content. -=begin - # These two settings work together to allow you to limit a spec run - # to individual examples or groups you care about by tagging them with - # `:focus` metadata. When nothing is tagged with `:focus`, all examples - # get run. - config.filter_run :focus - config.run_all_when_everything_filtered = true - - # Allows RSpec to persist some state between runs in order to support - # the `--only-failures` and `--next-failure` CLI options. We recommend - # you configure your source control system to ignore this file. - config.example_status_persistence_file_path = "spec/examples.txt" - - # Limits the available syntax to the non-monkey patched syntax that is - # recommended. For more details, see: - # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ - # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ - # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode - config.disable_monkey_patching! - - # Many RSpec users commonly either run the entire suite or an individual - # file, and it's useful to allow more verbose output when running an - # individual spec file. - if config.files_to_run.one? - # Use the documentation formatter for detailed output, - # unless a formatter has already been configured - # (e.g. via a command-line flag). - config.default_formatter = 'doc' - end - - # Print the 10 slowest examples and example groups at the - # end of the spec run, to help surface which specs are running - # particularly slow. - config.profile_examples = 10 - - # Run specs in random order to surface order dependencies. If you find an - # order dependency and want to debug it, you can fix the order by providing - # the seed, which is printed after each run. - # --seed 1234 - config.order = :random - - # Seed global randomization in this process using the `--seed` CLI option. - # Setting this allows you to use `--seed` to deterministically reproduce - # test failures related to randomization by passing the same `--seed` value - # as the one that triggered the failure. - Kernel.srand config.seed -=end -end +# # Allows RSpec to persist some state between runs in order to support +# # the `--only-failures` and `--next-failure` CLI options. We recommend +# # you configure your source control system to ignore this file. +# config.example_status_persistence_file_path = "spec/examples.txt" +# +# # Limits the available syntax to the non-monkey patched syntax that is +# # recommended. For more details, see: +# # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ +# # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ +# # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode +# config.disable_monkey_patching! +# +# # Many RSpec users commonly either run the entire suite or an individual +# # file, and it's useful to allow more verbose output when running an +# # individual spec file. +# if config.files_to_run.one? +# # Use the documentation formatter for detailed output, +# # unless a formatter has already been configured +# # (e.g. via a command-line flag). +# config.default_formatter = 'doc' +# end +# +# # Print the 10 slowest examples and example groups at the +# # end of the spec run, to help surface which specs are running +# # particularly slow. +# config.profile_examples = 10 +# +# # Run specs in random order to surface order dependencies. If you find an +# # order dependency and want to debug it, you can fix the order by providing +# # the seed, which is printed after each run. +# # --seed 1234 +# config.order = :random +# +# # Seed global randomization in this process using the `--seed` CLI option. +# # Setting this allows you to use `--seed` to deterministically reproduce +# # test failures related to randomization by passing the same `--seed` value +# # as the one that triggered the failure. +# Kernel.srand config.seed +# =end +# end From 721b82eb59afa54c45515e9def007440ce7a6365 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 10 Dec 2015 14:10:43 -0800 Subject: [PATCH 079/299] fix bug with showing all products --- app/assets/javascripts/application.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index b7483a4ce2..3800211fb3 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -16,16 +16,13 @@ //= require bootstrap-sprockets //= require_tree . -$(document).ready(function() { +var resize_thumbs = function(){ var thumb = document.getElementsByClassName('thumbnail')[0]; var width = thumb.clientWidth; console.log(width); $('.img-container').css({ "height": width+"px" }); -}); +}; -$(window).resize(function() { - var thumb = document.getElementsByClassName('thumbnail')[0]; - var width = thumb.clientWidth; - console.log(width); - $('.img-container').css({ "height": width+"px" }); -}); +$(document).ready(resize_thumbs); +$(window).resize(resize_thumbs); +$(document).on('page:change', resize_thumbs); From a3e1204975df2e4ebf8b2a5ce5e7fcd1c6ef2b8c Mon Sep 17 00:00:00 2001 From: Tammy Date: Thu, 10 Dec 2015 14:33:09 -0800 Subject: [PATCH 080/299] Now I really comment everything out- and returned the helpers --- spec/controllers/users_controller_spec.rb | 303 +++++++++--------- spec/models/category_spec.rb | 1 + spec/rails_helper.rb | 110 +++---- spec/spec_helper.rb | 178 +++++----- spec/views/categories/edit.html.erb_spec.rb | 36 +-- spec/views/categories/index.html.erb_spec.rb | 38 +-- spec/views/categories/new.html.erb_spec.rb | 36 +-- spec/views/categories/show.html.erb_spec.rb | 28 +- spec/views/order_items/edit.html.erb_spec.rb | 48 +-- spec/views/order_items/index.html.erb_spec.rb | 50 +-- spec/views/order_items/new.html.erb_spec.rb | 48 +-- spec/views/order_items/show.html.erb_spec.rb | 36 +-- spec/views/orders/edit.html.erb_spec.rb | 78 ++--- spec/views/orders/index.html.erb_spec.rb | 80 ++--- spec/views/orders/new.html.erb_spec.rb | 78 ++--- spec/views/orders/show.html.erb_spec.rb | 56 ++-- spec/views/products/edit.html.erb_spec.rb | 72 ++--- spec/views/products/index.html.erb_spec.rb | 74 ++--- spec/views/products/new.html.erb_spec.rb | 72 ++--- spec/views/products/show.html.erb_spec.rb | 52 +-- spec/views/reviews/edit.html.erb_spec.rb | 48 +-- spec/views/reviews/index.html.erb_spec.rb | 50 +-- spec/views/reviews/new.html.erb_spec.rb | 48 +-- spec/views/reviews/show.html.erb_spec.rb | 36 +-- spec/views/users/edit.html.erb_spec.rb | 54 ++-- spec/views/users/index.html.erb_spec.rb | 56 ++-- spec/views/users/new.html.erb_spec.rb | 54 ++-- spec/views/users/show.html.erb_spec.rb | 40 +-- spec/views/welcome/index.html.erb_spec.rb | 10 +- 29 files changed, 939 insertions(+), 931 deletions(-) diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index b9b2373ea1..0f7d9e1cef 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -1,158 +1,165 @@ 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. - # This should return the minimal set of attributes required to create a valid - # User. As you add validations to User, be sure to - # adjust the attributes here as well. - RSpec.describe UsersController, type: :controller do - describe "GET 'index'" do - it "is successful" do - get :index - expect(response.status).to eq 200 - end - end +RSpec.describe UsersController, type: :controller do + describe "GET 'index'" do + it "is successful" do + get :index + expect(response.status).to eq 200 end +end - - # let(:valid_attributes) - # { - # user: { - # username: "Nemo1", - # email: "nemo@gmail.com", - # name: "Nemo", - # password: "Nemo123", - # password_confirmation: "Nemo123" - # } + # This should return the minimal set of attributes required to create a valid + # User. As you add validations to User, be sure to + # # adjust the attributes here as well. + # let(:valid_attributes) { + # skip("Add a hash of attributes valid for your model") # } - + # # let(:invalid_attributes) { # skip("Add a hash of attributes invalid for your model") # } + # + # # 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 + # # UsersController. Be sure to keep this updated too. + # let(:valid_session) { {} } + # + # describe "GET #index" do + # it "assigns all users as @users" do + # user = User.create! valid_attributes + # get :index, {}, valid_session + # expect(assigns(:users)).to eq([user]) + # end + # end + # + # describe "GET #show" do + # it "assigns the requested user as @user" do + # user = User.create! valid_attributes + # get :show, {:id => user.to_param}, valid_session + # expect(assigns(:user)).to eq(user) + # end + # end + # + # describe "GET #new" do + # it "assigns a new user as @user" do + # get :new, {}, valid_session + # expect(assigns(:user)).to be_a_new(User) + # end + # end + # + # describe "GET #edit" do + # it "assigns the requested user as @user" do + # user = User.create! valid_attributes + # get :edit, {:id => user.to_param}, valid_session + # expect(assigns(:user)).to eq(user) + # end + # end + # + # describe "POST #create" do + # context "with valid params" do + # it "creates a new User" do + # expect { + # post :create, {:user => valid_attributes}, valid_session + # }.to change(User, :count).by(1) + # end + # + # it "assigns a newly created user as @user" do + # post :create, {:user => valid_attributes}, valid_session + # expect(assigns(:user)).to be_a(User) + # expect(assigns(:user)).to be_persisted + # end + # + # it "redirects to the created user" do + # post :create, {:user => valid_attributes}, valid_session + # expect(response).to redirect_to(User.last) + # end + # end + # + # context "with invalid params" do + # it "assigns a newly created but unsaved user as @user" do + # post :create, {:user => invalid_attributes}, valid_session + # expect(assigns(:user)).to be_a_new(User) + # end + # + # it "re-renders the 'new' template" do + # post :create, {:user => invalid_attributes}, valid_session + # expect(response).to render_template("new") + # end + # end + # end + # + # describe "PUT #update" do + # context "with valid params" do + # let(:new_attributes) { + # skip("Add a hash of attributes valid for your model") + # } + # + # it "updates the requested user" do + # user = User.create! valid_attributes + # put :update, {:id => user.to_param, :user => new_attributes}, valid_session + # user.reload + # skip("Add assertions for updated state") + # end + # + # it "assigns the requested user as @user" do + # user = User.create! valid_attributes + # put :update, {:id => user.to_param, :user => valid_attributes}, valid_session + # expect(assigns(:user)).to eq(user) + # end + # + # it "redirects to the user" do + # user = User.create! valid_attributes + # put :update, {:id => user.to_param, :user => valid_attributes}, valid_session + # expect(response).to redirect_to(user) + # end + # end + # + # context "with invalid params" do + # it "assigns the user as @user" do + # user = User.create! valid_attributes + # put :update, {:id => user.to_param, :user => invalid_attributes}, valid_session + # expect(assigns(:user)).to eq(user) + # end + # + # it "re-renders the 'edit' template" do + # user = User.create! valid_attributes + # put :update, {:id => user.to_param, :user => invalid_attributes}, valid_session + # expect(response).to render_template("edit") + # end + # end + # end + # + # describe "DELETE #destroy" do + # it "destroys the requested user" do + # user = User.create! valid_attributes + # expect { + # delete :destroy, {:id => user.to_param}, valid_session + # }.to change(User, :count).by(-1) + # end + # + # it "redirects to the users list" do + # user = User.create! valid_attributes + # delete :destroy, {:id => user.to_param}, valid_session + # expect(response).to redirect_to(users_url) + # end + # end - # 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 - # UsersController. Be sure to keep this updated too. -# let(:valid_session) { {} } -# -# describe "GET #index" do -# it "assigns all users as @users" do -# user = User.create! valid_attributes -# get :index, {}, valid_session -# expect(assigns(:users)).to eq([user]) -# end -# end -# end -# -# describe "GET #show" do -# it "assigns the requested user as @user" do -# user = User.create! valid_attributes -# get :show, {:id => user.to_param}, valid_session -# expect(assigns(:user)).to eq(user) -# end -# end -# -# describe "GET #new" do -# it "assigns a new user as @user" do -# get :new, {}, valid_session -# expect(assigns(:user)).to be_a_new(User) -# end -# end -# -# describe "GET #edit" do -# it "assigns the requested user as @user" do -# user = User.create! valid_attributes -# get :edit, {:id => user.to_param}, valid_session -# expect(assigns(:user)).to eq(user) -# end -# end -# -# describe "POST #create" do -# context "with valid params" do -# it "creates a new User" do -# expect { -# post :create, {:user => valid_attributes}, valid_session -# }.to change(User, :count).by(1) -# end -# -# it "assigns a newly created user as @user" do -# post :create, {:user => valid_attributes}, valid_session -# expect(assigns(:user)).to be_a(User) -# expect(assigns(:user)).to be_persisted -# end -# -# it "redirects to the created user" do -# post :create, {:user => valid_attributes}, valid_session -# expect(response).to redirect_to(User.last) -# end -# end -# -# context "with invalid params" do -# it "assigns a newly created but unsaved user as @user" do -# post :create, {:user => invalid_attributes}, valid_session -# expect(assigns(:user)).to be_a_new(User) -# end -# -# it "re-renders the 'new' template" do -# post :create, {:user => invalid_attributes}, valid_session -# expect(response).to render_template("new") -# end -# end -# end -# -# describe "PUT #update" do -# context "with valid params" do -# let(:new_attributes) { -# skip("Add a hash of attributes valid for your model") -# } -# -# it "updates the requested user" do -# user = User.create! valid_attributes -# put :update, {:id => user.to_param, :user => new_attributes}, valid_session -# user.reload -# skip("Add assertions for updated state") -# end -# -# it "assigns the requested user as @user" do -# user = User.create! valid_attributes -# put :update, {:id => user.to_param, :user => valid_attributes}, valid_session -# expect(assigns(:user)).to eq(user) -# end -# -# it "redirects to the user" do -# user = User.create! valid_attributes -# put :update, {:id => user.to_param, :user => valid_attributes}, valid_session -# expect(response).to redirect_to(user) -# end -# end -# -# context "with invalid params" do -# it "assigns the user as @user" do -# user = User.create! valid_attributes -# put :update, {:id => user.to_param, :user => invalid_attributes}, valid_session -# expect(assigns(:user)).to eq(user) -# end -# -# it "re-renders the 'edit' template" do -# user = User.create! valid_attributes -# put :update, {:id => user.to_param, :user => invalid_attributes}, valid_session -# expect(response).to render_template("edit") -# end -# end -# end -# -# describe "DELETE #destroy" do -# it "destroys the requested user" do -# user = User.create! valid_attributes -# expect { -# delete :destroy, {:id => user.to_param}, valid_session -# }.to change(User, :count).by(-1) -# end -# -# it "redirects to the users list" do -# user = User.create! valid_attributes -# delete :destroy, {:id => user.to_param}, valid_session -# expect(response).to redirect_to(users_url) -# end -# end -# -# end +end diff --git a/spec/models/category_spec.rb b/spec/models/category_spec.rb index 9db915c575..fc3d6c0c7e 100644 --- a/spec/models/category_spec.rb +++ b/spec/models/category_spec.rb @@ -3,3 +3,4 @@ # RSpec.describe Category, type: :model do # pending "add some examples to (or delete) #{__FILE__}" # end +# # diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index d832eac2ef..6f1ab14638 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -1,57 +1,57 @@ -# # This file is copied to spec/ when you run 'rails generate rspec:install' -# ENV['RAILS_ENV'] ||= 'test' -# require File.expand_path('../../config/environment', __FILE__) -# # Prevent database truncation if the environment is production -# abort("The Rails environment is running in production mode!") if Rails.env.production? -# require 'spec_helper' -# require 'rspec/rails' -# # Add additional requires below this line. Rails is not loaded until this point! +# This file is copied to spec/ when you run 'rails generate rspec:install' +ENV['RAILS_ENV'] ||= 'test' +require File.expand_path('../../config/environment', __FILE__) +# Prevent database truncation if the environment is production +abort("The Rails environment is running in production mode!") if Rails.env.production? +require 'spec_helper' +require 'rspec/rails' +# Add additional requires below this line. Rails is not loaded until this point! + +# Requires supporting ruby files with custom matchers and macros, etc, in +# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are +# run as spec files by default. This means that files in spec/support that end +# in _spec.rb will both be required and run as specs, causing the specs to be +# run twice. It is recommended that you do not name files matching this glob to +# end with _spec.rb. You can configure this pattern with the --pattern +# option on the command line or in ~/.rspec, .rspec or `.rspec-local`. # -# # Requires supporting ruby files with custom matchers and macros, etc, in -# # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are -# # run as spec files by default. This means that files in spec/support that end -# # in _spec.rb will both be required and run as specs, causing the specs to be -# # run twice. It is recommended that you do not name files matching this glob to -# # end with _spec.rb. You can configure this pattern with the --pattern -# # option on the command line or in ~/.rspec, .rspec or `.rspec-local`. -# # -# # The following line is provided for convenience purposes. It has the downside -# # of increasing the boot-up time by auto-requiring all files in the support -# # directory. Alternatively, in the individual `*_spec.rb` files, manually -# # require only the support files necessary. -# # -# # Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } +# The following line is provided for convenience purposes. It has the downside +# of increasing the boot-up time by auto-requiring all files in the support +# directory. Alternatively, in the individual `*_spec.rb` files, manually +# require only the support files necessary. # -# # Checks for pending migration and applies them before tests are run. -# # If you are not using ActiveRecord, you can remove this line. -# ActiveRecord::Migration.maintain_test_schema! -# -# RSpec.configure do |config| -# # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures -# config.fixture_path = "#{::Rails.root}/spec/fixtures" -# -# # If you're not using ActiveRecord, or you'd prefer not to run each of your -# # examples within a transaction, remove the following line or assign false -# # instead of true. -# config.use_transactional_fixtures = true -# -# # RSpec Rails can automatically mix in different behaviours to your tests -# # based on their file location, for example enabling you to call `get` and -# # `post` in specs under `spec/controllers`. -# # -# # You can disable this behaviour by removing the line below, and instead -# # explicitly tag your specs with their type, e.g.: -# # -# # RSpec.describe UsersController, :type => :controller do -# # # ... -# # end -# # -# # The different available types are documented in the features, such as in -# # https://relishapp.com/rspec/rspec-rails/docs -# config.infer_spec_type_from_file_location! -# -# # Filter lines from Rails gems in backtraces. -# config.filter_rails_from_backtrace! -# # arbitrary gems may also be filtered via: -# # config.filter_gems_from_backtrace("gem name") -# end +# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } + +# Checks for pending migration and applies them before tests are run. +# If you are not using ActiveRecord, you can remove this line. +ActiveRecord::Migration.maintain_test_schema! + +RSpec.configure do |config| + # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures + config.fixture_path = "#{::Rails.root}/spec/fixtures" + + # If you're not using ActiveRecord, or you'd prefer not to run each of your + # examples within a transaction, remove the following line or assign false + # instead of true. + config.use_transactional_fixtures = true + + # RSpec Rails can automatically mix in different behaviours to your tests + # based on their file location, for example enabling you to call `get` and + # `post` in specs under `spec/controllers`. + # + # You can disable this behaviour by removing the line below, and instead + # explicitly tag your specs with their type, e.g.: + # + # RSpec.describe UsersController, :type => :controller do + # # ... + # end + # + # The different available types are documented in the features, such as in + # https://relishapp.com/rspec/rspec-rails/docs + config.infer_spec_type_from_file_location! + + # Filter lines from Rails gems in backtraces. + config.filter_rails_from_backtrace! + # arbitrary gems may also be filtered via: + # config.filter_gems_from_backtrace("gem name") +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 50f54eb442..61e27385c3 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,92 +1,92 @@ -# # This file was generated by the `rails generate rspec:install` command. Conventionally, all -# # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. -# # The generated `.rspec` file contains `--require spec_helper` which will cause -# # this file to always be loaded, without a need to explicitly require it in any -# # files. -# # -# # Given that it is always loaded, you are encouraged to keep this file as -# # light-weight as possible. Requiring heavyweight dependencies from this file -# # will add to the boot time of your test suite on EVERY test run, even for an -# # individual file that may not need all of that loaded. Instead, consider making -# # a separate helper file that requires the additional dependencies and performs -# # the additional setup, and require it from the spec files that actually need -# # it. -# # -# # The `.rspec` file also contains a few flags that are not defaults but that -# # users commonly want. -# # -# # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration -# RSpec.configure do |config| -# # rspec-expectations config goes here. You can use an alternate -# # assertion/expectation library such as wrong or the stdlib/minitest -# # assertions if you prefer. -# config.expect_with :rspec do |expectations| -# # This option will default to `true` in RSpec 4. It makes the `description` -# # and `failure_message` of custom matchers include text for helper methods -# # defined using `chain`, e.g.: -# # be_bigger_than(2).and_smaller_than(4).description -# # # => "be bigger than 2 and smaller than 4" -# # ...rather than: -# # # => "be bigger than 2" -# expectations.include_chain_clauses_in_custom_matcher_descriptions = true -# end +# This file was generated by the `rails generate rspec:install` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. # -# # rspec-mocks config goes here. You can use an alternate test double -# # library (such as bogus or mocha) by changing the `mock_with` option here. -# config.mock_with :rspec do |mocks| -# # Prevents you from mocking or stubbing a method that does not exist on -# # a real object. This is generally recommended, and will default to -# # `true` in RSpec 4. -# mocks.verify_partial_doubles = true -# end +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. # -# # The settings below are suggested to provide a good initial experience -# # with RSpec, but feel free to customize to your heart's content. -# =begin -# # These two settings work together to allow you to limit a spec run -# # to individual examples or groups you care about by tagging them with -# # `:focus` metadata. When nothing is tagged with `:focus`, all examples -# # get run. -# config.filter_run :focus -# config.run_all_when_everything_filtered = true +# The `.rspec` file also contains a few flags that are not defaults but that +# users commonly want. # -# # Allows RSpec to persist some state between runs in order to support -# # the `--only-failures` and `--next-failure` CLI options. We recommend -# # you configure your source control system to ignore this file. -# config.example_status_persistence_file_path = "spec/examples.txt" -# -# # Limits the available syntax to the non-monkey patched syntax that is -# # recommended. For more details, see: -# # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ -# # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ -# # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode -# config.disable_monkey_patching! -# -# # Many RSpec users commonly either run the entire suite or an individual -# # file, and it's useful to allow more verbose output when running an -# # individual spec file. -# if config.files_to_run.one? -# # Use the documentation formatter for detailed output, -# # unless a formatter has already been configured -# # (e.g. via a command-line flag). -# config.default_formatter = 'doc' -# end -# -# # Print the 10 slowest examples and example groups at the -# # end of the spec run, to help surface which specs are running -# # particularly slow. -# config.profile_examples = 10 -# -# # Run specs in random order to surface order dependencies. If you find an -# # order dependency and want to debug it, you can fix the order by providing -# # the seed, which is printed after each run. -# # --seed 1234 -# config.order = :random -# -# # Seed global randomization in this process using the `--seed` CLI option. -# # Setting this allows you to use `--seed` to deterministically reproduce -# # test failures related to randomization by passing the same `--seed` value -# # as the one that triggered the failure. -# Kernel.srand config.seed -# =end -# end +# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + +# The settings below are suggested to provide a good initial experience +# with RSpec, but feel free to customize to your heart's content. +=begin + # These two settings work together to allow you to limit a spec run + # to individual examples or groups you care about by tagging them with + # `:focus` metadata. When nothing is tagged with `:focus`, all examples + # get run. + config.filter_run :focus + config.run_all_when_everything_filtered = true + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + config.example_status_persistence_file_path = "spec/examples.txt" + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ + # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode + config.disable_monkey_patching! + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = 'doc' + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed +=end +end diff --git a/spec/views/categories/edit.html.erb_spec.rb b/spec/views/categories/edit.html.erb_spec.rb index 6e6f92c6c7..e22444976a 100644 --- a/spec/views/categories/edit.html.erb_spec.rb +++ b/spec/views/categories/edit.html.erb_spec.rb @@ -1,18 +1,18 @@ -require 'rails_helper' - -RSpec.describe "categories/edit", type: :view do - before(:each) do - @category = assign(:category, Category.create!( - :name => "MyString" - )) - 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]" - end - end -end +# require 'rails_helper' +# +# RSpec.describe "categories/edit", type: :view do +# before(:each) do +# @category = assign(:category, Category.create!( +# :name => "MyString" +# )) +# 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]" +# end +# end +# end diff --git a/spec/views/categories/index.html.erb_spec.rb b/spec/views/categories/index.html.erb_spec.rb index 7131ca8e1e..2f93dc39a8 100644 --- a/spec/views/categories/index.html.erb_spec.rb +++ b/spec/views/categories/index.html.erb_spec.rb @@ -1,19 +1,19 @@ -require 'rails_helper' - -RSpec.describe "categories/index", type: :view do - before(:each) do - assign(:categories, [ - Category.create!( - :name => "Name" - ), - Category.create!( - :name => "Name" - ) - ]) - end - - it "renders a list of categories" do - render - assert_select "tr>td", :text => "Name".to_s, :count => 2 - end -end +# require 'rails_helper' +# +# RSpec.describe "categories/index", type: :view do +# before(:each) do +# assign(:categories, [ +# Category.create!( +# :name => "Name" +# ), +# Category.create!( +# :name => "Name" +# ) +# ]) +# end +# +# it "renders a list of categories" do +# render +# assert_select "tr>td", :text => "Name".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 index b3aa22d739..dc7e093c8c 100644 --- a/spec/views/categories/new.html.erb_spec.rb +++ b/spec/views/categories/new.html.erb_spec.rb @@ -1,18 +1,18 @@ -require 'rails_helper' - -RSpec.describe "categories/new", type: :view do - before(:each) do - assign(:category, Category.new( - :name => "MyString" - )) - 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]" - end - end -end +# require 'rails_helper' +# +# RSpec.describe "categories/new", type: :view do +# before(:each) do +# assign(:category, Category.new( +# :name => "MyString" +# )) +# 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]" +# end +# end +# end diff --git a/spec/views/categories/show.html.erb_spec.rb b/spec/views/categories/show.html.erb_spec.rb index 7c95100ffa..be2ce124f8 100644 --- a/spec/views/categories/show.html.erb_spec.rb +++ b/spec/views/categories/show.html.erb_spec.rb @@ -1,14 +1,14 @@ -require 'rails_helper' - -RSpec.describe "categories/show", type: :view do - before(:each) do - @category = assign(:category, Category.create!( - :name => "Name" - )) - end - - it "renders attributes in

" do - render - expect(rendered).to match(/Name/) - end -end +# require 'rails_helper' +# +# RSpec.describe "categories/show", type: :view do +# before(:each) do +# @category = assign(:category, Category.create!( +# :name => "Name" +# )) +# end +# +# it "renders attributes in

" do +# render +# expect(rendered).to match(/Name/) +# end +# end diff --git a/spec/views/order_items/edit.html.erb_spec.rb b/spec/views/order_items/edit.html.erb_spec.rb index 6ec53a1ccb..23d8b3c661 100644 --- a/spec/views/order_items/edit.html.erb_spec.rb +++ b/spec/views/order_items/edit.html.erb_spec.rb @@ -1,24 +1,24 @@ -require 'rails_helper' - -RSpec.describe "order_items/edit", type: :view do - before(:each) do - @order_item = assign(:order_item, OrderItem.create!( - :product_id => 1, - :order_id => 1, - :quantity => 1 - )) - end - - it "renders the edit order_item form" do - render - - assert_select "form[action=?][method=?]", order_item_path(@order_item), "post" do - - assert_select "input#order_item_product_id[name=?]", "order_item[product_id]" - - assert_select "input#order_item_order_id[name=?]", "order_item[order_id]" - - assert_select "input#order_item_quantity[name=?]", "order_item[quantity]" - end - end -end +# require 'rails_helper' +# +# RSpec.describe "order_items/edit", type: :view do +# before(:each) do +# @order_item = assign(:order_item, OrderItem.create!( +# :product_id => 1, +# :order_id => 1, +# :quantity => 1 +# )) +# end +# +# it "renders the edit order_item form" do +# render +# +# assert_select "form[action=?][method=?]", order_item_path(@order_item), "post" do +# +# assert_select "input#order_item_product_id[name=?]", "order_item[product_id]" +# +# assert_select "input#order_item_order_id[name=?]", "order_item[order_id]" +# +# assert_select "input#order_item_quantity[name=?]", "order_item[quantity]" +# end +# end +# end diff --git a/spec/views/order_items/index.html.erb_spec.rb b/spec/views/order_items/index.html.erb_spec.rb index 16fc3caf0a..832ebc12cb 100644 --- a/spec/views/order_items/index.html.erb_spec.rb +++ b/spec/views/order_items/index.html.erb_spec.rb @@ -1,25 +1,25 @@ -require 'rails_helper' - -RSpec.describe "order_items/index", type: :view do - before(:each) do - assign(:order_items, [ - OrderItem.create!( - :product_id => 1, - :order_id => 2, - :quantity => 3 - ), - OrderItem.create!( - :product_id => 1, - :order_id => 2, - :quantity => 3 - ) - ]) - end - - it "renders a list of order_items" do - render - assert_select "tr>td", :text => 1.to_s, :count => 2 - assert_select "tr>td", :text => 2.to_s, :count => 2 - assert_select "tr>td", :text => 3.to_s, :count => 2 - end -end +# require 'rails_helper' +# +# RSpec.describe "order_items/index", type: :view do +# before(:each) do +# assign(:order_items, [ +# OrderItem.create!( +# :product_id => 1, +# :order_id => 2, +# :quantity => 3 +# ), +# OrderItem.create!( +# :product_id => 1, +# :order_id => 2, +# :quantity => 3 +# ) +# ]) +# end +# +# it "renders a list of order_items" do +# render +# assert_select "tr>td", :text => 1.to_s, :count => 2 +# assert_select "tr>td", :text => 2.to_s, :count => 2 +# assert_select "tr>td", :text => 3.to_s, :count => 2 +# end +# end diff --git a/spec/views/order_items/new.html.erb_spec.rb b/spec/views/order_items/new.html.erb_spec.rb index 01edddf94d..2e42fda02b 100644 --- a/spec/views/order_items/new.html.erb_spec.rb +++ b/spec/views/order_items/new.html.erb_spec.rb @@ -1,24 +1,24 @@ -require 'rails_helper' - -RSpec.describe "order_items/new", type: :view do - before(:each) do - assign(:order_item, OrderItem.new( - :product_id => 1, - :order_id => 1, - :quantity => 1 - )) - end - - it "renders new order_item form" do - render - - assert_select "form[action=?][method=?]", order_items_path, "post" do - - assert_select "input#order_item_product_id[name=?]", "order_item[product_id]" - - assert_select "input#order_item_order_id[name=?]", "order_item[order_id]" - - assert_select "input#order_item_quantity[name=?]", "order_item[quantity]" - end - end -end +# require 'rails_helper' +# +# RSpec.describe "order_items/new", type: :view do +# before(:each) do +# assign(:order_item, OrderItem.new( +# :product_id => 1, +# :order_id => 1, +# :quantity => 1 +# )) +# end +# +# it "renders new order_item form" do +# render +# +# assert_select "form[action=?][method=?]", order_items_path, "post" do +# +# assert_select "input#order_item_product_id[name=?]", "order_item[product_id]" +# +# assert_select "input#order_item_order_id[name=?]", "order_item[order_id]" +# +# assert_select "input#order_item_quantity[name=?]", "order_item[quantity]" +# end +# end +# end diff --git a/spec/views/order_items/show.html.erb_spec.rb b/spec/views/order_items/show.html.erb_spec.rb index 3a637b0a0d..18cf372bc6 100644 --- a/spec/views/order_items/show.html.erb_spec.rb +++ b/spec/views/order_items/show.html.erb_spec.rb @@ -1,18 +1,18 @@ -require 'rails_helper' - -RSpec.describe "order_items/show", type: :view do - before(:each) do - @order_item = assign(:order_item, OrderItem.create!( - :product_id => 1, - :order_id => 2, - :quantity => 3 - )) - end - - it "renders attributes in

" do - render - expect(rendered).to match(/1/) - expect(rendered).to match(/2/) - expect(rendered).to match(/3/) - end -end +# require 'rails_helper' +# +# RSpec.describe "order_items/show", type: :view do +# before(:each) do +# @order_item = assign(:order_item, OrderItem.create!( +# :product_id => 1, +# :order_id => 2, +# :quantity => 3 +# )) +# end +# +# it "renders attributes in

" do +# render +# expect(rendered).to match(/1/) +# expect(rendered).to match(/2/) +# expect(rendered).to match(/3/) +# end +# end diff --git a/spec/views/orders/edit.html.erb_spec.rb b/spec/views/orders/edit.html.erb_spec.rb index 00a9bd18a5..055bac9c3b 100644 --- a/spec/views/orders/edit.html.erb_spec.rb +++ b/spec/views/orders/edit.html.erb_spec.rb @@ -1,39 +1,39 @@ -require 'rails_helper' - -RSpec.describe "orders/edit", type: :view do - before(:each) do - @order = assign(:order, Order.create!( - :email => "MyString", - :street => "MyString", - :city => "MyString", - :state => "MyString", - :zip => "MyString", - :cc_num => "MyString", - :cc_cvv => 1, - :cc_name => "MyString" - )) - end - - it "renders the edit order form" do - render - - assert_select "form[action=?][method=?]", order_path(@order), "post" do - - assert_select "input#order_email[name=?]", "order[email]" - - assert_select "input#order_street[name=?]", "order[street]" - - assert_select "input#order_city[name=?]", "order[city]" - - assert_select "input#order_state[name=?]", "order[state]" - - assert_select "input#order_zip[name=?]", "order[zip]" - - assert_select "input#order_cc_num[name=?]", "order[cc_num]" - - assert_select "input#order_cc_cvv[name=?]", "order[cc_cvv]" - - assert_select "input#order_cc_name[name=?]", "order[cc_name]" - end - end -end +# require 'rails_helper' +# +# RSpec.describe "orders/edit", type: :view do +# before(:each) do +# @order = assign(:order, Order.create!( +# :email => "MyString", +# :street => "MyString", +# :city => "MyString", +# :state => "MyString", +# :zip => "MyString", +# :cc_num => "MyString", +# :cc_cvv => 1, +# :cc_name => "MyString" +# )) +# end +# +# it "renders the edit order form" do +# render +# +# assert_select "form[action=?][method=?]", order_path(@order), "post" do +# +# assert_select "input#order_email[name=?]", "order[email]" +# +# assert_select "input#order_street[name=?]", "order[street]" +# +# assert_select "input#order_city[name=?]", "order[city]" +# +# assert_select "input#order_state[name=?]", "order[state]" +# +# assert_select "input#order_zip[name=?]", "order[zip]" +# +# assert_select "input#order_cc_num[name=?]", "order[cc_num]" +# +# assert_select "input#order_cc_cvv[name=?]", "order[cc_cvv]" +# +# assert_select "input#order_cc_name[name=?]", "order[cc_name]" +# end +# end +# end diff --git a/spec/views/orders/index.html.erb_spec.rb b/spec/views/orders/index.html.erb_spec.rb index a38f782137..86595e5009 100644 --- a/spec/views/orders/index.html.erb_spec.rb +++ b/spec/views/orders/index.html.erb_spec.rb @@ -1,40 +1,40 @@ -require 'rails_helper' - -RSpec.describe "orders/index", type: :view do - before(:each) do - assign(:orders, [ - Order.create!( - :email => "Email", - :street => "Street", - :city => "City", - :state => "State", - :zip => "Zip", - :cc_num => "Cc Num", - :cc_cvv => 1, - :cc_name => "Cc Name" - ), - Order.create!( - :email => "Email", - :street => "Street", - :city => "City", - :state => "State", - :zip => "Zip", - :cc_num => "Cc Num", - :cc_cvv => 1, - :cc_name => "Cc Name" - ) - ]) - end - - it "renders a list of orders" do - render - assert_select "tr>td", :text => "Email".to_s, :count => 2 - assert_select "tr>td", :text => "Street".to_s, :count => 2 - assert_select "tr>td", :text => "City".to_s, :count => 2 - assert_select "tr>td", :text => "State".to_s, :count => 2 - assert_select "tr>td", :text => "Zip".to_s, :count => 2 - assert_select "tr>td", :text => "Cc Num".to_s, :count => 2 - assert_select "tr>td", :text => 1.to_s, :count => 2 - assert_select "tr>td", :text => "Cc Name".to_s, :count => 2 - end -end +# require 'rails_helper' +# +# RSpec.describe "orders/index", type: :view do +# before(:each) do +# assign(:orders, [ +# Order.create!( +# :email => "Email", +# :street => "Street", +# :city => "City", +# :state => "State", +# :zip => "Zip", +# :cc_num => "Cc Num", +# :cc_cvv => 1, +# :cc_name => "Cc Name" +# ), +# Order.create!( +# :email => "Email", +# :street => "Street", +# :city => "City", +# :state => "State", +# :zip => "Zip", +# :cc_num => "Cc Num", +# :cc_cvv => 1, +# :cc_name => "Cc Name" +# ) +# ]) +# end +# +# it "renders a list of orders" do +# render +# assert_select "tr>td", :text => "Email".to_s, :count => 2 +# assert_select "tr>td", :text => "Street".to_s, :count => 2 +# assert_select "tr>td", :text => "City".to_s, :count => 2 +# assert_select "tr>td", :text => "State".to_s, :count => 2 +# assert_select "tr>td", :text => "Zip".to_s, :count => 2 +# assert_select "tr>td", :text => "Cc Num".to_s, :count => 2 +# assert_select "tr>td", :text => 1.to_s, :count => 2 +# assert_select "tr>td", :text => "Cc Name".to_s, :count => 2 +# end +# end diff --git a/spec/views/orders/new.html.erb_spec.rb b/spec/views/orders/new.html.erb_spec.rb index 2b1083d95b..81b76271f1 100644 --- a/spec/views/orders/new.html.erb_spec.rb +++ b/spec/views/orders/new.html.erb_spec.rb @@ -1,39 +1,39 @@ -require 'rails_helper' - -RSpec.describe "orders/new", type: :view do - before(:each) do - assign(:order, Order.new( - :email => "MyString", - :street => "MyString", - :city => "MyString", - :state => "MyString", - :zip => "MyString", - :cc_num => "MyString", - :cc_cvv => 1, - :cc_name => "MyString" - )) - end - - it "renders new order form" do - render - - assert_select "form[action=?][method=?]", orders_path, "post" do - - assert_select "input#order_email[name=?]", "order[email]" - - assert_select "input#order_street[name=?]", "order[street]" - - assert_select "input#order_city[name=?]", "order[city]" - - assert_select "input#order_state[name=?]", "order[state]" - - assert_select "input#order_zip[name=?]", "order[zip]" - - assert_select "input#order_cc_num[name=?]", "order[cc_num]" - - assert_select "input#order_cc_cvv[name=?]", "order[cc_cvv]" - - assert_select "input#order_cc_name[name=?]", "order[cc_name]" - end - end -end +# require 'rails_helper' +# +# RSpec.describe "orders/new", type: :view do +# before(:each) do +# assign(:order, Order.new( +# :email => "MyString", +# :street => "MyString", +# :city => "MyString", +# :state => "MyString", +# :zip => "MyString", +# :cc_num => "MyString", +# :cc_cvv => 1, +# :cc_name => "MyString" +# )) +# end +# +# it "renders new order form" do +# render +# +# assert_select "form[action=?][method=?]", orders_path, "post" do +# +# assert_select "input#order_email[name=?]", "order[email]" +# +# assert_select "input#order_street[name=?]", "order[street]" +# +# assert_select "input#order_city[name=?]", "order[city]" +# +# assert_select "input#order_state[name=?]", "order[state]" +# +# assert_select "input#order_zip[name=?]", "order[zip]" +# +# assert_select "input#order_cc_num[name=?]", "order[cc_num]" +# +# assert_select "input#order_cc_cvv[name=?]", "order[cc_cvv]" +# +# assert_select "input#order_cc_name[name=?]", "order[cc_name]" +# end +# end +# end diff --git a/spec/views/orders/show.html.erb_spec.rb b/spec/views/orders/show.html.erb_spec.rb index 34affa4524..ce61e0d132 100644 --- a/spec/views/orders/show.html.erb_spec.rb +++ b/spec/views/orders/show.html.erb_spec.rb @@ -1,28 +1,28 @@ -require 'rails_helper' - -RSpec.describe "orders/show", type: :view do - before(:each) do - @order = assign(:order, Order.create!( - :email => "Email", - :street => "Street", - :city => "City", - :state => "State", - :zip => "Zip", - :cc_num => "Cc Num", - :cc_cvv => 1, - :cc_name => "Cc Name" - )) - end - - it "renders attributes in

" do - render - expect(rendered).to match(/Email/) - expect(rendered).to match(/Street/) - expect(rendered).to match(/City/) - expect(rendered).to match(/State/) - expect(rendered).to match(/Zip/) - expect(rendered).to match(/Cc Num/) - expect(rendered).to match(/1/) - expect(rendered).to match(/Cc Name/) - end -end +# require 'rails_helper' +# +# RSpec.describe "orders/show", type: :view do +# before(:each) do +# @order = assign(:order, Order.create!( +# :email => "Email", +# :street => "Street", +# :city => "City", +# :state => "State", +# :zip => "Zip", +# :cc_num => "Cc Num", +# :cc_cvv => 1, +# :cc_name => "Cc Name" +# )) +# end +# +# it "renders attributes in

" do +# render +# expect(rendered).to match(/Email/) +# expect(rendered).to match(/Street/) +# expect(rendered).to match(/City/) +# expect(rendered).to match(/State/) +# expect(rendered).to match(/Zip/) +# expect(rendered).to match(/Cc Num/) +# expect(rendered).to match(/1/) +# expect(rendered).to match(/Cc Name/) +# end +# end diff --git a/spec/views/products/edit.html.erb_spec.rb b/spec/views/products/edit.html.erb_spec.rb index 3625755533..f67c51720c 100644 --- a/spec/views/products/edit.html.erb_spec.rb +++ b/spec/views/products/edit.html.erb_spec.rb @@ -1,36 +1,36 @@ -require 'rails_helper' - -RSpec.describe "products/edit", type: :view do - before(:each) do - @product = assign(:product, Product.create!( - :name => "MyString", - :price => 1, - :user_id => 1, - :photo_url => "MyString", - :stock => 1, - :description => "MyString", - :active => false - )) - end - - it "renders the edit product form" do - render - - assert_select "form[action=?][method=?]", product_path(@product), "post" do - - assert_select "input#product_name[name=?]", "product[name]" - - assert_select "input#product_price[name=?]", "product[price]" - - assert_select "input#product_user_id[name=?]", "product[user_id]" - - assert_select "input#product_photo_url[name=?]", "product[photo_url]" - - assert_select "input#product_stock[name=?]", "product[stock]" - - assert_select "input#product_description[name=?]", "product[description]" - - assert_select "input#product_active[name=?]", "product[active]" - end - end -end +# require 'rails_helper' +# +# RSpec.describe "products/edit", type: :view do +# before(:each) do +# @product = assign(:product, Product.create!( +# :name => "MyString", +# :price => 1, +# :user_id => 1, +# :photo_url => "MyString", +# :stock => 1, +# :description => "MyString", +# :active => false +# )) +# end +# +# it "renders the edit product form" do +# render +# +# assert_select "form[action=?][method=?]", product_path(@product), "post" do +# +# assert_select "input#product_name[name=?]", "product[name]" +# +# assert_select "input#product_price[name=?]", "product[price]" +# +# assert_select "input#product_user_id[name=?]", "product[user_id]" +# +# assert_select "input#product_photo_url[name=?]", "product[photo_url]" +# +# assert_select "input#product_stock[name=?]", "product[stock]" +# +# assert_select "input#product_description[name=?]", "product[description]" +# +# assert_select "input#product_active[name=?]", "product[active]" +# end +# end +# end diff --git a/spec/views/products/index.html.erb_spec.rb b/spec/views/products/index.html.erb_spec.rb index a44be22ba6..6ed2bd9908 100644 --- a/spec/views/products/index.html.erb_spec.rb +++ b/spec/views/products/index.html.erb_spec.rb @@ -1,37 +1,37 @@ -require 'rails_helper' - -RSpec.describe "products/index", type: :view do - before(:each) do - assign(:products, [ - Product.create!( - :name => "Name", - :price => 1, - :user_id => 2, - :photo_url => "Photo Url", - :stock => 3, - :description => "Description", - :active => false - ), - Product.create!( - :name => "Name", - :price => 1, - :user_id => 2, - :photo_url => "Photo Url", - :stock => 3, - :description => "Description", - :active => false - ) - ]) - end - - it "renders a list of products" do - render - assert_select "tr>td", :text => "Name".to_s, :count => 2 - assert_select "tr>td", :text => 1.to_s, :count => 2 - assert_select "tr>td", :text => 2.to_s, :count => 2 - assert_select "tr>td", :text => "Photo Url".to_s, :count => 2 - assert_select "tr>td", :text => 3.to_s, :count => 2 - assert_select "tr>td", :text => "Description".to_s, :count => 2 - assert_select "tr>td", :text => false.to_s, :count => 2 - end -end +# require 'rails_helper' +# +# RSpec.describe "products/index", type: :view do +# before(:each) do +# assign(:products, [ +# Product.create!( +# :name => "Name", +# :price => 1, +# :user_id => 2, +# :photo_url => "Photo Url", +# :stock => 3, +# :description => "Description", +# :active => false +# ), +# Product.create!( +# :name => "Name", +# :price => 1, +# :user_id => 2, +# :photo_url => "Photo Url", +# :stock => 3, +# :description => "Description", +# :active => false +# ) +# ]) +# end +# +# it "renders a list of products" do +# render +# assert_select "tr>td", :text => "Name".to_s, :count => 2 +# assert_select "tr>td", :text => 1.to_s, :count => 2 +# assert_select "tr>td", :text => 2.to_s, :count => 2 +# assert_select "tr>td", :text => "Photo Url".to_s, :count => 2 +# assert_select "tr>td", :text => 3.to_s, :count => 2 +# assert_select "tr>td", :text => "Description".to_s, :count => 2 +# assert_select "tr>td", :text => false.to_s, :count => 2 +# end +# end diff --git a/spec/views/products/new.html.erb_spec.rb b/spec/views/products/new.html.erb_spec.rb index 93f6984b91..3d008881c8 100644 --- a/spec/views/products/new.html.erb_spec.rb +++ b/spec/views/products/new.html.erb_spec.rb @@ -1,36 +1,36 @@ -require 'rails_helper' - -RSpec.describe "products/new", type: :view do - before(:each) do - assign(:product, Product.new( - :name => "MyString", - :price => 1, - :user_id => 1, - :photo_url => "MyString", - :stock => 1, - :description => "MyString", - :active => false - )) - end - - it "renders new product form" do - render - - assert_select "form[action=?][method=?]", products_path, "post" do - - assert_select "input#product_name[name=?]", "product[name]" - - assert_select "input#product_price[name=?]", "product[price]" - - assert_select "input#product_user_id[name=?]", "product[user_id]" - - assert_select "input#product_photo_url[name=?]", "product[photo_url]" - - assert_select "input#product_stock[name=?]", "product[stock]" - - assert_select "input#product_description[name=?]", "product[description]" - - assert_select "input#product_active[name=?]", "product[active]" - end - end -end +# require 'rails_helper' +# +# RSpec.describe "products/new", type: :view do +# before(:each) do +# assign(:product, Product.new( +# :name => "MyString", +# :price => 1, +# :user_id => 1, +# :photo_url => "MyString", +# :stock => 1, +# :description => "MyString", +# :active => false +# )) +# end +# +# it "renders new product form" do +# render +# +# assert_select "form[action=?][method=?]", products_path, "post" do +# +# assert_select "input#product_name[name=?]", "product[name]" +# +# assert_select "input#product_price[name=?]", "product[price]" +# +# assert_select "input#product_user_id[name=?]", "product[user_id]" +# +# assert_select "input#product_photo_url[name=?]", "product[photo_url]" +# +# assert_select "input#product_stock[name=?]", "product[stock]" +# +# assert_select "input#product_description[name=?]", "product[description]" +# +# assert_select "input#product_active[name=?]", "product[active]" +# end +# end +# end diff --git a/spec/views/products/show.html.erb_spec.rb b/spec/views/products/show.html.erb_spec.rb index 99469c9e23..0bdc6b621c 100644 --- a/spec/views/products/show.html.erb_spec.rb +++ b/spec/views/products/show.html.erb_spec.rb @@ -1,26 +1,26 @@ -require 'rails_helper' - -RSpec.describe "products/show", type: :view do - before(:each) do - @product = assign(:product, Product.create!( - :name => "Name", - :price => 1, - :user_id => 2, - :photo_url => "Photo Url", - :stock => 3, - :description => "Description", - :active => false - )) - end - - it "renders attributes in

" do - render - expect(rendered).to match(/Name/) - expect(rendered).to match(/1/) - expect(rendered).to match(/2/) - expect(rendered).to match(/Photo Url/) - expect(rendered).to match(/3/) - expect(rendered).to match(/Description/) - expect(rendered).to match(/false/) - end -end +# require 'rails_helper' +# +# RSpec.describe "products/show", type: :view do +# before(:each) do +# @product = assign(:product, Product.create!( +# :name => "Name", +# :price => 1, +# :user_id => 2, +# :photo_url => "Photo Url", +# :stock => 3, +# :description => "Description", +# :active => false +# )) +# end +# +# it "renders attributes in

" do +# render +# expect(rendered).to match(/Name/) +# expect(rendered).to match(/1/) +# expect(rendered).to match(/2/) +# expect(rendered).to match(/Photo Url/) +# expect(rendered).to match(/3/) +# expect(rendered).to match(/Description/) +# expect(rendered).to match(/false/) +# end +# end diff --git a/spec/views/reviews/edit.html.erb_spec.rb b/spec/views/reviews/edit.html.erb_spec.rb index 06339bace4..0abc10f550 100644 --- a/spec/views/reviews/edit.html.erb_spec.rb +++ b/spec/views/reviews/edit.html.erb_spec.rb @@ -1,24 +1,24 @@ -require 'rails_helper' - -RSpec.describe "reviews/edit", type: :view do - before(:each) do - @review = assign(:review, Review.create!( - :rating => 1, - :product_id => 1, - :description => "MyString" - )) - end - - it "renders the edit review form" do - render - - assert_select "form[action=?][method=?]", review_path(@review), "post" do - - assert_select "input#review_rating[name=?]", "review[rating]" - - assert_select "input#review_product_id[name=?]", "review[product_id]" - - assert_select "input#review_description[name=?]", "review[description]" - end - end -end +# require 'rails_helper' +# +# RSpec.describe "reviews/edit", type: :view do +# before(:each) do +# @review = assign(:review, Review.create!( +# :rating => 1, +# :product_id => 1, +# :description => "MyString" +# )) +# end +# +# it "renders the edit review form" do +# render +# +# assert_select "form[action=?][method=?]", review_path(@review), "post" do +# +# assert_select "input#review_rating[name=?]", "review[rating]" +# +# assert_select "input#review_product_id[name=?]", "review[product_id]" +# +# assert_select "input#review_description[name=?]", "review[description]" +# end +# end +# end diff --git a/spec/views/reviews/index.html.erb_spec.rb b/spec/views/reviews/index.html.erb_spec.rb index df5100e8fb..9fbd1326b3 100644 --- a/spec/views/reviews/index.html.erb_spec.rb +++ b/spec/views/reviews/index.html.erb_spec.rb @@ -1,25 +1,25 @@ -require 'rails_helper' - -RSpec.describe "reviews/index", type: :view do - before(:each) do - assign(:reviews, [ - Review.create!( - :rating => 1, - :product_id => 2, - :description => "Description" - ), - Review.create!( - :rating => 1, - :product_id => 2, - :description => "Description" - ) - ]) - end - - it "renders a list of reviews" do - render - assert_select "tr>td", :text => 1.to_s, :count => 2 - assert_select "tr>td", :text => 2.to_s, :count => 2 - assert_select "tr>td", :text => "Description".to_s, :count => 2 - end -end +# require 'rails_helper' +# +# RSpec.describe "reviews/index", type: :view do +# before(:each) do +# assign(:reviews, [ +# Review.create!( +# :rating => 1, +# :product_id => 2, +# :description => "Description" +# ), +# Review.create!( +# :rating => 1, +# :product_id => 2, +# :description => "Description" +# ) +# ]) +# end +# +# it "renders a list of reviews" do +# render +# assert_select "tr>td", :text => 1.to_s, :count => 2 +# assert_select "tr>td", :text => 2.to_s, :count => 2 +# assert_select "tr>td", :text => "Description".to_s, :count => 2 +# end +# end diff --git a/spec/views/reviews/new.html.erb_spec.rb b/spec/views/reviews/new.html.erb_spec.rb index b813c6abfe..6f33143cb8 100644 --- a/spec/views/reviews/new.html.erb_spec.rb +++ b/spec/views/reviews/new.html.erb_spec.rb @@ -1,24 +1,24 @@ -require 'rails_helper' - -RSpec.describe "reviews/new", type: :view do - before(:each) do - assign(:review, Review.new( - :rating => 1, - :product_id => 1, - :description => "MyString" - )) - end - - it "renders new review form" do - render - - assert_select "form[action=?][method=?]", reviews_path, "post" do - - assert_select "input#review_rating[name=?]", "review[rating]" - - assert_select "input#review_product_id[name=?]", "review[product_id]" - - assert_select "input#review_description[name=?]", "review[description]" - end - end -end +# require 'rails_helper' +# +# RSpec.describe "reviews/new", type: :view do +# before(:each) do +# assign(:review, Review.new( +# :rating => 1, +# :product_id => 1, +# :description => "MyString" +# )) +# end +# +# it "renders new review form" do +# render +# +# assert_select "form[action=?][method=?]", reviews_path, "post" do +# +# assert_select "input#review_rating[name=?]", "review[rating]" +# +# assert_select "input#review_product_id[name=?]", "review[product_id]" +# +# assert_select "input#review_description[name=?]", "review[description]" +# end +# end +# end diff --git a/spec/views/reviews/show.html.erb_spec.rb b/spec/views/reviews/show.html.erb_spec.rb index ac833ca8cd..ab2daa65f3 100644 --- a/spec/views/reviews/show.html.erb_spec.rb +++ b/spec/views/reviews/show.html.erb_spec.rb @@ -1,18 +1,18 @@ -require 'rails_helper' - -RSpec.describe "reviews/show", type: :view do - before(:each) do - @review = assign(:review, Review.create!( - :rating => 1, - :product_id => 2, - :description => "Description" - )) - end - - it "renders attributes in

" do - render - expect(rendered).to match(/1/) - expect(rendered).to match(/2/) - expect(rendered).to match(/Description/) - end -end +# require 'rails_helper' +# +# RSpec.describe "reviews/show", type: :view do +# before(:each) do +# @review = assign(:review, Review.create!( +# :rating => 1, +# :product_id => 2, +# :description => "Description" +# )) +# end +# +# it "renders attributes in

" do +# render +# expect(rendered).to match(/1/) +# expect(rendered).to match(/2/) +# expect(rendered).to match(/Description/) +# end +# end diff --git a/spec/views/users/edit.html.erb_spec.rb b/spec/views/users/edit.html.erb_spec.rb index 396075b332..cee8634427 100644 --- a/spec/views/users/edit.html.erb_spec.rb +++ b/spec/views/users/edit.html.erb_spec.rb @@ -1,27 +1,27 @@ -require 'rails_helper' - -RSpec.describe "users/edit", type: :view do - before(:each) do - @user = assign(:user, User.create!( - :username => "MyString", - :email => "MyString", - :password_digest => "MyString", - :name => "MyString" - )) - end - - it "renders the edit user form" do - render - - assert_select "form[action=?][method=?]", user_path(@user), "post" do - - assert_select "input#user_username[name=?]", "user[username]" - - assert_select "input#user_email[name=?]", "user[email]" - - assert_select "input#user_password_digest[name=?]", "user[password_digest]" - - assert_select "input#user_name[name=?]", "user[name]" - end - end -end +# require 'rails_helper' +# +# RSpec.describe "users/edit", type: :view do +# before(:each) do +# @user = assign(:user, User.create!( +# :username => "MyString", +# :email => "MyString", +# :password_digest => "MyString", +# :name => "MyString" +# )) +# end +# +# it "renders the edit user form" do +# render +# +# assert_select "form[action=?][method=?]", user_path(@user), "post" do +# +# assert_select "input#user_username[name=?]", "user[username]" +# +# assert_select "input#user_email[name=?]", "user[email]" +# +# assert_select "input#user_password_digest[name=?]", "user[password_digest]" +# +# assert_select "input#user_name[name=?]", "user[name]" +# end +# end +# end diff --git a/spec/views/users/index.html.erb_spec.rb b/spec/views/users/index.html.erb_spec.rb index 4fdbc1b545..865824f7db 100644 --- a/spec/views/users/index.html.erb_spec.rb +++ b/spec/views/users/index.html.erb_spec.rb @@ -1,28 +1,28 @@ -require 'rails_helper' - -RSpec.describe "users/index", type: :view do - before(:each) do - assign(:users, [ - User.create!( - :username => "Username", - :email => "Email", - :password_digest => "Password Digest", - :name => "Name" - ), - User.create!( - :username => "Username", - :email => "Email", - :password_digest => "Password Digest", - :name => "Name" - ) - ]) - end - - it "renders a list of users" do - render - assert_select "tr>td", :text => "Username".to_s, :count => 2 - assert_select "tr>td", :text => "Email".to_s, :count => 2 - assert_select "tr>td", :text => "Password Digest".to_s, :count => 2 - assert_select "tr>td", :text => "Name".to_s, :count => 2 - end -end +# require 'rails_helper' +# +# RSpec.describe "users/index", type: :view do +# before(:each) do +# assign(:users, [ +# User.create!( +# :username => "Username", +# :email => "Email", +# :password_digest => "Password Digest", +# :name => "Name" +# ), +# User.create!( +# :username => "Username", +# :email => "Email", +# :password_digest => "Password Digest", +# :name => "Name" +# ) +# ]) +# end +# +# it "renders a list of users" do +# render +# assert_select "tr>td", :text => "Username".to_s, :count => 2 +# assert_select "tr>td", :text => "Email".to_s, :count => 2 +# assert_select "tr>td", :text => "Password Digest".to_s, :count => 2 +# assert_select "tr>td", :text => "Name".to_s, :count => 2 +# end +# end diff --git a/spec/views/users/new.html.erb_spec.rb b/spec/views/users/new.html.erb_spec.rb index e60bfed0a1..39a492f595 100644 --- a/spec/views/users/new.html.erb_spec.rb +++ b/spec/views/users/new.html.erb_spec.rb @@ -1,27 +1,27 @@ -require 'rails_helper' - -RSpec.describe "users/new", type: :view do - before(:each) do - assign(:user, User.new( - :username => "MyString", - :email => "MyString", - :password_digest => "MyString", - :name => "MyString" - )) - end - - it "renders new user form" do - render - - assert_select "form[action=?][method=?]", users_path, "post" do - - assert_select "input#user_username[name=?]", "user[username]" - - assert_select "input#user_email[name=?]", "user[email]" - - assert_select "input#user_password_digest[name=?]", "user[password_digest]" - - assert_select "input#user_name[name=?]", "user[name]" - end - end -end +# require 'rails_helper' +# +# RSpec.describe "users/new", type: :view do +# before(:each) do +# assign(:user, User.new( +# :username => "MyString", +# :email => "MyString", +# :password_digest => "MyString", +# :name => "MyString" +# )) +# end +# +# it "renders new user form" do +# render +# +# assert_select "form[action=?][method=?]", users_path, "post" do +# +# assert_select "input#user_username[name=?]", "user[username]" +# +# assert_select "input#user_email[name=?]", "user[email]" +# +# assert_select "input#user_password_digest[name=?]", "user[password_digest]" +# +# assert_select "input#user_name[name=?]", "user[name]" +# end +# end +# end diff --git a/spec/views/users/show.html.erb_spec.rb b/spec/views/users/show.html.erb_spec.rb index d5c9eb6f10..e2aae715be 100644 --- a/spec/views/users/show.html.erb_spec.rb +++ b/spec/views/users/show.html.erb_spec.rb @@ -1,20 +1,20 @@ -require 'rails_helper' - -RSpec.describe "users/show", type: :view do - before(:each) do - @user = assign(:user, User.create!( - :username => "Username", - :email => "Email", - :password_digest => "Password Digest", - :name => "Name" - )) - end - - it "renders attributes in

" do - render - expect(rendered).to match(/Username/) - expect(rendered).to match(/Email/) - expect(rendered).to match(/Password Digest/) - expect(rendered).to match(/Name/) - end -end +# require 'rails_helper' +# +# RSpec.describe "users/show", type: :view do +# before(:each) do +# @user = assign(:user, User.create!( +# :username => "Username", +# :email => "Email", +# :password_digest => "Password Digest", +# :name => "Name" +# )) +# end +# +# it "renders attributes in

" do +# render +# expect(rendered).to match(/Username/) +# expect(rendered).to match(/Email/) +# expect(rendered).to match(/Password Digest/) +# expect(rendered).to match(/Name/) +# end +# end diff --git a/spec/views/welcome/index.html.erb_spec.rb b/spec/views/welcome/index.html.erb_spec.rb index 226835cead..c80a4fc9b3 100644 --- a/spec/views/welcome/index.html.erb_spec.rb +++ b/spec/views/welcome/index.html.erb_spec.rb @@ -1,5 +1,5 @@ -require 'rails_helper' - -RSpec.describe "welcome/index.html.erb", type: :view do - pending "add some examples to (or delete) #{__FILE__}" -end +# require 'rails_helper' +# +# RSpec.describe "welcome/index.html.erb", type: :view do +# pending "add some examples to (or delete) #{__FILE__}" +# end From 5a8e611f043e32819fb8cee403a5bb012d90dc5e Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 10 Dec 2015 14:36:53 -0800 Subject: [PATCH 081/299] fix product image urls --- seeds_csvs/products.csv | 104 ++++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/seeds_csvs/products.csv b/seeds_csvs/products.csv index 1bd78ed782..ebe1b00cb3 100644 --- a/seeds_csvs/products.csv +++ b/seeds_csvs/products.csv @@ -1,56 +1,56 @@ name,price,user_id,photo_url,stock,description -Relieved Dive Rings,599,1,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",12,Unbreakable rings stand up on the pool bottom for diving games. Set of 4. -Heavenly Inflatable Water Wheel,3795,1,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,6,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended." +Relieved Dive Rings,599,1,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",2,Unbreakable rings stand up on the pool bottom for diving games. Set of 4. +Heavenly Inflatable Water Wheel,3795,1,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,12,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended." Two Shark Goggles,1196,1,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,7,Made using the highest quality materials -Curved Swimming Fish Pool Toy,1399,1,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,5, +Curved Swimming Fish Pool Toy,1399,1,http://ecx.images-amazon.com/images/I/71R6EdJ3pVL._SL1001_.jpg,13, Lavish Water Noodles,1143,1,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,7,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random. -Pumped Water Wings,690,1,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,9,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue -Bouncy Dive Rings,599,2,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",4,Unbreakable rings stand up on the pool bottom for diving games. Set of 4. -Steep Dive Sticks,395,2,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,11,Sticks stand upright on pool bottom. -Sore Dory Doll,3000,2,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,13,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll" -Talented Inflatable Water Wheel,3795,2,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,9,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended." -Young Swimming Fish Pool Toy,1399,2,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,9, -Moldy Toypedo Bandits,615,2,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,3,Glides underwater up to 30 feet -Courageous Water Noodles,1143,2,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,7,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random. -Guarded Water Wings,690,2,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,5,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue -Crooked Dive Rings,599,3,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",4,Unbreakable rings stand up on the pool bottom for diving games. Set of 4. -Efficacious Dive Sticks,395,3,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,12,Sticks stand upright on pool bottom. -Wrong Finding Nemo DVD,1996,3,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,6,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination." -Easy Inflatable Water Wheel,3795,3,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,15,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended." -Unwieldy Puddle Jumper Life Jacket,1359,3,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,4,For children 30-50 lbs. -Near Shark Goggles,1196,3,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,10,Made using the highest quality materials -Uppity Swimming Fish Pool Toy,1399,3,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,7, -Black Toypedo Bandits,615,3,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,6,Glides underwater up to 30 feet -Necessary Water Noodles,1143,3,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,5,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random. -Piquant Water Wings,690,3,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,5,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue -Ripe Dive Sticks,395,4,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,5,Sticks stand upright on pool bottom. -Wandering Finding Nemo DVD,1996,4,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,11,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination." -Stereotyped Inflatable Water Wheel,3795,4,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,15,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended." -Soft Puddle Jumper Life Jacket,1359,4,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,1,For children 30-50 lbs. -Abrupt Shark Goggles,1196,4,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,1,Made using the highest quality materials -Womanly Swimming Fish Pool Toy,1399,4,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,5, -Minor Water Wings,690,4,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,1,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue -Grateful Dive Rings,599,5,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",13,Unbreakable rings stand up on the pool bottom for diving games. Set of 4. -Stale Dory Doll,3000,5,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,13,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll" -Thundering Finding Nemo DVD,1996,5,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,4,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination." -Right Dory Doll,3000,6,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,6,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll" -Petite Finding Nemo DVD,1996,6,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,8,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination." -Spotty Water Wings,690,6,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,11,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue -Ubiquitous Dive Sticks,395,7,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,14,Sticks stand upright on pool bottom. -Bustling Shark Goggles,1196,7,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,15,Made using the highest quality materials -Wry Toypedo Bandits,615,7,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,7,Glides underwater up to 30 feet +Pumped Water Wings,690,1,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,1,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue +Bouncy Dive Rings,599,2,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",6,Unbreakable rings stand up on the pool bottom for diving games. Set of 4. +Steep Dive Sticks,395,2,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,10,Sticks stand upright on pool bottom. +Sore Dory Doll,3000,2,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,8,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll" +Talented Inflatable Water Wheel,3795,2,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,5,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended." +Young Swimming Fish Pool Toy,1399,2,http://ecx.images-amazon.com/images/I/71R6EdJ3pVL._SL1001_.jpg,2, +Moldy Toypedo Bandits,615,2,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,2,Glides underwater up to 30 feet +Courageous Water Noodles,1143,2,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,1,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random. +Guarded Water Wings,690,2,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,9,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue +Crooked Dive Rings,599,3,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",5,Unbreakable rings stand up on the pool bottom for diving games. Set of 4. +Efficacious Dive Sticks,395,3,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,9,Sticks stand upright on pool bottom. +Wrong Finding Nemo DVD,1996,3,http://cdn.funcheap.com/wp-content/uploads/2014/03/finding-nemo-poster.jpg,4,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination." +Easy Inflatable Water Wheel,3795,3,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,14,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended." +Unwieldy Puddle Jumper Life Jacket,1359,3,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,3,For children 30-50 lbs. +Near Shark Goggles,1196,3,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,5,Made using the highest quality materials +Uppity Swimming Fish Pool Toy,1399,3,http://ecx.images-amazon.com/images/I/71R6EdJ3pVL._SL1001_.jpg,3, +Black Toypedo Bandits,615,3,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,5,Glides underwater up to 30 feet +Necessary Water Noodles,1143,3,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,9,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random. +Piquant Water Wings,690,3,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,14,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue +Ripe Dive Sticks,395,4,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,12,Sticks stand upright on pool bottom. +Wandering Finding Nemo DVD,1996,4,http://cdn.funcheap.com/wp-content/uploads/2014/03/finding-nemo-poster.jpg,8,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination." +Stereotyped Inflatable Water Wheel,3795,4,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,2,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended." +Soft Puddle Jumper Life Jacket,1359,4,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,5,For children 30-50 lbs. +Abrupt Shark Goggles,1196,4,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,7,Made using the highest quality materials +Womanly Swimming Fish Pool Toy,1399,4,http://ecx.images-amazon.com/images/I/71R6EdJ3pVL._SL1001_.jpg,6, +Minor Water Wings,690,4,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,3,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue +Grateful Dive Rings,599,5,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",4,Unbreakable rings stand up on the pool bottom for diving games. Set of 4. +Stale Dory Doll,3000,5,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,12,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll" +Thundering Finding Nemo DVD,1996,5,http://cdn.funcheap.com/wp-content/uploads/2014/03/finding-nemo-poster.jpg,13,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination." +Right Dory Doll,3000,6,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,2,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll" +Petite Finding Nemo DVD,1996,6,http://cdn.funcheap.com/wp-content/uploads/2014/03/finding-nemo-poster.jpg,3,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination." +Spotty Water Wings,690,6,http://ecx.images-amazon.com/images/I/41d4FRluYsL.jpg,14,Boys Floatsafe Flotie Soft Fabric Armbands floatie Blue +Ubiquitous Dive Sticks,395,7,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,12,Sticks stand upright on pool bottom. +Bustling Shark Goggles,1196,7,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,12,Made using the highest quality materials +Wry Toypedo Bandits,615,7,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,15,Glides underwater up to 30 feet Squealing Water Noodles,1143,7,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,3,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random. -Adhesive Dive Sticks,395,8,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,9,Sticks stand upright on pool bottom. -Hissing Puddle Jumper Life Jacket,1359,8,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,13,For children 30-50 lbs. -Sloppy Puddle Jumper Life Jacket,1359,9,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,7,For children 30-50 lbs. -Hanging Shark Goggles,1196,8,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,15,Made using the highest quality materials -Fumbling Toypedo Bandits,615,8,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,15,Glides underwater up to 30 feet -Brief Dive Rings,599,9,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",12,Unbreakable rings stand up on the pool bottom for diving games. Set of 4. -Lean Dory Doll,3000,9,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,10,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll" -Giant Inflatable Water Wheel,3795,9,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,7,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended." -Lazy Water Noodles,1143,9,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,3,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random. -Animated Dory Doll,3000,10,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,1,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll" -Ethereal Finding Nemo DVD,1996,10,http://ecx.images-amazon.com/images/I/51qeAio4V-L.jpg,2,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination." -Regular Puddle Jumper Life Jacket,1359,10,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,8,For children 30-50 lbs. -Dizzy Swimming Fish Pool Toy,1399,10,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,9, -Medical Toypedo Bandits,615,10,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,15,Glides underwater up to 30 feet +Adhesive Dive Sticks,395,8,http://ecx.images-amazon.com/images/I/71HLzuKqRAL._SX522_.jpg,8,Sticks stand upright on pool bottom. +Hissing Puddle Jumper Life Jacket,1359,8,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,4,For children 30-50 lbs. +Sloppy Puddle Jumper Life Jacket,1359,9,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,1,For children 30-50 lbs. +Hanging Shark Goggles,1196,8,http://ecx.images-amazon.com/images/I/617jzjqn8gL._SX522_.jpg,7,Made using the highest quality materials +Fumbling Toypedo Bandits,615,8,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,12,Glides underwater up to 30 feet +Brief Dive Rings,599,9,"http://ecx.images-amazon.com/images/I/41LsD5TcnYL.AA500_PIcountsize-2,TopRight,0,0_AA500_SH20_.jpg",1,Unbreakable rings stand up on the pool bottom for diving games. Set of 4. +Lean Dory Doll,3000,9,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,7,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll" +Giant Inflatable Water Wheel,3795,9,http://ecx.images-amazon.com/images/I/51K8HOgMx5L.jpg,3,"Kid's Inflatable Water Wheel Swimming Pool Toy (49"" X 33"") - Summer just got funner in the pool with this brand new Kidster Water Wheel. Don't you wish we had these when we were kids. Your kids will love the hamster wheel like movement in this fun and unique inflatable pool toy. Roll along the top of the water with ease in the Kidster Water Wheel. Adult Supervision is always recommended." +Lazy Water Noodles,1143,9,http://ecx.images-amazon.com/images/I/41nwJCNDadL.jpg,14,Large diameter for extra fun! Made from Safe Soft Funnoodle Foam! Floats over 200 pounds! Funnoodle Monster America's #1 selling pool toy. Let's have fun in the sun. Listing is for 1 Monster Funnoodle - color chosen at random. +Animated Dory Doll,3000,10,http://ecx.images-amazon.com/images/I/51K6wQjaqYL.jpg,9,"Disney Finding Nemo Large Finding Dory 12"" Plush DORY Doll" +Ethereal Finding Nemo DVD,1996,10,http://cdn.funcheap.com/wp-content/uploads/2014/03/finding-nemo-poster.jpg,14,"Sea it like never before! For the first time ever, through the magic of Blu-ray and Blu-ray 3D, fully immerse yourself in the stunning underwater world of Disney/Pixar's FINDING NEMO! From the creators of TOY STORY and MONSTERS, INC., this critically acclaimed and heartwarming tale splashes off the screen with brilliant digital picture, high definition sound and breathtaking bonus features that transport you beyond your imagination." +Regular Puddle Jumper Life Jacket,1359,10,http://ecx.images-amazon.com/images/I/61gR3TBnTuL._SX522_.jpg,1,For children 30-50 lbs. +Dizzy Swimming Fish Pool Toy,1399,10,http://ecx.images-amazon.com/images/I/71R6EdJ3pVL._SL1001_.jpg,14, +Medical Toypedo Bandits,615,10,http://ecx.images-amazon.com/images/I/41YoOqCoHlL.jpg,8,Glides underwater up to 30 feet From cabbf873d7e049c1a247685c728d8c3fb47019ff Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 10 Dec 2015 14:47:54 -0800 Subject: [PATCH 082/299] make review stars change based on review average --- app/models/product.rb | 13 +++++++++++++ app/views/shared/_display_products.html.erb | 7 ++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/app/models/product.rb b/app/models/product.rb index 629a357e12..a11451f2b7 100644 --- a/app/models/product.rb +++ b/app/models/product.rb @@ -9,4 +9,17 @@ class Product < ActiveRecord::Base validates_numericality_of :price, :greater_than => 0 validates :photo_url, format: {with: /\.(png|jpg)\Z/i}, allow_nil: true + def review_average + if reviews.any? + total = reviews.inject(0) { |sum, review| sum + review.rating } + return total * 1.0 / reviews.count + else + return 0 + end + end + + def review_rounded + return review_average.round + end + end diff --git a/app/views/shared/_display_products.html.erb b/app/views/shared/_display_products.html.erb index 0872be5bc6..83bafcc2c0 100644 --- a/app/views/shared/_display_products.html.erb +++ b/app/views/shared/_display_products.html.erb @@ -22,11 +22,12 @@

<%= pluralize(product.reviews.count, "Review") %>

+ <% product.review_rounded.times do %> - - - + <% end %> + <% (5 - product.review_rounded).times do %> + <% end %>

From c24a3a7623a6f9b6da571884b315f7a153f94993 Mon Sep 17 00:00:00 2001 From: Tammy Date: Thu, 10 Dec 2015 14:53:36 -0800 Subject: [PATCH 083/299] 4 tests are working --- spec/controllers/users_controller_spec.rb | 73 ++++++++++++++--------- 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 0f7d9e1cef..12c638a91e 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -20,35 +20,54 @@ RSpec.describe UsersController, type: :controller do describe "GET 'index'" do - it "is successful" do - get :index - expect(response.status).to eq 200 + it "is successful" do + get :index + expect(response.status).to eq 200 + end end -end - # This should return the minimal set of attributes required to create a valid - # User. As you add validations to User, be sure to - # # adjust the attributes here as well. - # let(:valid_attributes) { - # skip("Add a hash of attributes valid for your model") - # } - # - # let(:invalid_attributes) { - # skip("Add a hash of attributes invalid for your model") - # } - # - # # 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 - # # UsersController. Be sure to keep this updated too. - # let(:valid_session) { {} } - # - # describe "GET #index" do - # it "assigns all users as @users" do - # user = User.create! valid_attributes - # get :index, {}, valid_session - # expect(assigns(:users)).to eq([user]) - # end - # end + describe "GET 'new'" do + it "render new view" do + get :new + expect(subject).to render_template :new + end + end + + describe "GET 'edit'" do + let(:user) do + User.create(name: "Nemo", username: "Nemo1", email: "nemo@gmail.com", password: "123", password_confirmation: "123") + end + + it "renders edit view" do + get :edit, id: user.id + expect(subject).to render_template :edit + end + + end + + describe "GET 'show'" do + let(:user) do + User.create(name: "Nemo", username: "Nemo1", email: "nemo@gmail.com", password: "123", password_confirmation: "123") + end + + it "renders the show view" do + get :show, id: user.id + expect(subject).to render_template :show + end + end + + + # let(:good_params) do + # { + # user: { + # name: "Nemo", + # username: "Nemo1", + # email: "nemo@gmail.com", + # password: "123", + # password_confirmation: "123" + # } + # } + # # describe "GET #show" do # it "assigns the requested user as @user" do From ffdc3b0394f74759c17d185abb4c514fc7b911f0 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 10 Dec 2015 15:03:48 -0800 Subject: [PATCH 084/299] change template for all products page --- app/views/products/index.html.erb | 2 +- app/views/shared/_display_products.html.erb | 77 +++++++++++---------- 2 files changed, 43 insertions(+), 36 deletions(-) diff --git a/app/views/products/index.html.erb b/app/views/products/index.html.erb index 3b9847992f..6e0cdc6373 100644 --- a/app/views/products/index.html.erb +++ b/app/views/products/index.html.erb @@ -1,2 +1,2 @@

All Products

-<%= render partial: 'shared/products' %> +<%= render partial: 'shared/display_products' %> diff --git a/app/views/shared/_display_products.html.erb b/app/views/shared/_display_products.html.erb index 83bafcc2c0..4b93c314f2 100644 --- a/app/views/shared/_display_products.html.erb +++ b/app/views/shared/_display_products.html.erb @@ -1,38 +1,45 @@ -<% @products.to_ary.in_groups_of(4, false) do |group| %> -
- <% group.each do |product| %> -
-
-
- <%= image_tag product.photo_url, alt: "product photo" %> -
-
-
<%= dollar_price(product.price) %>
-
<%= link_to product.name, user_product_path(product.user_id, product.id) %> -
-

- <% if !product.description.nil? %> - <%= product.description %> - <% else %> -
+

+ <% if @products.respond_to?(:total_pages) %> + <%= will_paginate @products %> + <% end %> + <% @products.to_ary.in_groups_of(4, false) do |group| %> +
+ <% group.each do |product| %> +
+
+
+ <%= image_tag product.photo_url, alt: "product photo" %> +
+
+
<%= dollar_price(product.price) %>
+
<%= link_to product.name, user_product_path(product.user_id, product.id) %> +
+

+ <% if !product.description.nil? %> + <%= product.description %> + <% else %> +
+ <% end %> +

+

<%= product.stock %> Available

+
+
+

<%= pluralize(product.reviews.count, "Review") %>

+

+ <% product.review_rounded.times do %> + + <% end %> + <% (5 - product.review_rounded).times do %> + <% end %>

-

<%= product.stock %> Available

-
-
-

<%= pluralize(product.reviews.count, "Review") %>

-

- <% product.review_rounded.times do %> - - <% end %> - <% (5 - product.review_rounded).times do %> - - <% end %> -

-
- +
+
-
- <% end %> -
-<% end %> + <% end %> +
+ <% end %> + <% if @products.respond_to?(:total_pages) %> + <%= will_paginate @products %> + <% end %> +
From 6fd42f67ad8a863c8c5481de744147a1eb48fc47 Mon Sep 17 00:00:00 2001 From: Tammy Date: Thu, 10 Dec 2015 15:14:43 -0800 Subject: [PATCH 085/299] created update and get tests --- spec/controllers/users_controller_spec.rb | 203 +++++++++------------- 1 file changed, 80 insertions(+), 123 deletions(-) diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 12c638a91e..4ffd84ddcc 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -56,129 +56,86 @@ end end + describe "POST 'create'" do + let(:good_params) do + { + user: { + name: "Nemo", + username: "Nemo1", + email: "nemo@gmail.com", + password: "123", + password_confirmation: "123" + } + } + end + + let(:bad_params) do + { + user: { + name: "", + username: "Nemo1", + email: "nemo@gmail.com", + password: "1223", + password_confirmation: "123" + } + } + end + + it "redirect to index page" do + post :create, good_params + #success case + expect(subject).to redirect_to users_path + end + + it "render new template on error" do + #Error case + post :create, bad_params + expect(subject).to render_template :new + end + end + - # let(:good_params) do - # { - # user: { - # name: "Nemo", - # username: "Nemo1", - # email: "nemo@gmail.com", - # password: "123", - # password_confirmation: "123" - # } - # } - - # - # describe "GET #show" do - # it "assigns the requested user as @user" do - # user = User.create! valid_attributes - # get :show, {:id => user.to_param}, valid_session - # expect(assigns(:user)).to eq(user) - # end - # end - # - # describe "GET #new" do - # it "assigns a new user as @user" do - # get :new, {}, valid_session - # expect(assigns(:user)).to be_a_new(User) - # end - # end - # - # describe "GET #edit" do - # it "assigns the requested user as @user" do - # user = User.create! valid_attributes - # get :edit, {:id => user.to_param}, valid_session - # expect(assigns(:user)).to eq(user) - # end - # end - # - # describe "POST #create" do - # context "with valid params" do - # it "creates a new User" do - # expect { - # post :create, {:user => valid_attributes}, valid_session - # }.to change(User, :count).by(1) - # end - # - # it "assigns a newly created user as @user" do - # post :create, {:user => valid_attributes}, valid_session - # expect(assigns(:user)).to be_a(User) - # expect(assigns(:user)).to be_persisted - # end - # - # it "redirects to the created user" do - # post :create, {:user => valid_attributes}, valid_session - # expect(response).to redirect_to(User.last) - # end - # end - # - # context "with invalid params" do - # it "assigns a newly created but unsaved user as @user" do - # post :create, {:user => invalid_attributes}, valid_session - # expect(assigns(:user)).to be_a_new(User) - # end - # - # it "re-renders the 'new' template" do - # post :create, {:user => invalid_attributes}, valid_session - # expect(response).to render_template("new") - # end - # end - # end - # - # describe "PUT #update" do - # context "with valid params" do - # let(:new_attributes) { - # skip("Add a hash of attributes valid for your model") - # } - # - # it "updates the requested user" do - # user = User.create! valid_attributes - # put :update, {:id => user.to_param, :user => new_attributes}, valid_session - # user.reload - # skip("Add assertions for updated state") - # end - # - # it "assigns the requested user as @user" do - # user = User.create! valid_attributes - # put :update, {:id => user.to_param, :user => valid_attributes}, valid_session - # expect(assigns(:user)).to eq(user) - # end - # - # it "redirects to the user" do - # user = User.create! valid_attributes - # put :update, {:id => user.to_param, :user => valid_attributes}, valid_session - # expect(response).to redirect_to(user) - # end - # end - # - # context "with invalid params" do - # it "assigns the user as @user" do - # user = User.create! valid_attributes - # put :update, {:id => user.to_param, :user => invalid_attributes}, valid_session - # expect(assigns(:user)).to eq(user) - # end - # - # it "re-renders the 'edit' template" do - # user = User.create! valid_attributes - # put :update, {:id => user.to_param, :user => invalid_attributes}, valid_session - # expect(response).to render_template("edit") - # end - # end - # end - # - # describe "DELETE #destroy" do - # it "destroys the requested user" do - # user = User.create! valid_attributes - # expect { - # delete :destroy, {:id => user.to_param}, valid_session - # }.to change(User, :count).by(-1) - # end - # - # it "redirects to the users list" do - # user = User.create! valid_attributes - # delete :destroy, {:id => user.to_param}, valid_session - # expect(response).to redirect_to(users_url) - # end - # end + describe "PATCH 'update'" do + let(:user) do + User.create(name: "Nemo", username: "Nemo1", email: "nemo@gmail.com", password: "123", password_confirmation: "123") + end + + let(:good_params) do + { + id: user.id, + user: { + name: "Nemo", + username: "Nemo1", + email: "nemo@gmail.com", + password: "123", + password_confirmation: "123" + } + } + end + + let(:bad_params) do + { + id: user.id, + user: { + name: "", + username: "Nemo1", + email: "nemo@gmail.com", + password: "1223", + password_confirmation: "123" + } + } + end + + it "redirect to index page" do + patch :update, good_params + expect(subject).to redirect_to users_path + end + + it "render edit template on error" do + patch :update, bad_params + expect(subject).to render_template "edit" + end + + end end From bbad6178041edc5ecb35cdef8a6eb47dff4454d9 Mon Sep 17 00:00:00 2001 From: Tammy Date: Thu, 10 Dec 2015 15:17:39 -0800 Subject: [PATCH 086/299] done with users spec --- spec/controllers/users_controller_spec.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 4ffd84ddcc..c217ed6599 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -136,6 +136,18 @@ expect(subject).to render_template "edit" end + end + + describe "DELETE 'destroy'" do + let(:user) do + User.create(name: "Nemo", username: "Nemo1", email: "nemo@gmail.com", password: "123", password_confirmation: "123") end + it "redirect to index after deleting" do + delete :destroy, id: user.id + expect(subject).to redirect_to users_path + end + + end + end From 4972ed1643f9f5e557a16c4bcf4770fedbbe7f28 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 10 Dec 2015 15:51:20 -0800 Subject: [PATCH 087/299] create product model tests for validations --- spec/models/product_spec.rb | 40 ++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/spec/models/product_spec.rb b/spec/models/product_spec.rb index 3ed2123666..5113c35e43 100644 --- a/spec/models/product_spec.rb +++ b/spec/models/product_spec.rb @@ -1,5 +1,35 @@ -# require 'rails_helper' -# -# RSpec.describe Product, type: :model do -# pending "add some examples to (or delete) #{__FILE__}" -# end +require 'rails_helper' + +RSpec.describe Product, type: :model do + let(:sample_product) { + Product.create(name: "Water bottle", price: 10 ) + } + describe ".validates" do + it "must have a name and price" do + expect(Product.new(name: "a")).to_not be_valid + expect(Product.new(price: 15)).to_not be_valid + expect(Product.new(name: "a", price: 15)).to be_valid + end + it "must have a unique name" do + expect(Product.new(name: "Water bottle")).to_not be_valid + end + it "must have a numerical price" do + expect(Product.new(name: "a", price: "a")).to_not be_valid + end + it "must have a price greater than 0" do + expect(Product.new(name: "a", price: -1)).to_not be_valid + expect(Product.new(name: "a", price: 0)).to_not be_valid + end + it "must have an image url ending in jpg or png" do + sample_product.photo_url = "image.jpg" + expect(sample_product).to be_valid + sample_product.photo_url = "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png" + expect(sample_product).to be_valid + sample_product.photo_url = "image.mov" + expect(sample_product).to_not be_valid + sample_product.photo_url = "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1" + expect(sample_product).to_not be_valid + end + end + +end From eaa6ddca3149edf7a1f3c3fe89cdc2b466f3c094 Mon Sep 17 00:00:00 2001 From: Kelly Date: Thu, 10 Dec 2015 15:57:01 -0800 Subject: [PATCH 088/299] Update product#create and product#update to accept categories --- app/controllers/products_controller.rb | 7 +++++++ app/controllers/reviews_controller.rb | 3 +-- app/views/products/_form.html.erb | 7 ++++++- app/views/products/edit.html.erb | 2 +- app/views/products/show.html.erb | 7 +++++++ 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index cc8294af55..850004684a 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -13,14 +13,19 @@ def show def new @product = Product.new + @categories = Category.all end def edit + @categories = Category.all + @product_categories = @product.categories end def create + @categories = Category.all @product = Product.create(product_params) do |p| p.user_id = @user.id + p.categories = Category.find(params[:categories]) end if @product.save redirect_to user_products_path(@product.user) @@ -31,6 +36,8 @@ def create def update @product.update(product_params) + @product.categories = Category.find(params[:categories]) + @product.save if @product.save redirect_to user_products_path(@product.user) else diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb index ad0877caad..45a4a3672c 100644 --- a/app/controllers/reviews_controller.rb +++ b/app/controllers/reviews_controller.rb @@ -33,8 +33,7 @@ def create def update - @review.update(review_params) - if @review.save + if @review.update(review_params) redirect_to user_product_reviews_path(@review.product.user, @review.product, @review) else render :edit diff --git a/app/views/products/_form.html.erb b/app/views/products/_form.html.erb index f85fb94c42..81d25244ab 100644 --- a/app/views/products/_form.html.erb +++ b/app/views/products/_form.html.erb @@ -28,7 +28,12 @@ <%= f.label :active %> <%= f.check_box :active %> - +
+ <%= f.label "Categories:" %> + <% @categories.each do |c| %> + <%= check_box_tag "categories[]", c.id, @product.categories.include?(c) %> + <%= label_tag c.name %> + <% end %> <%= f.submit %>
<% end %> diff --git a/app/views/products/edit.html.erb b/app/views/products/edit.html.erb index 1cd7ea216f..f94a25f113 100644 --- a/app/views/products/edit.html.erb +++ b/app/views/products/edit.html.erb @@ -4,4 +4,4 @@ <%= link_to 'Show', user_product_path(@product.user, @product) %> | -<%= link_to 'Back', user_products_path %> +<%= link_to 'Back', user_products_path(@product.user) %> diff --git a/app/views/products/show.html.erb b/app/views/products/show.html.erb index 9e2b3a1a5e..81547a4e73 100644 --- a/app/views/products/show.html.erb +++ b/app/views/products/show.html.erb @@ -30,6 +30,13 @@ <%= @product.description %>

+

+ Categories: + <% @product.categories.each do |c| %> + <%= c.name %> + <% end %> +

+

Active: <%= @product.active %> From 91962632a07b28dc0b11c6bf6dc54c5b89569045 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 10 Dec 2015 15:58:22 -0800 Subject: [PATCH 089/299] create tests for product model --- spec/models/product_spec.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/spec/models/product_spec.rb b/spec/models/product_spec.rb index 5113c35e43..8e4e8fe8be 100644 --- a/spec/models/product_spec.rb +++ b/spec/models/product_spec.rb @@ -31,5 +31,18 @@ expect(sample_product).to_not be_valid end end + describe "review methods" do + let(:r1) { + Review.create(rating: 3) + } + let(:r2) { + Review.create(rating: 4) + } + it "calculates the correct review statistics" do + sample_product.reviews = [r1, r2] + expect(sample_product.review_average).to eq(3.5) + expect(sample_product.review_rounded).to eq(4) + end + end end From dd7f8215f6349e98fdcb2dd68db3e1e5b3eb0317 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 10 Dec 2015 16:05:20 -0800 Subject: [PATCH 090/299] add coverage report to helper file --- spec/models/product_spec.rb | 4 ++++ spec/spec_helper.rb | 3 +++ 2 files changed, 7 insertions(+) diff --git a/spec/models/product_spec.rb b/spec/models/product_spec.rb index 8e4e8fe8be..9f36dfcaca 100644 --- a/spec/models/product_spec.rb +++ b/spec/models/product_spec.rb @@ -43,6 +43,10 @@ expect(sample_product.review_average).to eq(3.5) expect(sample_product.review_rounded).to eq(4) end + it "returns 0 for no reviews" do + expect(sample_product.review_average).to eq(0) + expect(sample_product.review_average).to eq(0) + end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 61e27385c3..7c1a15ce54 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,3 +1,6 @@ +require 'simplecov' +SimpleCov.start + # This file was generated by the `rails generate rspec:install` command. Conventionally, all # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. # The generated `.rspec` file contains `--require spec_helper` which will cause From 087b8a210848715f93b932796ed34ca7f0ad107a Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 10 Dec 2015 16:19:47 -0800 Subject: [PATCH 091/299] fix uniqueness test for product model --- spec/models/product_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/models/product_spec.rb b/spec/models/product_spec.rb index 9f36dfcaca..e4fd8069ae 100644 --- a/spec/models/product_spec.rb +++ b/spec/models/product_spec.rb @@ -11,7 +11,8 @@ expect(Product.new(name: "a", price: 15)).to be_valid end it "must have a unique name" do - expect(Product.new(name: "Water bottle")).to_not be_valid + Product.create(name: "a", price: 10) + expect(Product.new(name: "a", price: 10)).to_not be_valid end it "must have a numerical price" do expect(Product.new(name: "a", price: "a")).to_not be_valid From 99f5020a0f7009b39f0fadf1d069d1037a31973b Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 10 Dec 2015 16:25:22 -0800 Subject: [PATCH 092/299] add shoula matchers to gemfile --- Gemfile | 4 ++++ Gemfile.lock | 3 +++ 2 files changed, 7 insertions(+) diff --git a/Gemfile b/Gemfile index afe58860a8..c3eacacfab 100644 --- a/Gemfile +++ b/Gemfile @@ -42,6 +42,10 @@ group :production do gem "pg" end +group :test do + gem 'shoulda-matchers', '~> 3.0' +end + group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug' diff --git a/Gemfile.lock b/Gemfile.lock index c9418ea29b..bceaf62f4c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -151,6 +151,8 @@ GEM sdoc (0.4.1) json (~> 1.7, >= 1.7.7) rdoc (~> 4.0) + shoulda-matchers (3.0.1) + activesupport (>= 4.0.0) simplecov (0.11.1) docile (~> 1.1.0) json (~> 1.8) @@ -201,6 +203,7 @@ DEPENDENCIES rspec-rails sass-rails (~> 5.0) sdoc (~> 0.4.0) + shoulda-matchers (~> 3.0) simplecov spring sqlite3 From 8fce019ff4ca7d3ffd99bef4cbeed58b6b12ba99 Mon Sep 17 00:00:00 2001 From: Tammy Date: Thu, 10 Dec 2015 16:26:10 -0800 Subject: [PATCH 093/299] almost done with user model RSPEC --- spec/models/user_spec.rb | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 7608427118..4b5784c24f 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1,5 +1,25 @@ -# require 'rails_helper' -# -# RSpec.describe User, type: :model do -# pending "add some examples to (or delete) #{__FILE__}" -# end +require 'rails_helper' + +RSpec.describe User, type: :model do + describe ".validates" do + let(:user1) do + User.create(name: "Nemo", username: "Nemo1", email: "nemo@gmail.com", password: "123", password_confirmation: "123") + end + let(:user2) do + User.create(name: "Nemo2", username: "Nemo2", email: "nemo@gmail.com", password: "123", password_confirmation: "123") + end + it "must have a username" do + expect(User.new(username: nil)).to_not be_valid + end + + it "must have an email" do + expect(User.new(email: nil)).to_not be_valid + end + + it "should have uniqueness email" do + expect(:user2).to_not be_vaild + end + end + + +end From 0d83687043440172cb8e2d5f3fed9048eef3ed04 Mon Sep 17 00:00:00 2001 From: Kelly Date: Thu, 10 Dec 2015 16:33:11 -0800 Subject: [PATCH 094/299] Complete product#create and product#update --- app/controllers/categories_controller.rb | 1 - app/controllers/products_controller.rb | 44 ++++++++++++++---------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb index 61be22439c..e1eb4b77c0 100644 --- a/app/controllers/categories_controller.rb +++ b/app/controllers/categories_controller.rb @@ -43,7 +43,6 @@ def set_category @category = Category.find(params[:id]) end - def category_params params.require(:category).permit(:name) end diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index 850004684a..8d8c85bc98 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -1,6 +1,7 @@ class ProductsController < ApplicationController - before_action :find_product, only: [:show, :edit, :update, :destroy] + before_action :find_product, only: [:show, :edit, :update] before_action :find_user, only: [:new, :edit, :create, :update] + before_action :all_categories, only: [:new, :edit, :create, :update] def index @products = Product.all.paginate(page: params[:page], per_page: 12) @@ -13,19 +14,19 @@ def show def new @product = Product.new - @categories = Category.all end def edit - @categories = Category.all - @product_categories = @product.categories end def create - @categories = Category.all @product = Product.create(product_params) do |p| p.user_id = @user.id - p.categories = Category.find(params[:categories]) + if params[:categories].nil? + p.categories = [] + else + p.categories = Category.find(params[:categories]) + end end if @product.save redirect_to user_products_path(@product.user) @@ -35,9 +36,12 @@ def create end def update - @product.update(product_params) - @product.categories = Category.find(params[:categories]) - @product.save + @product.assign_attributes(product_params) + if params[:categories].nil? + @product.categories = [] + else + @product.categories = Category.find(params[:categories]) + end if @product.save redirect_to user_products_path(@product.user) else @@ -47,15 +51,19 @@ def update private - def find_product - @product = Product.find(params[:id]) - end + def find_product + @product = Product.find(params[:id]) + end - def find_user - @user = User.find(params[:user_id]) - end + def find_user + @user = User.find(params[:user_id]) + end - def product_params - params.require(:product).permit(:name, :price, :photo_url, :stock, :description, :active) - end + def all_categories + @categories = Category.all + end + + def product_params + params.require(:product).permit(:name, :price, :photo_url, :stock, :description, :active) + end end From b1c00b0a4dd446b8664840291e63003747893c77 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 10 Dec 2015 16:37:10 -0800 Subject: [PATCH 095/299] configure shoulda matchers gem --- spec/models/product_spec.rb | 13 ++++++++----- spec/models/review_spec.rb | 12 +++++++----- spec/rails_helper.rb | 9 +++++++++ 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/spec/models/product_spec.rb b/spec/models/product_spec.rb index e4fd8069ae..1b684a7330 100644 --- a/spec/models/product_spec.rb +++ b/spec/models/product_spec.rb @@ -5,11 +5,14 @@ Product.create(name: "Water bottle", price: 10 ) } describe ".validates" do - it "must have a name and price" do - expect(Product.new(name: "a")).to_not be_valid - expect(Product.new(price: 15)).to_not be_valid - expect(Product.new(name: "a", price: 15)).to be_valid - end + it { is_expected.to validate_presence_of(:name) } + it { is_expected.to validate_presence_of(:price) } + + # it "must have a name and price" do + # expect(Product.new(name: "a")).to_not be_valid + # expect(Product.new(price: 15)).to_not be_valid + # expect(Product.new(name: "a", price: 15)).to be_valid + # end it "must have a unique name" do Product.create(name: "a", price: 10) expect(Product.new(name: "a", price: 10)).to_not be_valid diff --git a/spec/models/review_spec.rb b/spec/models/review_spec.rb index fec60888bd..c298a1febe 100644 --- a/spec/models/review_spec.rb +++ b/spec/models/review_spec.rb @@ -1,5 +1,7 @@ -# require 'rails_helper' -# -# RSpec.describe Review, type: :model do -# pending "add some examples to (or delete) #{__FILE__}" -# end +require 'rails_helper' + +RSpec.describe Review, type: :model do + let(:sample_product) { + Product.create(name: "Water bottle", price: 10 ) + } +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 6f1ab14638..aea1737bcd 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -5,6 +5,8 @@ abort("The Rails environment is running in production mode!") if Rails.env.production? require 'spec_helper' require 'rspec/rails' +require 'shoulda-matchers' + # Add additional requires below this line. Rails is not loaded until this point! # Requires supporting ruby files with custom matchers and macros, etc, in @@ -55,3 +57,10 @@ # arbitrary gems may also be filtered via: # config.filter_gems_from_backtrace("gem name") end + +Shoulda::Matchers.configure do |config| + config.integrate do |with| + with.test_framework :rspec + with.library :rails + end +end From 581bedf9dfe3a6abc575f246f9041b2376358d60 Mon Sep 17 00:00:00 2001 From: Tammy Date: Thu, 10 Dec 2015 16:48:15 -0800 Subject: [PATCH 096/299] the user email validation spec is working --- spec/models/user_spec.rb | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 4b5784c24f..474de02e39 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1,5 +1,6 @@ require 'rails_helper' + RSpec.describe User, type: :model do describe ".validates" do let(:user1) do @@ -15,11 +16,24 @@ it "must have an email" do expect(User.new(email: nil)).to_not be_valid end - - it "should have uniqueness email" do - expect(:user2).to_not be_vaild + end + # + describe "uniqueness" do + it do + should validate_uniqueness_of(:email) end end + # it "should have uniqueness email" do + # expect validate_uniqueness_of(:email) + # end + # it "should have uniqueness email" do + # expect(:user2).to be_vaild + # end + # end + # + # + # it { validate_uniqueness_of(:email) } + # end end From de4c1ecef762559c3f6225df4eec4a2caa221818 Mon Sep 17 00:00:00 2001 From: Kelly Date: Thu, 10 Dec 2015 16:55:15 -0800 Subject: [PATCH 097/299] Category CRU, removed D --- app/controllers/categories_controller.rb | 37 ++++++++++++------------ app/controllers/products_controller.rb | 2 -- app/controllers/users_controller.rb | 25 +++++++--------- app/models/category.rb | 1 + app/views/categories/_form.html.erb | 2 -- app/views/categories/index.html.erb | 1 - app/views/categories/show.html.erb | 6 ++-- 7 files changed, 32 insertions(+), 42 deletions(-) diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb index e1eb4b77c0..373be73fe0 100644 --- a/app/controllers/categories_controller.rb +++ b/app/controllers/categories_controller.rb @@ -1,5 +1,5 @@ class CategoriesController < ApplicationController - before_action :set_category, only: [:show, :edit, :update, :destroy] + before_action :find_category, only: [:show, :edit, :update] def index @categories = Category.all @@ -7,6 +7,7 @@ def index def show + @products = @category.products.paginate(page: params[:page], per_page: 12) end @@ -20,30 +21,28 @@ def edit def create @category = Category.new(category_params) - if @category.save - redirect_to categories_path - else - render "new" - end + if @category.save + redirect_to categories_path + else + render :new + end end def update - @category.update(category_params) - redirect_to categories_path - end - - def destroy - @category.destroy - redirect_to categories_path + if @category.update(category_params) + redirect_to categories_path + else + render :edit + end end private - def set_category - @category = Category.find(params[:id]) - end + def find_category + @category = Category.find(params[:id]) + end - def category_params - params.require(:category).permit(:name) - end + def category_params + params.require(:category).permit(:name) + end end diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index 8d8c85bc98..7046758cb9 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -7,11 +7,9 @@ def index @products = Product.all.paginate(page: params[:page], per_page: 12) end - def show end - def new @product = Product.new end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 1518e8b9c1..baa34868e4 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -16,10 +16,8 @@ def new def products @products = @user.products.paginate(page: params[:page], per_page: 12) - end - def edit end @@ -33,12 +31,11 @@ def create end def update - if @user.update(user_params) - redirect_to users_path - else - render "edit" - end - + if @user.update(user_params) + redirect_to users_path + else + render "edit" + end end def destroy @@ -50,12 +47,12 @@ def destroy private - def set_user - @user = User.find(params[:id]) - end + def set_user + @user = User.find(params[:id]) + end - def user_params - params.require(:user).permit(:username, :email, :password, :password_confirmation, :name) - end + def user_params + params.require(:user).permit(:username, :email, :password, :password_confirmation, :name) + end end diff --git a/app/models/category.rb b/app/models/category.rb index 7f018cd725..ffcf81213b 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -1,3 +1,4 @@ class Category < ActiveRecord::Base has_and_belongs_to_many :products + validates :name, presence: true end diff --git a/app/views/categories/_form.html.erb b/app/views/categories/_form.html.erb index dd35d336a7..d244c9eac7 100644 --- a/app/views/categories/_form.html.erb +++ b/app/views/categories/_form.html.erb @@ -1,8 +1,6 @@ <%= form_for(@category) do |f| %> <% if @category.errors.any? %>

-

<%= pluralize(@category.errors.count, "error") %> prohibited this category from being saved:

-
    <% @category.errors.full_messages.each do |message| %>
  • <%= message %>
  • diff --git a/app/views/categories/index.html.erb b/app/views/categories/index.html.erb index f0e18cca21..cddff1237e 100644 --- a/app/views/categories/index.html.erb +++ b/app/views/categories/index.html.erb @@ -16,7 +16,6 @@ <%= category.name %> <%= link_to 'Show', category %> <%= link_to 'Edit', edit_category_path(category) %> - <%= link_to 'Destroy', category_path(category), method: :delete, data: { confirm: 'Are you sure?' } %> <% end %> diff --git a/app/views/categories/show.html.erb b/app/views/categories/show.html.erb index 09b199c8c5..5e323453bd 100644 --- a/app/views/categories/show.html.erb +++ b/app/views/categories/show.html.erb @@ -1,9 +1,7 @@

    <%= notice %>

    +

    <%= @category.name %> Products

    -

    - Name: - <%= @category.name %> -

    +<%= render partial: 'shared/products' %> <%= link_to 'Edit', edit_category_path(@category) %> | <%= link_to 'Back', categories_path %> From 919056cc2c5e2e4a0fc96e46ef1ff2111d2f80eb Mon Sep 17 00:00:00 2001 From: Kelly Date: Fri, 11 Dec 2015 11:39:44 -0800 Subject: [PATCH 098/299] add category name uniqueness validation --- app/models/category.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/category.rb b/app/models/category.rb index ffcf81213b..737e221b2e 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -1,4 +1,5 @@ class Category < ActiveRecord::Base has_and_belongs_to_many :products + validates :name, uniqueness: true validates :name, presence: true end From 43c7f51db3856e50a6d10b6c745a50ac80e3b0b9 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Fri, 11 Dec 2015 12:24:10 -0800 Subject: [PATCH 099/299] create review model spec --- spec/models/product_spec.rb | 5 ----- spec/models/review_spec.rb | 12 +++++++++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/spec/models/product_spec.rb b/spec/models/product_spec.rb index 1b684a7330..cc4c15297b 100644 --- a/spec/models/product_spec.rb +++ b/spec/models/product_spec.rb @@ -8,11 +8,6 @@ it { is_expected.to validate_presence_of(:name) } it { is_expected.to validate_presence_of(:price) } - # it "must have a name and price" do - # expect(Product.new(name: "a")).to_not be_valid - # expect(Product.new(price: 15)).to_not be_valid - # expect(Product.new(name: "a", price: 15)).to be_valid - # end it "must have a unique name" do Product.create(name: "a", price: 10) expect(Product.new(name: "a", price: 10)).to_not be_valid diff --git a/spec/models/review_spec.rb b/spec/models/review_spec.rb index c298a1febe..baff1b73b1 100644 --- a/spec/models/review_spec.rb +++ b/spec/models/review_spec.rb @@ -1,7 +1,13 @@ require 'rails_helper' RSpec.describe Review, type: :model do - let(:sample_product) { - Product.create(name: "Water bottle", price: 10 ) - } + describe ".validates" do + it { is_expected.to validate_presence_of(:rating) } + it "requires a rating in correct range" do + expect(Review.new(rating: 5)).to be_valid + expect(Review.new(rating: 0)).to be_invalid + expect(Review.new(rating: 6)).to be_invalid + end + end + end From 94495cc3b925579961e3df37d925fa140e907b02 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Fri, 11 Dec 2015 12:26:28 -0800 Subject: [PATCH 100/299] test for welcome controller --- spec/controllers/welcome_controller_spec.rb | 24 ++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/spec/controllers/welcome_controller_spec.rb b/spec/controllers/welcome_controller_spec.rb index d77cd0e594..133f9e71ec 100644 --- a/spec/controllers/welcome_controller_spec.rb +++ b/spec/controllers/welcome_controller_spec.rb @@ -1,12 +1,12 @@ -# require 'rails_helper' -# -# RSpec.describe WelcomeController, type: :controller do -# -# describe "GET #index" do -# it "returns http success" do -# get :index -# expect(response).to have_http_status(:success) -# end -# end -# -# end +require 'rails_helper' + +RSpec.describe WelcomeController, type: :controller do + + describe "GET #index" do + it "returns http success" do + get :index + expect(response).to have_http_status(:success) + end + end + +end From 861cc83f281a67390953ecf05db094995ce78f4c Mon Sep 17 00:00:00 2001 From: Kelly Date: Fri, 11 Dec 2015 13:45:44 -0800 Subject: [PATCH 101/299] Add stock validation in Product model --- app/models/product.rb | 3 ++- spec/models/order_spec.rb | 35 +++++++++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/app/models/product.rb b/app/models/product.rb index a11451f2b7..65be9e768b 100644 --- a/app/models/product.rb +++ b/app/models/product.rb @@ -6,9 +6,10 @@ class Product < ActiveRecord::Base validates :name, :price, presence: true validates :name, uniqueness: true - validates_numericality_of :price, :greater_than => 0 + validates_numericality_of :price, :stock, :greater_than => 0 validates :photo_url, format: {with: /\.(png|jpg)\Z/i}, allow_nil: true + def review_average if reviews.any? total = reviews.inject(0) { |sum, review| sum + review.rating } diff --git a/spec/models/order_spec.rb b/spec/models/order_spec.rb index 412f61c081..1e427ff23e 100644 --- a/spec/models/order_spec.rb +++ b/spec/models/order_spec.rb @@ -1,5 +1,32 @@ -# require 'rails_helper' -# -# RSpec.describe Order, type: :model do -# pending "add some examples to (or delete) #{__FILE__}" +require 'rails_helper' + +RSpec.describe Order, type: :model do + let (:sample_order) { + Order.create + } + + describe ".validates" do + + end +end + +# class Order < ActiveRecord::Base +# has_many :order_items +# validates_numericality_of :zip, :cc_num, allow_nil: true +# validates_length_of :zip, is: 5, allow_nil: true +# validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i }, allow_nil: true +# end + +# create_table "orders", force: :cascade do |t| +# t.string "email" +# t.string "street" +# t.string "city" +# t.string "state" +# t.string "zip" +# t.string "cc_num" +# t.date "cc_exp" +# t.integer "cc_cvv" +# t.string "cc_name" +# t.datetime "created_at", null: false +# t.datetime "updated_at", null: false # end From ff78f694b8665a01e8b9368f211de5c0946d7729 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Fri, 11 Dec 2015 15:23:25 -0800 Subject: [PATCH 102/299] create seeds for categories --- db/seeds.rb | 34 ++++++++++++++++++++-------------- seeds_csvs/categories.csv | 11 +++++++++++ 2 files changed, 31 insertions(+), 14 deletions(-) create mode 100644 seeds_csvs/categories.csv diff --git a/db/seeds.rb b/db/seeds.rb index fdebd195a4..18d183fe1c 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -7,8 +7,10 @@ # Mayor.create(name: 'Emanuel', city: cities.first) require 'csv' +require 'pry' tables = { + "Category" => './seeds_csvs/categories.csv', "Order" => './seeds_csvs/orders.csv', "Product" => './seeds_csvs/products.csv', "User" => './seeds_csvs/users.csv', @@ -16,19 +18,23 @@ 'OrderItem' => './seeds_csvs/order_items.csv' } - tables.each do |k, v| - data = CSV.read(v, :headers => true, :header_converters => :symbol).map{ |row| row.to_hash } - data.each do |info| - if k == "Order" - Order.create(info) - elsif k == "Product" - Product.create(info) - elsif k == "User" - User.create(info) - elsif k == "Review" - Review.create(info) - elsif k == "OrderItem" - OrderItem.create(info) - end +tables.each do |k, v| + data = CSV.read(v, :headers => true, :header_converters => :symbol).map{ |row| row.to_hash } + data.each do |info| + if k == "Order" + Order.create(info) + elsif k == "Category" + Category.create(info) + elsif k == "Product" + p = Product.create(info) + a = Array.new(rand(1..5)){ |i| i = rand(1..10) } + p.categories << Category.find(a.uniq) + elsif k == "User" + User.create(info) + elsif k == "Review" + Review.create(info) + elsif k == "OrderItem" + OrderItem.create(info) end end +end diff --git a/seeds_csvs/categories.csv b/seeds_csvs/categories.csv new file mode 100644 index 0000000000..167fb133fd --- /dev/null +++ b/seeds_csvs/categories.csv @@ -0,0 +1,11 @@ +name +toys +pool +bath +ocean +movie +dvd +beach +fog +mist +wet From 7651f34a9e4682e5aa8b80307d298b3ccd5f09bf Mon Sep 17 00:00:00 2001 From: Kelly Date: Fri, 11 Dec 2015 15:25:25 -0800 Subject: [PATCH 103/299] Add numericality test for model/order_spec --- app/controllers/reviews_controller.rb | 4 ++-- app/controllers/sessions_controller.rb | 1 + spec/models/order_spec.rb | 8 +++++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb index 45a4a3672c..d611a6c1f0 100644 --- a/app/controllers/reviews_controller.rb +++ b/app/controllers/reviews_controller.rb @@ -25,7 +25,7 @@ def create r.product_id = params[:product_id] end if @review.save - redirect_to user_product_reviews_path(@review.product.user, @review.product, @review) + redirect_to user_product_reviews_path(@review.product.user, @review.product) else render :new end @@ -34,7 +34,7 @@ def create def update if @review.update(review_params) - redirect_to user_product_reviews_path(@review.product.user, @review.product, @review) + redirect_to user_product_reviews_path(@review.product.user, @review.product) else render :edit end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 1b484ebd90..65dcd6b0d4 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -1,6 +1,7 @@ class SessionsController < ApplicationController def new + 1 + 1 end def create diff --git a/spec/models/order_spec.rb b/spec/models/order_spec.rb index 1e427ff23e..bb2b187336 100644 --- a/spec/models/order_spec.rb +++ b/spec/models/order_spec.rb @@ -1,11 +1,13 @@ require 'rails_helper' RSpec.describe Order, type: :model do - let (:sample_order) { - Order.create - } + # let (:sample_order) { + # Order.create(zip: "02780") + # } describe ".validates" do + it { is_expected.to validate_numericality_of(:zip) } + it { is_expected.to validate_numericality_of(:cc_num) } end end From 6ffddabf0cb6ac11203c0eb4d81c8b47fa3db6b9 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Fri, 11 Dec 2015 15:32:39 -0800 Subject: [PATCH 104/299] fix validation of product with negative stock --- spec/models/product_spec.rb | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/spec/models/product_spec.rb b/spec/models/product_spec.rb index cc4c15297b..e6a3178181 100644 --- a/spec/models/product_spec.rb +++ b/spec/models/product_spec.rb @@ -2,23 +2,26 @@ RSpec.describe Product, type: :model do let(:sample_product) { - Product.create(name: "Water bottle", price: 10 ) + Product.create(name: "Water bottle", price: 10, stock: 5 ) } describe ".validates" do it { is_expected.to validate_presence_of(:name) } it { is_expected.to validate_presence_of(:price) } it "must have a unique name" do - Product.create(name: "a", price: 10) - expect(Product.new(name: "a", price: 10)).to_not be_valid + Product.create(name: "a", price: 10, stock: 5) + expect(Product.new(name: "a", price: 10, stock: 5)).to_not be_valid end it "must have a numerical price" do - expect(Product.new(name: "a", price: "a")).to_not be_valid + expect(Product.new(name: "a", price: "a", stock: 5)).to_not be_valid end it "must have a price greater than 0" do expect(Product.new(name: "a", price: -1)).to_not be_valid expect(Product.new(name: "a", price: 0)).to_not be_valid end + it "must have a stock greater or equal to 0" do + expect(Product.new(name: "a", price: 5, stock: -1)).to_not be_valid + end it "must have an image url ending in jpg or png" do sample_product.photo_url = "image.jpg" expect(sample_product).to be_valid From ff6a9d832d582e2c2d51384e65915a0bb15a763e Mon Sep 17 00:00:00 2001 From: Kelly Date: Fri, 11 Dec 2015 15:33:57 -0800 Subject: [PATCH 105/299] remove 1+1 from sessions controller --- app/controllers/sessions_controller.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 65dcd6b0d4..1b484ebd90 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -1,7 +1,6 @@ class SessionsController < ApplicationController def new - 1 + 1 end def create From 4b5132cb54e089e9a1aeb8e144df3e68a5915e8c Mon Sep 17 00:00:00 2001 From: Kelly Date: Fri, 11 Dec 2015 15:59:16 -0800 Subject: [PATCH 106/299] Complete tests in model/order_spec --- spec/models/order_spec.rb | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/spec/models/order_spec.rb b/spec/models/order_spec.rb index bb2b187336..46b0928484 100644 --- a/spec/models/order_spec.rb +++ b/spec/models/order_spec.rb @@ -1,34 +1,20 @@ require 'rails_helper' RSpec.describe Order, type: :model do - # let (:sample_order) { - # Order.create(zip: "02780") - # } - describe ".validates" do it { is_expected.to validate_numericality_of(:zip) } it { is_expected.to validate_numericality_of(:cc_num) } - + it { is_expected.to validate_length_of(:zip) } + + it "must have a nil or valid email " do + expect(Order.create(email: 'user@foo,com')).to_not be_valid + expect(Order.create(email: 'user_at_foo.org')).to_not be_valid + expect(Order.create(email: 'example.user@foo.')).to_not be_valid + expect(Order.create(email: 'foo@bar_baz.com')).to_not be_valid + expect(Order.create(email: 'foo@bar+baz.com')).to_not be_valid + expect(Order.create(email: ' ')).to_not be_valid + expect(Order.create(email: 'kelly@kelly.com')).to be_valid + expect(Order.create(email: nil)).to be_valid + end end end - -# class Order < ActiveRecord::Base -# has_many :order_items -# validates_numericality_of :zip, :cc_num, allow_nil: true -# validates_length_of :zip, is: 5, allow_nil: true -# validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i }, allow_nil: true -# end - -# create_table "orders", force: :cascade do |t| -# t.string "email" -# t.string "street" -# t.string "city" -# t.string "state" -# t.string "zip" -# t.string "cc_num" -# t.date "cc_exp" -# t.integer "cc_cvv" -# t.string "cc_name" -# t.datetime "created_at", null: false -# t.datetime "updated_at", null: false -# end From 20c06033b52880c289182c088cfc7f7bcd998f9c Mon Sep 17 00:00:00 2001 From: Tammy Date: Sun, 13 Dec 2015 12:33:15 -0800 Subject: [PATCH 107/299] working on rspec user model --- app/views/categories/index.html.erb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/categories/index.html.erb b/app/views/categories/index.html.erb index f0e18cca21..3e2834c40f 100644 --- a/app/views/categories/index.html.erb +++ b/app/views/categories/index.html.erb @@ -25,3 +25,4 @@
    <%= link_to 'New Category', new_category_path %> +<%= link_to 'All Categories', categories_path %> From ae926a060ad1604b437dacac068ce3183b3dcb6b Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Sun, 13 Dec 2015 12:48:17 -0800 Subject: [PATCH 108/299] start working on reviews controller specs --- spec/controllers/reviews_controller_spec.rb | 153 +++++++++++++++----- 1 file changed, 114 insertions(+), 39 deletions(-) diff --git a/spec/controllers/reviews_controller_spec.rb b/spec/controllers/reviews_controller_spec.rb index b6a992e02a..a1b3bca463 100644 --- a/spec/controllers/reviews_controller_spec.rb +++ b/spec/controllers/reviews_controller_spec.rb @@ -1,48 +1,123 @@ -# 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 ReviewsController, type: :controller do +require 'rails_helper' +require 'pry' +# +# 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 ReviewsController, type: :controller do # # # This should return the minimal set of attributes required to create a valid # # Review. As you add validations to Review, be sure to # # adjust the attributes here as well. -# let(:valid_attributes) { -# skip("Add a hash of attributes valid for your model") -# } -# -# let(:invalid_attributes) { -# skip("Add a hash of attributes invalid for your model") -# } -# + let(:valid_attributes) { + { rating: 4, + description: "Great!"} + } + + let(:invalid_attributes) { + { description: "The worst"} + } + # # 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 # # ReviewsController. Be sure to keep this updated too. -# let(:valid_session) { {} } -# -# describe "GET #index" do -# it "assigns all reviews as @reviews" do -# review = Review.create! valid_attributes -# get :index, {}, valid_session -# expect(assigns(:reviews)).to eq([review]) -# end -# end + let(:valid_session) { {} } + + describe "GET 'index'" do + it "is successful" do + get :index + expect(response.status).to eq 200 + end + end + + describe "GET 'new'" do + it "renders the new page" do + get :new + expect(subject).to render_template :new + end + end + + describe "GET 'edit'" do + it "renders edit page" do + new_review = Review.create(valid_attributes) + get :edit, id: new_review.id + expect(subject).to render_template :edit + end + end + + # describe "GET 'show'" do + # it "renders show page" do + # new_medium = Review.create(title: "Hello, World!", creator: "Jennie") + # get :show, id: new_medium.id + # expect(subject).to render_template :show, id: new_medium.id + # end + # end + # + # describe "POST 'create'" do + # it "redirects to show on success" do + # post :create, good_params + # new_medium = Review.last + # expect(subject).to redirect_to polymorphic_path(new_medium) # need to fix this path + # end + # it "renders new on fail" do + # post :create, bad_params + # expect(subject).to render_template :new + # end + # end + # + # describe "PATCH 'update'" do + # let (:new_medium) do + # Review.create(title: "Hello, World!", creator: "Jennie") + # end + # it "redirects to album on success" do + # patch :update, update_params + # expect(subject).to redirect_to polymorphic_path(new_medium) # need to fix this path + # end + # it "renders edit template on fail" do + # patch :update, bad_update_params + # expect(subject).to render_template (:edit) + # end + # end + # + # describe "DELETE 'destroy'" do + # it "redirects to index on delete" do + # new_medium = Review.create(title: "Hello, World!", creator: "Jennie") + # delete :destroy, id: new_medium.id + # expect(subject).to redirect_to polymorphic_path(Review.name.downcase.pluralize) # need to fix this path + # end + # end + # + # describe "POST 'upvote'" do + # it "redirects to show page" do + # new_medium = Review.create(title: "Hello, World!", creator: "Jennie") + # post :upvote, id: new_medium.id + # expect(subject).to redirect_to polymorphic_path(new_medium) # need to fix this path + # end + # end + + # describe "GET #index" do + # it "assigns all reviews as @reviews" do + # review = Review.create! valid_attributes + # get :index + # binding.pry + # expect(assigns(:reviews)).to eq([review]) + # end + # end # # describe "GET #show" do # it "assigns the requested review as @review" do @@ -156,4 +231,4 @@ # end # end # -# end +end From 9db6aa315a1c1bb1e15f35e99fc16bcef746292d Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Sun, 13 Dec 2015 13:40:29 -0800 Subject: [PATCH 109/299] first test working with factorygirl --- Gemfile | 1 + Gemfile.lock | 8 ++++- spec/controllers/reviews_controller_spec.rb | 37 ++++++++++++--------- spec/factories.rb | 33 ++++++++++++++++++ 4 files changed, 63 insertions(+), 16 deletions(-) create mode 100644 spec/factories.rb diff --git a/Gemfile b/Gemfile index c3eacacfab..9bce13d60b 100644 --- a/Gemfile +++ b/Gemfile @@ -44,6 +44,7 @@ end group :test do gem 'shoulda-matchers', '~> 3.0' + gem "factory_girl_rails", "~> 4.0" end group :development, :test do diff --git a/Gemfile.lock b/Gemfile.lock index bceaf62f4c..66aca29fc2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -66,6 +66,11 @@ GEM docile (1.1.5) erubis (2.7.0) execjs (2.6.0) + factory_girl (4.5.0) + activesupport (>= 3.0.0) + factory_girl_rails (4.5.0) + factory_girl (~> 4.5.0) + railties (>= 3.0.0) globalid (0.3.6) activesupport (>= 4.1.0) i18n (0.7.0) @@ -195,6 +200,7 @@ DEPENDENCIES bootstrap-sass (~> 3.3.5) byebug coffee-rails (~> 4.1.0) + factory_girl_rails (~> 4.0) jbuilder (~> 2.0) jquery-rails pg @@ -213,4 +219,4 @@ DEPENDENCIES will_paginate BUNDLED WITH - 1.10.6 + 1.11.0 diff --git a/spec/controllers/reviews_controller_spec.rb b/spec/controllers/reviews_controller_spec.rb index a1b3bca463..fa09a9291c 100644 --- a/spec/controllers/reviews_controller_spec.rb +++ b/spec/controllers/reviews_controller_spec.rb @@ -33,32 +33,39 @@ { description: "The worst"} } + let(:review) { FactoryGirl.create(:review )} + # # 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 # # ReviewsController. Be sure to keep this updated too. - let(:valid_session) { {} } + # let(:valid_session) { {} } describe "GET 'index'" do it "is successful" do - get :index + # review = FactoryGirl.create(:review) + get :index, product_id: review.product_id, user_id: review.product.user_id expect(response.status).to eq 200 end - end - - describe "GET 'new'" do - it "renders the new page" do - get :new - expect(subject).to render_template :new + it "assigns all reviews as @reviews" do + get :index, product_id: review.product_id, user_id: review.product.user_id + expect(assigns(:reviews)).to eq([review]) end end - describe "GET 'edit'" do - it "renders edit page" do - new_review = Review.create(valid_attributes) - get :edit, id: new_review.id - expect(subject).to render_template :edit - end - end + # describe "GET 'new'" do + # it "renders the new page" do + # get :new + # expect(subject).to render_template :new + # end + # end + # + # describe "GET 'edit'" do + # it "renders edit page" do + # new_review = Review.create(valid_attributes) + # get :edit, id: new_review.id + # expect(subject).to render_template :edit + # end + # end # describe "GET 'show'" do # it "renders show page" do diff --git a/spec/factories.rb b/spec/factories.rb new file mode 100644 index 0000000000..1c69cc8a26 --- /dev/null +++ b/spec/factories.rb @@ -0,0 +1,33 @@ +FactoryGirl.define do + factory :user do + username "foo" + email { "#{username}@example.com" } + password "foobar" + password_confirmation "foobar" + end + + factory :product do + name "Water Noodle" + price 500 + stock 10 + end + + factory :order do + + end + + factory :review do + rating 4 + association :product, :factory => :product, :user_id => 1 + end + + factory :orderitem do + + end + + factory :category do + name "toy" + product + end + +end From 5a40fb451021d562f01b4ebc4639cabd56a21fcf Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Sun, 13 Dec 2015 14:10:40 -0800 Subject: [PATCH 110/299] complete create test for reviews controller --- spec/controllers/reviews_controller_spec.rb | 97 ++++++++++++--------- spec/factories.rb | 3 +- 2 files changed, 57 insertions(+), 43 deletions(-) diff --git a/spec/controllers/reviews_controller_spec.rb b/spec/controllers/reviews_controller_spec.rb index fa09a9291c..e9854c0543 100644 --- a/spec/controllers/reviews_controller_spec.rb +++ b/spec/controllers/reviews_controller_spec.rb @@ -24,16 +24,24 @@ # # This should return the minimal set of attributes required to create a valid # # Review. As you add validations to Review, be sure to # # adjust the attributes here as well. - let(:valid_attributes) { - { rating: 4, - description: "Great!"} - } + # let(:user) { FactoryGirl.create(:user) } + # let(:product) { FactoryGirl.create(:product) } + let(:review) { FactoryGirl.create(:review) } - let(:invalid_attributes) { - { description: "The worst"} + let(:valid_create_attributes) { + { + user_id: review.product.user_id, + product_id: review.product_id, + review: { rating: 4, description: "Great!" }} } - let(:review) { FactoryGirl.create(:review )} + let(:invalid_create_attributes) { + { + user_id: review.product.user_id, + product_id: review.product_id, + review: { description: "The worst"} + } + } # # 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 @@ -42,7 +50,6 @@ describe "GET 'index'" do it "is successful" do - # review = FactoryGirl.create(:review) get :index, product_id: review.product_id, user_id: review.product.user_id expect(response.status).to eq 200 end @@ -52,41 +59,47 @@ end end - # describe "GET 'new'" do - # it "renders the new page" do - # get :new - # expect(subject).to render_template :new - # end - # end - # - # describe "GET 'edit'" do - # it "renders edit page" do - # new_review = Review.create(valid_attributes) - # get :edit, id: new_review.id - # expect(subject).to render_template :edit - # end - # end + describe "GET 'new'" do + it "renders the new page" do + get :new, product_id: review.product_id, user_id: review.product.user_id + expect(subject).to render_template :new + end + end + + describe "GET 'edit'" do + it "renders edit page" do + get :edit, product_id: review.product_id, user_id: review.product.user_id, id: review.id + expect(subject).to render_template :edit + end + end + + describe "GET 'show'" do + it "renders show page" do + get :show, product_id: review.product_id, user_id: review.product.user_id, id: review.id + expect(subject).to render_template :show, product_id: review.product_id, user_id: review.product.user_id, id: review.id + end + end + + describe "POST 'create'" do + let(:product) { FactoryGirl.create(:product) } + let(:valid_create_attributes) { + { + user_id: product.user_id, + product_id: product.id, + review: { rating: 4, description: "Great!" }} + } + it "redirects to index on success" do + binding.pry + post :create, valid_create_attributes + new_review = Review.last + expect(subject).to redirect_to user_product_reviews_path(new_review.product.user_id, new_review.product_id) + end + it "renders new on fail" do + post :create, invalid_create_attributes + expect(subject).to render_template :new + end + end - # describe "GET 'show'" do - # it "renders show page" do - # new_medium = Review.create(title: "Hello, World!", creator: "Jennie") - # get :show, id: new_medium.id - # expect(subject).to render_template :show, id: new_medium.id - # end - # end - # - # describe "POST 'create'" do - # it "redirects to show on success" do - # post :create, good_params - # new_medium = Review.last - # expect(subject).to redirect_to polymorphic_path(new_medium) # need to fix this path - # end - # it "renders new on fail" do - # post :create, bad_params - # expect(subject).to render_template :new - # end - # end - # # describe "PATCH 'update'" do # let (:new_medium) do # Review.create(title: "Hello, World!", creator: "Jennie") diff --git a/spec/factories.rb b/spec/factories.rb index 1c69cc8a26..833f7534f4 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -10,6 +10,7 @@ name "Water Noodle" price 500 stock 10 + association :user end factory :order do @@ -18,7 +19,7 @@ factory :review do rating 4 - association :product, :factory => :product, :user_id => 1 + association :product end factory :orderitem do From 445e8f63222fbae73391c98cacacf1a8e8592de2 Mon Sep 17 00:00:00 2001 From: Kelly Date: Sun, 13 Dec 2015 14:12:58 -0800 Subject: [PATCH 111/299] update spec_helper with '/support/' filter --- spec/spec_helper.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 7c1a15ce54..13cf12afe8 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,5 +1,8 @@ require 'simplecov' -SimpleCov.start +require 'rails_helper' +SimpleCov.start do + add_filter '/support/' +end # This file was generated by the `rails generate rspec:install` command. Conventionally, all # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. From 44e73d5000083369b37f6dae5f07f4dc6703333d Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Sun, 13 Dec 2015 14:20:23 -0800 Subject: [PATCH 112/299] complete update tests for reviews controller --- spec/controllers/reviews_controller_spec.rb | 73 ++++++++++----------- 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/spec/controllers/reviews_controller_spec.rb b/spec/controllers/reviews_controller_spec.rb index e9854c0543..52cfae22c3 100644 --- a/spec/controllers/reviews_controller_spec.rb +++ b/spec/controllers/reviews_controller_spec.rb @@ -28,21 +28,6 @@ # let(:product) { FactoryGirl.create(:product) } let(:review) { FactoryGirl.create(:review) } - let(:valid_create_attributes) { - { - user_id: review.product.user_id, - product_id: review.product_id, - review: { rating: 4, description: "Great!" }} - } - - let(:invalid_create_attributes) { - { - user_id: review.product.user_id, - product_id: review.product_id, - review: { description: "The worst"} - } - } - # # 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 # # ReviewsController. Be sure to keep this updated too. @@ -88,8 +73,14 @@ product_id: product.id, review: { rating: 4, description: "Great!" }} } - it "redirects to index on success" do - binding.pry + let(:invalid_create_attributes) { + { + user_id: product.user_id, + product_id: product.id, + review: { description: "The worst"} + } + } + it "redirects to user_product_reviews on success" do post :create, valid_create_attributes new_review = Review.last expect(subject).to redirect_to user_product_reviews_path(new_review.product.user_id, new_review.product_id) @@ -100,20 +91,32 @@ end end - # describe "PATCH 'update'" do - # let (:new_medium) do - # Review.create(title: "Hello, World!", creator: "Jennie") - # end - # it "redirects to album on success" do - # patch :update, update_params - # expect(subject).to redirect_to polymorphic_path(new_medium) # need to fix this path - # end - # it "renders edit template on fail" do - # patch :update, bad_update_params - # expect(subject).to render_template (:edit) - # end - # end - # + describe "PATCH 'update'" do + let(:valid_update_attributes) { + { + id: review.id, + user_id: review.product.user_id, + product_id: review.product.id, + review: { rating: 4, description: "Great!" }} + } + let(:invalid_update_attributes) { + { + id: review.id, + user_id: review.product.user_id, + product_id: review.product.id, + review: { rating: -1 } + } + } + it "redirects to user_product_reviews on success" do + patch :update, valid_update_attributes + expect(subject).to redirect_to user_product_reviews_path(review.product.user_id, review.product_id) + end + it "renders edit template on fail" do + patch :update, invalid_update_attributes + expect(subject).to render_template (:edit) + end + end + # describe "DELETE 'destroy'" do # it "redirects to index on delete" do # new_medium = Review.create(title: "Hello, World!", creator: "Jennie") @@ -121,14 +124,6 @@ # expect(subject).to redirect_to polymorphic_path(Review.name.downcase.pluralize) # need to fix this path # end # end - # - # describe "POST 'upvote'" do - # it "redirects to show page" do - # new_medium = Review.create(title: "Hello, World!", creator: "Jennie") - # post :upvote, id: new_medium.id - # expect(subject).to redirect_to polymorphic_path(new_medium) # need to fix this path - # end - # end # describe "GET #index" do # it "assigns all reviews as @reviews" do From fe361654f5c7aea1c8886a0cad6810329bb61ac6 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Sun, 13 Dec 2015 14:26:22 -0800 Subject: [PATCH 113/299] complete destroy test for review controller --- app/controllers/reviews_controller.rb | 2 +- spec/controllers/reviews_controller_spec.rb | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb index d611a6c1f0..63d88e6dc0 100644 --- a/app/controllers/reviews_controller.rb +++ b/app/controllers/reviews_controller.rb @@ -43,7 +43,7 @@ def update def destroy @review.destroy - redirect_to user_product_reviews_path(@review.product.user, @review.product, @review) + redirect_to user_product_reviews_path(@review.product.user, @review.product) end private diff --git a/spec/controllers/reviews_controller_spec.rb b/spec/controllers/reviews_controller_spec.rb index 52cfae22c3..94d3ea1d19 100644 --- a/spec/controllers/reviews_controller_spec.rb +++ b/spec/controllers/reviews_controller_spec.rb @@ -117,13 +117,12 @@ end end - # describe "DELETE 'destroy'" do - # it "redirects to index on delete" do - # new_medium = Review.create(title: "Hello, World!", creator: "Jennie") - # delete :destroy, id: new_medium.id - # expect(subject).to redirect_to polymorphic_path(Review.name.downcase.pluralize) # need to fix this path - # end - # end + describe "DELETE 'destroy'" do + it "redirects to user_product_reviews on delete" do + delete :destroy, id: review.id, user_id: review.product.user_id, product_id: review.product_id + expect(subject).to redirect_to user_product_reviews_path(review.product.user_id, review.product_id) + end + end # describe "GET #index" do # it "assigns all reviews as @reviews" do From d963ccdedcd50d7b7ee085da751d25bc395cc2b4 Mon Sep 17 00:00:00 2001 From: Kelly Date: Sun, 13 Dec 2015 16:16:10 -0800 Subject: [PATCH 114/299] Add rspec tests for orders controller --- app/controllers/orders_controller.rb | 1 - spec/controllers/orders_controller_spec.rb | 256 ++++++++------------- 2 files changed, 97 insertions(+), 160 deletions(-) diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index 90a7450787..93f239aa45 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -12,7 +12,6 @@ def show end def new - c @order = Order.new end diff --git a/spec/controllers/orders_controller_spec.rb b/spec/controllers/orders_controller_spec.rb index 6e3907463e..0c719cbfcf 100644 --- a/spec/controllers/orders_controller_spec.rb +++ b/spec/controllers/orders_controller_spec.rb @@ -1,159 +1,97 @@ -# 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 OrdersController, type: :controller do -# -# # This should return the minimal set of attributes required to create a valid -# # Order. As you add validations to Order, be sure to -# # adjust the attributes here as well. -# let(:valid_attributes) { -# skip("Add a hash of attributes valid for your model") -# } -# -# let(:invalid_attributes) { -# skip("Add a hash of attributes invalid for your model") -# } -# -# # 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 -# # OrdersController. Be sure to keep this updated too. -# let(:valid_session) { {} } -# -# describe "GET #index" do -# it "assigns all orders as @orders" do -# order = Order.create! valid_attributes -# get :index, {}, valid_session -# expect(assigns(:orders)).to eq([order]) -# end -# end -# -# describe "GET #show" do -# it "assigns the requested order as @order" do -# order = Order.create! valid_attributes -# get :show, {:id => order.to_param}, valid_session -# expect(assigns(:order)).to eq(order) -# end -# end -# -# describe "GET #new" do -# it "assigns a new order as @order" do -# get :new, {}, valid_session -# expect(assigns(:order)).to be_a_new(Order) -# end -# end -# -# describe "GET #edit" do -# it "assigns the requested order as @order" do -# order = Order.create! valid_attributes -# get :edit, {:id => order.to_param}, valid_session -# expect(assigns(:order)).to eq(order) -# end -# end -# -# describe "POST #create" do -# context "with valid params" do -# it "creates a new Order" do -# expect { -# post :create, {:order => valid_attributes}, valid_session -# }.to change(Order, :count).by(1) -# end -# -# it "assigns a newly created order as @order" do -# post :create, {:order => valid_attributes}, valid_session -# expect(assigns(:order)).to be_a(Order) -# expect(assigns(:order)).to be_persisted -# end -# -# it "redirects to the created order" do -# post :create, {:order => valid_attributes}, valid_session -# expect(response).to redirect_to(Order.last) -# end -# end -# -# context "with invalid params" do -# it "assigns a newly created but unsaved order as @order" do -# post :create, {:order => invalid_attributes}, valid_session -# expect(assigns(:order)).to be_a_new(Order) -# end -# -# it "re-renders the 'new' template" do -# post :create, {:order => invalid_attributes}, valid_session -# expect(response).to render_template("new") -# end -# end -# end -# -# describe "PUT #update" do -# context "with valid params" do -# let(:new_attributes) { -# skip("Add a hash of attributes valid for your model") -# } -# -# it "updates the requested order" do -# order = Order.create! valid_attributes -# put :update, {:id => order.to_param, :order => new_attributes}, valid_session -# order.reload -# skip("Add assertions for updated state") -# end -# -# it "assigns the requested order as @order" do -# order = Order.create! valid_attributes -# put :update, {:id => order.to_param, :order => valid_attributes}, valid_session -# expect(assigns(:order)).to eq(order) -# end -# -# it "redirects to the order" do -# order = Order.create! valid_attributes -# put :update, {:id => order.to_param, :order => valid_attributes}, valid_session -# expect(response).to redirect_to(order) -# end -# end -# -# context "with invalid params" do -# it "assigns the order as @order" do -# order = Order.create! valid_attributes -# put :update, {:id => order.to_param, :order => invalid_attributes}, valid_session -# expect(assigns(:order)).to eq(order) -# end -# -# it "re-renders the 'edit' template" do -# order = Order.create! valid_attributes -# put :update, {:id => order.to_param, :order => invalid_attributes}, valid_session -# expect(response).to render_template("edit") -# end -# end -# end -# -# describe "DELETE #destroy" do -# it "destroys the requested order" do -# order = Order.create! valid_attributes -# expect { -# delete :destroy, {:id => order.to_param}, valid_session -# }.to change(Order, :count).by(-1) -# end -# -# it "redirects to the orders list" do -# order = Order.create! valid_attributes -# delete :destroy, {:id => order.to_param}, valid_session -# expect(response).to redirect_to(orders_url) -# end -# end -# -# end +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 OrdersController, type: :controller do + + # This should return the minimal set of attributes required to create a valid + # Order. As you add validations to Order, be sure to + # adjust the attributes here as well. + + let (:sample_order) { + Order.create + } + + let (:bad_params) { + { + order: { zip: "zzz" } + } + } + + describe "GET 'index'" do + it "is successful" do + get :index + expect(response.status).to eq 200 + end + end + + describe "GET 'show'" do + it "renders the show view" do + get :show, id: sample_order.id + expect(subject).to render_template :show + end + end + + describe "GET 'new'" do + it "renders new view" do + get :new + expect(subject).to render_template :new + end + end + + describe "POST 'create'" do + it "redirects to index page" do + post :create + expect(subject).to redirect_to orders_path + end + + it "renders new template on error" do + post :create, bad_params + expect(subject).to render_template :new + end + end + + describe "GET 'edit'" do + it "renders edit view" do + get :edit, id: sample_order.id + expect(subject).to render_template :edit + end + end + + describe "PATCH 'update'" do + it "redirects to index page" do + patch :update, { order: { zip: "02780" } } + expect(subject).to redirect_to orders_path + expect(Order.all.last.zip).to eq "02780" + end + + it "renders edit template on error" do + patch :update, bad_params + expect(subject).to render_template :edit + expect(Order.all.last.zip).to eq nil + end + end + + describe "DELETE 'destroy'" do + it "redirects to index page" do + delete :destroy, id: sample_order.id + expect(subject).to redirect_to orders_path + end + end +end From dc9673f381f9880d45a49349bf21ea00040c6ec8 Mon Sep 17 00:00:00 2001 From: Kelly Date: Sun, 13 Dec 2015 16:49:07 -0800 Subject: [PATCH 115/299] update product model validation to allow 0 stock --- app/models/product.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/product.rb b/app/models/product.rb index 65be9e768b..d5c5d1beb2 100644 --- a/app/models/product.rb +++ b/app/models/product.rb @@ -6,10 +6,10 @@ class Product < ActiveRecord::Base validates :name, :price, presence: true validates :name, uniqueness: true - validates_numericality_of :price, :stock, :greater_than => 0 + validates_numericality_of :price, :greater_than => 0 + validates_numericality_of :stock, :greater_than_or_equal_to => 0 validates :photo_url, format: {with: /\.(png|jpg)\Z/i}, allow_nil: true - def review_average if reviews.any? total = reviews.inject(0) { |sum, review| sum + review.rating } From a3e717420d87b1c25b8c7ffb4a93f700d86726eb Mon Sep 17 00:00:00 2001 From: Kelly Date: Sun, 13 Dec 2015 17:57:01 -0800 Subject: [PATCH 116/299] Complete tests for products controller --- spec/controllers/orders_controller_spec.rb | 23 -- spec/controllers/products_controller_spec.rb | 242 +++++++------------ 2 files changed, 83 insertions(+), 182 deletions(-) diff --git a/spec/controllers/orders_controller_spec.rb b/spec/controllers/orders_controller_spec.rb index 0c719cbfcf..51670cd9b8 100644 --- a/spec/controllers/orders_controller_spec.rb +++ b/spec/controllers/orders_controller_spec.rb @@ -1,29 +1,6 @@ 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 OrdersController, type: :controller do - - # This should return the minimal set of attributes required to create a valid - # Order. As you add validations to Order, be sure to - # adjust the attributes here as well. - let (:sample_order) { Order.create } diff --git a/spec/controllers/products_controller_spec.rb b/spec/controllers/products_controller_spec.rb index 0ce390873b..631a45875c 100644 --- a/spec/controllers/products_controller_spec.rb +++ b/spec/controllers/products_controller_spec.rb @@ -1,159 +1,83 @@ -# 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 ProductsController, type: :controller do -# -# # This should return the minimal set of attributes required to create a valid -# # Product. As you add validations to Product, be sure to -# # adjust the attributes here as well. -# let(:valid_attributes) { -# skip("Add a hash of attributes valid for your model") -# } -# -# let(:invalid_attributes) { -# skip("Add a hash of attributes invalid for your model") -# } -# -# # 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 -# # ProductsController. Be sure to keep this updated too. -# let(:valid_session) { {} } -# -# describe "GET #index" do -# it "assigns all products as @products" do -# product = Product.create! valid_attributes -# get :index, {}, valid_session -# expect(assigns(:products)).to 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 -# expect(assigns(:product)).to eq(product) -# end -# end -# -# describe "GET #new" do -# it "assigns a new product as @product" do -# get :new, {}, valid_session -# expect(assigns(:product)).to 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 -# expect(assigns(:product)).to eq(product) -# end -# end -# -# describe "POST #create" do -# context "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 -# expect(assigns(:product)).to be_a(Product) -# expect(assigns(:product)).to be_persisted -# end -# -# it "redirects to the created product" do -# post :create, {:product => valid_attributes}, valid_session -# expect(response).to redirect_to(Product.last) -# end -# end -# -# context "with invalid params" do -# it "assigns a newly created but unsaved product as @product" do -# post :create, {:product => invalid_attributes}, valid_session -# expect(assigns(:product)).to be_a_new(Product) -# end -# -# it "re-renders the 'new' template" do -# post :create, {:product => invalid_attributes}, valid_session -# expect(response).to render_template("new") -# end -# end -# end -# -# describe "PUT #update" do -# context "with valid params" do -# let(:new_attributes) { -# skip("Add a hash of attributes valid for your model") -# } -# -# it "updates the requested product" do -# product = Product.create! valid_attributes -# put :update, {:id => product.to_param, :product => new_attributes}, valid_session -# product.reload -# skip("Add assertions for updated state") -# 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 -# expect(assigns(:product)).to 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 -# expect(response).to redirect_to(product) -# end -# end -# -# context "with invalid params" do -# it "assigns the product as @product" do -# product = Product.create! valid_attributes -# put :update, {:id => product.to_param, :product => invalid_attributes}, valid_session -# expect(assigns(:product)).to eq(product) -# end -# -# it "re-renders the 'edit' template" do -# product = Product.create! valid_attributes -# put :update, {:id => product.to_param, :product => invalid_attributes}, valid_session -# expect(response).to 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 -# expect(response).to redirect_to(products_url) -# end -# end -# -# end +require 'rails_helper' + +RSpec.describe ProductsController, type: :controller do + let (:sample_user) { + User.create(username: "Kelly", email: "Kelly@kelly.com", password: "password") + } + + let (:sample_product) { + Product.create(name: "Rubber ducky", price: "500", stock: "1", user_id: sample_user.id) + } + + let (:bad_params) { + { user_id: sample_user.id, + product: { price: "zzz" } + } + } + + let (:sample_category_1) { + Category.create(name: "Pool toys") + } + + let (:sample_category_2) { + Category.create(name: "Fun in the sun") + } + + let (:good_params) { + { user_id: sample_user.id, categories: [sample_category_1.id, sample_category_2.id], product: { name: "Loofah", price: "600", stock: "2", photo_url: "hi.jpg" } } + } + + describe "GET 'index'" do + it "is successful" do + get :index + expect(response.status).to eq 200 + end + end + + describe "GET 'show'" do + it "renders the show view" do + get :show, id: sample_product.id, user_id: sample_product.user_id + expect(subject).to render_template :show + end + end + + describe "GET 'new'" do + it "renders new view" do + get :new, user_id: sample_user.id + expect(subject).to render_template :new + end + end + + describe "POST 'create'" do + it "redirects to users's products page" do + post :create, good_params + expect(subject).to redirect_to user_products_path(Product.all.last.user_id) + end + + it "renders new template on error" do + post :create, bad_params + expect(subject).to render_template :new + end + end + + describe "GET 'edit'" do + it "renders edit view" do + get :edit, id: sample_product.id, user_id: sample_product.user_id + expect(subject).to render_template :edit + end + end + + describe "PATCH 'update'" do + it "redirects to users's products page" do + patch :update, good_params.merge({id: sample_product.id}) + expect(subject).to redirect_to user_products_path(sample_product.user) + expect(Product.all.last.name).to eq "Loofah" + end + + it "renders edit template on error" do + patch :update, bad_params.merge({id: sample_product.id}) + expect(subject).to render_template :edit + expect(Product.all.last.name).to eq "Rubber ducky" + end + end +end From 1908e067f42aae03593eb73a6e305237021d1d60 Mon Sep 17 00:00:00 2001 From: Tammy Date: Sun, 13 Dec 2015 19:53:01 -0800 Subject: [PATCH 117/299] finisg user model RSPEC --- app/controllers/orders_controller.rb | 1 - spec/models/user_spec.rb | 39 +++++++++------------------- 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index 90a7450787..93f239aa45 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -12,7 +12,6 @@ def show end def new - c @order = Order.new end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 474de02e39..82aabb9026 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -2,38 +2,23 @@ RSpec.describe User, type: :model do - describe ".validates" do - let(:user1) do + + let(:user1) { User.create(name: "Nemo", username: "Nemo1", email: "nemo@gmail.com", password: "123", password_confirmation: "123") - end - let(:user2) do - User.create(name: "Nemo2", username: "Nemo2", email: "nemo@gmail.com", password: "123", password_confirmation: "123") - end - it "must have a username" do - expect(User.new(username: nil)).to_not be_valid - end + } - it "must have an email" do - expect(User.new(email: nil)).to_not be_valid + describe ".validates" do + it { is_expected.to validate_presence_of(:email) } + + it "must have a unique email" do + User.create(name: "Bob", username: "bobi", email: "nemo@gmail.com", password: "333", password_confirmation: "333") + expect(User.new(name: "Nemo", username: "Nemo1", email: "nemo@gmail.com", password: "123", password_confirmation: "123")).to_not be_valid end - end - # - describe "uniqueness" do - it do - should validate_uniqueness_of(:email) + + it "must have an email format" do + expect(User.new(name: "Nemo", username: "Nemo1", email: "nemo.gmail.com", password: "123", password_confirmation: "123")).to_not be_valid end end - # it "should have uniqueness email" do - # expect validate_uniqueness_of(:email) - # end - # it "should have uniqueness email" do - # expect(:user2).to be_vaild - # end - # end - # - # - # it { validate_uniqueness_of(:email) } - # end end From 415eb19d5e746bbb88716af4789ab8e4582b8db7 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Sun, 13 Dec 2015 20:14:26 -0800 Subject: [PATCH 118/299] complete reviews controller spec --- spec/controllers/reviews_controller_spec.rb | 242 ++++++-------------- 1 file changed, 75 insertions(+), 167 deletions(-) diff --git a/spec/controllers/reviews_controller_spec.rb b/spec/controllers/reviews_controller_spec.rb index 94d3ea1d19..d6ef61c1da 100644 --- a/spec/controllers/reviews_controller_spec.rb +++ b/spec/controllers/reviews_controller_spec.rb @@ -1,38 +1,8 @@ require 'rails_helper' require 'pry' -# -# 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 ReviewsController, type: :controller do -# -# # This should return the minimal set of attributes required to create a valid -# # Review. As you add validations to Review, be sure to -# # adjust the attributes here as well. - # let(:user) { FactoryGirl.create(:user) } - # let(:product) { FactoryGirl.create(:product) } let(:review) { FactoryGirl.create(:review) } - -# # 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 -# # ReviewsController. Be sure to keep this updated too. - # let(:valid_session) { {} } - describe "GET 'index'" do it "is successful" do get :index, product_id: review.product_id, user_id: review.product.user_id @@ -49,6 +19,12 @@ get :new, product_id: review.product_id, user_id: review.product.user_id expect(subject).to render_template :new end + + it "assigns a new review as @review" do + get :new, product_id: review.product_id, user_id: review.product.user_id + expect(assigns(:review)).to be_a_new(Review) + end + end describe "GET 'edit'" do @@ -56,6 +32,12 @@ get :edit, product_id: review.product_id, user_id: review.product.user_id, id: review.id expect(subject).to render_template :edit end + + it "assigns the requested review as @review" do + get :edit, product_id: review.product_id, user_id: review.product.user_id, id: review.id + expect(assigns(:review)).to eq(review) + end + end describe "GET 'show'" do @@ -63,6 +45,12 @@ get :show, product_id: review.product_id, user_id: review.product.user_id, id: review.id expect(subject).to render_template :show, product_id: review.product_id, user_id: review.product.user_id, id: review.id end + + it "assigns the requested review as @review" do + get :show, product_id: review.product_id, user_id: review.product.user_id, id: review.id + expect(assigns(:review)).to eq(review) + end + end describe "POST 'create'" do @@ -80,14 +68,33 @@ review: { description: "The worst"} } } - it "redirects to user_product_reviews on success" do - post :create, valid_create_attributes - new_review = Review.last - expect(subject).to redirect_to user_product_reviews_path(new_review.product.user_id, new_review.product_id) + context "with valid params" do + it "redirects to user_product_reviews" do + post :create, valid_create_attributes + new_review = Review.last + expect(subject).to redirect_to user_product_reviews_path(new_review.product.user_id, new_review.product_id) + end + it "creates a new Review" do + expect { + post :create, valid_create_attributes + }.to change(Review, :count).by(1) + end + + it "assigns a newly created review as @review" do + post :create, valid_create_attributes + expect(assigns(:review)).to be_a(Review) + expect(assigns(:review)).to be_persisted + end end - it "renders new on fail" do - post :create, invalid_create_attributes - expect(subject).to render_template :new + context "with invalid params" do + it "assigns a newly created but unsaved review as @review" do + post :create, invalid_create_attributes + expect(assigns(:review)).to be_a_new(Review) + end + it "re-renders the new template" do + post :create, invalid_create_attributes + expect(subject).to render_template :new + end end end @@ -107,142 +114,43 @@ review: { rating: -1 } } } - it "redirects to user_product_reviews on success" do - patch :update, valid_update_attributes - expect(subject).to redirect_to user_product_reviews_path(review.product.user_id, review.product_id) + context "with valid params" do + # it "updates the requested review" do + # patch :update, valid_update_attributes + # review.reload + # expect(assigns(:review)).to + # end + it "assigns the requested review as @review" do + patch :update, valid_update_attributes + expect(assigns(:review)).to eq(review) + end + it "redirects to user_product_reviews" do + patch :update, valid_update_attributes + expect(subject).to redirect_to user_product_reviews_path(review.product.user_id, review.product_id) + end end - it "renders edit template on fail" do - patch :update, invalid_update_attributes - expect(subject).to render_template (:edit) + context "with invalid params" do + it "assigns the review as @review" do + patch :update, invalid_update_attributes + expect(assigns(:review)).to eq(review) + end + it "re-renders edit template" do + patch :update, invalid_update_attributes + expect(subject).to render_template (:edit) + end end end describe "DELETE 'destroy'" do - it "redirects to user_product_reviews on delete" do + # it "destroys the requested review" do + # expect { + # delete :destroy, id: review.id, user_id: review.product.user_id, product_id: review.product_id + # }.to change(Review, :count).by(-1) + # end + + it "redirects to user_product_reviews" do delete :destroy, id: review.id, user_id: review.product.user_id, product_id: review.product_id expect(subject).to redirect_to user_product_reviews_path(review.product.user_id, review.product_id) end end - - # describe "GET #index" do - # it "assigns all reviews as @reviews" do - # review = Review.create! valid_attributes - # get :index - # binding.pry - # expect(assigns(:reviews)).to eq([review]) - # end - # end -# -# describe "GET #show" do -# it "assigns the requested review as @review" do -# review = Review.create! valid_attributes -# get :show, {:id => review.to_param}, valid_session -# expect(assigns(:review)).to eq(review) -# end -# end -# -# describe "GET #new" do -# it "assigns a new review as @review" do -# get :new, {}, valid_session -# expect(assigns(:review)).to be_a_new(Review) -# end -# end -# -# describe "GET #edit" do -# it "assigns the requested review as @review" do -# review = Review.create! valid_attributes -# get :edit, {:id => review.to_param}, valid_session -# expect(assigns(:review)).to eq(review) -# end -# end -# -# describe "POST #create" do -# context "with valid params" do -# it "creates a new Review" do -# expect { -# post :create, {:review => valid_attributes}, valid_session -# }.to change(Review, :count).by(1) -# end -# -# it "assigns a newly created review as @review" do -# post :create, {:review => valid_attributes}, valid_session -# expect(assigns(:review)).to be_a(Review) -# expect(assigns(:review)).to be_persisted -# end -# -# it "redirects to the created review" do -# post :create, {:review => valid_attributes}, valid_session -# expect(response).to redirect_to(Review.last) -# end -# end -# -# context "with invalid params" do -# it "assigns a newly created but unsaved review as @review" do -# post :create, {:review => invalid_attributes}, valid_session -# expect(assigns(:review)).to be_a_new(Review) -# end -# -# it "re-renders the 'new' template" do -# post :create, {:review => invalid_attributes}, valid_session -# expect(response).to render_template("new") -# end -# end -# end -# -# describe "PUT #update" do -# context "with valid params" do -# let(:new_attributes) { -# skip("Add a hash of attributes valid for your model") -# } -# -# it "updates the requested review" do -# review = Review.create! valid_attributes -# put :update, {:id => review.to_param, :review => new_attributes}, valid_session -# review.reload -# skip("Add assertions for updated state") -# end -# -# it "assigns the requested review as @review" do -# review = Review.create! valid_attributes -# put :update, {:id => review.to_param, :review => valid_attributes}, valid_session -# expect(assigns(:review)).to eq(review) -# end -# -# it "redirects to the review" do -# review = Review.create! valid_attributes -# put :update, {:id => review.to_param, :review => valid_attributes}, valid_session -# expect(response).to redirect_to(review) -# end -# end -# -# context "with invalid params" do -# it "assigns the review as @review" do -# review = Review.create! valid_attributes -# put :update, {:id => review.to_param, :review => invalid_attributes}, valid_session -# expect(assigns(:review)).to eq(review) -# end -# -# it "re-renders the 'edit' template" do -# review = Review.create! valid_attributes -# put :update, {:id => review.to_param, :review => invalid_attributes}, valid_session -# expect(response).to render_template("edit") -# end -# end -# end -# -# describe "DELETE #destroy" do -# it "destroys the requested review" do -# review = Review.create! valid_attributes -# expect { -# delete :destroy, {:id => review.to_param}, valid_session -# }.to change(Review, :count).by(-1) -# end -# -# it "redirects to the reviews list" do -# review = Review.create! valid_attributes -# delete :destroy, {:id => review.to_param}, valid_session -# expect(response).to redirect_to(reviews_url) -# end -# end -# end From 4e5928f5c01ae85b678770258820daff708317b1 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Sun, 13 Dec 2015 20:59:39 -0800 Subject: [PATCH 119/299] create login page and style it --- app/assets/stylesheets/application.scss | 14 ++++++++++++ app/controllers/sessions_controller.rb | 2 ++ app/views/sessions/index.html.erb | 1 - app/views/sessions/new.html.erb | 23 ++++++++++++++++++++ spec/controllers/sessions_controller_spec.rb | 7 ++++++ 5 files changed, 46 insertions(+), 1 deletion(-) delete mode 100644 app/views/sessions/index.html.erb create mode 100644 app/views/sessions/new.html.erb diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index fffa67374b..8708f9d922 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -96,6 +96,20 @@ h5 { text-overflow: ellipsis; } +// Login Page +.form-signin { + max-width: 330px; + padding: 15px; + margin: 0 auto; +} + +.btn-block { + display: block; + width: 100%; +} + +// Responsive images + @media (min-width: 768px){ .thumbnail { max-width: 300px; diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 1b484ebd90..a6701149c7 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -4,8 +4,10 @@ def new end def create + raise end def destroy end + end diff --git a/app/views/sessions/index.html.erb b/app/views/sessions/index.html.erb deleted file mode 100644 index 1d6c211720..0000000000 --- a/app/views/sessions/index.html.erb +++ /dev/null @@ -1 +0,0 @@ -

    Login page

    diff --git a/app/views/sessions/new.html.erb b/app/views/sessions/new.html.erb new file mode 100644 index 0000000000..58b72beb44 --- /dev/null +++ b/app/views/sessions/new.html.erb @@ -0,0 +1,23 @@ +
    + <% if !flash.now[:error].nil? %> +

    <%= flash.now[:error] %>

    + <% end %> + + <%= form_for(:session_data, url: login_path, :html => {:class => "form-signin"}) do |f| %> + + + <%= f.label :username, class: "sr-only" %> + <%= f.text_field :username, class: "form-control", placeholder: "Username" %> +
    + <%= f.label :password, class: "sr-only" %> + <%= f.password_field :password, class: "form-control", placeholder: "Password" %> +
    + + <%= f.submit "Sign in", class: "btn btn-lg btn-primary btn-block" %> + <% end %> + +
    diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index 003bededfb..868c5fc8ab 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -2,4 +2,11 @@ RSpec.describe SessionsController, type: :controller do + describe "GET 'new'" do + it 'renders the new page' do + + end + + end + end From 1791746fd1b299d5f44beb513469370d5a060893 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Sun, 13 Dec 2015 21:12:39 -0800 Subject: [PATCH 120/299] add styling to error on login page --- app/views/sessions/new.html.erb | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/app/views/sessions/new.html.erb b/app/views/sessions/new.html.erb index 58b72beb44..31aa7ca22a 100644 --- a/app/views/sessions/new.html.erb +++ b/app/views/sessions/new.html.erb @@ -1,10 +1,8 @@
    - <% if !flash.now[:error].nil? %> -

    <%= flash.now[:error] %>

    - <% end %> - <%= form_for(:session_data, url: login_path, :html => {:class => "form-signin"}) do |f| %> - + <% if !flash.now[:danger].nil? %> +

    <%= flash.now[:danger] %>

    + <% end %> <%= f.label :username, class: "sr-only" %> <%= f.text_field :username, class: "form-control", placeholder: "Username" %> @@ -12,11 +10,6 @@ <%= f.label :password, class: "sr-only" %> <%= f.password_field :password, class: "form-control", placeholder: "Password" %>
    - <%= f.submit "Sign in", class: "btn btn-lg btn-primary btn-block" %> <% end %> From 7ffcd6a7af12bae5dcc0430961a47d4a65ccd3bd Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Sun, 13 Dec 2015 21:13:36 -0800 Subject: [PATCH 121/299] make create method session controller --- app/controllers/sessions_controller.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index a6701149c7..2476a071a1 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -4,7 +4,18 @@ def new end def create - raise + data = params[:session_data] + @user = User.find_by_username(data[:username]) + if @user && @user.authenticate(data[:password])# User's email is in the system + # user is authenticated + session[:user_id] = @user.id + flash[:success] = "Welcome, #{@user.name}" + redirect_to root_path + else + # user not logged in + flash.now[:danger] = "Invalid username/password combination" + render :new + end end def destroy From eb8eaba71320da5299041c75e827fc9e70201105 Mon Sep 17 00:00:00 2001 From: Tammy Date: Sun, 13 Dec 2015 21:25:49 -0800 Subject: [PATCH 122/299] finished Category model Rspec --- app/views/categories/index.html.erb | 2 +- spec/models/category_spec.rb | 22 ++++++++++++++++------ spec/models/user_spec.rb | 11 +++++++++-- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/app/views/categories/index.html.erb b/app/views/categories/index.html.erb index 3536a32e8e..f0e18cca21 100644 --- a/app/views/categories/index.html.erb +++ b/app/views/categories/index.html.erb @@ -16,6 +16,7 @@ <%= category.name %> <%= link_to 'Show', category %> <%= link_to 'Edit', edit_category_path(category) %> + <%= link_to 'Destroy', category_path(category), method: :delete, data: { confirm: 'Are you sure?' } %> <% end %> @@ -24,4 +25,3 @@
    <%= link_to 'New Category', new_category_path %> -<%= link_to 'All Categories', categories_path %> diff --git a/spec/models/category_spec.rb b/spec/models/category_spec.rb index fc3d6c0c7e..a877297755 100644 --- a/spec/models/category_spec.rb +++ b/spec/models/category_spec.rb @@ -1,6 +1,16 @@ -# require 'rails_helper' -# -# RSpec.describe Category, type: :model do -# pending "add some examples to (or delete) #{__FILE__}" -# end -# # +require 'rails_helper' + +RSpec.describe Category, type: :model do + describe ".validates" do + + it { is_expected.to validate_presence_of(:name) } + + it "must have a unique name" do + Category.create(name: "sunscreen") + expect(Category.new(name: "sunscreen")).to_not be_valid + expect(Category.new(name: "babied sunscreen")).to be_valid + end + + end + +end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 82aabb9026..a6b4596248 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -15,9 +15,16 @@ expect(User.new(name: "Nemo", username: "Nemo1", email: "nemo@gmail.com", password: "123", password_confirmation: "123")).to_not be_valid end - it "must have an email format" do - expect(User.new(name: "Nemo", username: "Nemo1", email: "nemo.gmail.com", password: "123", password_confirmation: "123")).to_not be_valid + it "must have a valid email " do + expect(User.create(email: 'nemo@foo,com', name: "Bob", username: "bobi", password: "333", password_confirmation: "333")).to_not be_valid + expect(User.create(email: 'nemo_at_foo.org', name: "Bob", username: "bobi", password: "333", password_confirmation: "333")).to_not be_valid + expect(User.create(email: 'nemo.user@foo.', name: "Bob", username: "bobi", password: "333", password_confirmation: "333")).to_not be_valid + expect(User.create(email: 'nemo@bar_baz.com', name: "Bob", username: "bobi", password: "333", password_confirmation: "333")).to_not be_valid + expect(User.create(email: 'nemo@bar+baz.com', name: "Bob", username: "bobi", password: "333", password_confirmation: "333")).to_not be_valid + expect(User.create(email: ' ', name: "Bob", username: "bobi", password: "333", password_confirmation: "333")).to_not be_valid + expect(User.create(email: 'nemo@nemo.com', name: "Bob", username: "bobi", password: "333", password_confirmation: "333")).to be_valid end + end From c190d48dea58b452c27932986e8d929ea2977c39 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Sun, 13 Dec 2015 21:37:07 -0800 Subject: [PATCH 123/299] add flash message to welcome page on login --- app/views/welcome/index.html.erb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/views/welcome/index.html.erb b/app/views/welcome/index.html.erb index 66ba53f0a4..4baf1e0d52 100644 --- a/app/views/welcome/index.html.erb +++ b/app/views/welcome/index.html.erb @@ -2,6 +2,12 @@

    Wetsy Homepage

    + <% if !flash[:success].nil? %> +
    + + <%= flash[:success] %> +
    + <% end %>

    Find the Best Products for Fun Water Times


    <%= render 'shared/display_products' %> From db4094ee8756263da9edaea11db244cbcded52e5 Mon Sep 17 00:00:00 2001 From: Tammy Date: Sun, 13 Dec 2015 21:40:51 -0800 Subject: [PATCH 124/299] Order item model Rspec completed --- spec/models/order_item_spec.rb | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/spec/models/order_item_spec.rb b/spec/models/order_item_spec.rb index 05dae62b2b..720072bd57 100644 --- a/spec/models/order_item_spec.rb +++ b/spec/models/order_item_spec.rb @@ -1,5 +1,14 @@ -# require 'rails_helper' -# -# RSpec.describe OrderItem, type: :model do -# pending "add some examples to (or delete) #{__FILE__}" -# end +require 'rails_helper' + +RSpec.describe OrderItem, type: :model do + describe ".validates" do + it { is_expected.to validate_presence_of(:quantity) } + # don't need to validate numericality since it is an integer + + it "requires a quantity in correct range" do + expect(OrderItem.new(quantity: 5)).to be_valid + expect(OrderItem.new(quantity: 0)).to be_invalid + expect(OrderItem.new(quantity: -1)).to be_invalid + end + end +end From 8a15508dcf6d9612a99b6b2f40cbc170e2270f93 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Sun, 13 Dec 2015 21:47:49 -0800 Subject: [PATCH 125/299] fix logout link --- app/views/shared/_navbar.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/shared/_navbar.html.erb b/app/views/shared/_navbar.html.erb index b6b1977221..f0d15ef482 100644 --- a/app/views/shared/_navbar.html.erb +++ b/app/views/shared/_navbar.html.erb @@ -24,7 +24,7 @@
  • <%= link_to "Register", new_user_path %>
  • <%= link_to "Log In", login_path %>
  • -
  • <%= link_to "Log Out", logout_path %>
  • +
  • <%= link_to "Log Out", logout_path, method: :delete %>
  • My Cart
From 659034a5dc39dcbbff780f83438475ad3d9ef060 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Sun, 13 Dec 2015 21:48:10 -0800 Subject: [PATCH 126/299] complete sessions controller --- app/controllers/sessions_controller.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 2476a071a1..b5af9bae6b 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -19,6 +19,9 @@ def create end def destroy + reset_session + flash[:danger] = "You have successfully logged out" + redirect_to login_path end end From e5fdc803f38d93312f102b2c9112a0951773554b Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Sun, 13 Dec 2015 21:48:28 -0800 Subject: [PATCH 127/299] complete sessions controller spec --- spec/controllers/sessions_controller_spec.rb | 52 ++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index 868c5fc8ab..87b39df5d6 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -4,9 +4,61 @@ describe "GET 'new'" do it 'renders the new page' do + get :new + expect(response.status).to eq 200 + end + end + + describe "POST 'create'" do + let(:user) { FactoryGirl.create(:user) } + let(:valid_login_attributes) { + { session_data: { + username: user.username, + password: user.password + }} + } + let(:invalid_login_attributes) { + { session_data: { + username: user.username, + password: "thisisthewrongpassword" + }} + } + context "with valid login params" do + it "redirects to homepage" do + post :create, valid_login_attributes + expect(subject).to redirect_to root_path + end + it "saves user id to session" do + post :create, valid_login_attributes + expect(session[:user_id]).to eq user.id + end + end + context "with invalid login params" do + it "re-renders the new template" do + post :create, invalid_login_attributes + expect(subject).to render_template :new + end + it "does not save the user id to session" do + post :create, invalid_login_attributes + expect(session[:user_id]).to be_nil + end end + end + describe "DELETE 'destroy'" do + let(:user) { FactoryGirl.create(:user) } + let(:valid_login_attributes) { + { session_data: { + username: user.username, + password: user.password + }} + } + it "deletes user id from session" do + post :create, valid_login_attributes + delete :destroy + expect(session[:user_id]).to be_nil + end end end From 84ad761b925d47651a22a3a33266f96b7497de9f Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Sun, 13 Dec 2015 21:50:10 -0800 Subject: [PATCH 128/299] clear out sessions controller --- app/controllers/sessions_controller.rb | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index b5af9bae6b..d10ca9718b 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -1,27 +1,4 @@ class SessionsController < ApplicationController - def new - end - - def create - data = params[:session_data] - @user = User.find_by_username(data[:username]) - if @user && @user.authenticate(data[:password])# User's email is in the system - # user is authenticated - session[:user_id] = @user.id - flash[:success] = "Welcome, #{@user.name}" - redirect_to root_path - else - # user not logged in - flash.now[:danger] = "Invalid username/password combination" - render :new - end - end - - def destroy - reset_session - flash[:danger] = "You have successfully logged out" - redirect_to login_path - end end From 37b3ec606af0c6f9da12ceb57eb28c21893a2b34 Mon Sep 17 00:00:00 2001 From: Kelly Date: Mon, 14 Dec 2015 09:47:00 -0800 Subject: [PATCH 129/299] Add sessions#create and sessions#destroy --- app/controllers/sessions_controller.rb | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index a6701149c7..7e76c471e7 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -4,10 +4,24 @@ def new end def create - raise + data = params[:session_data] + @user = User.find_by_username(data[:username]) + if !@user.nil? + if @user.authenticate(data[:password]) + session[:user_id] = @user.id + redirect_to root_path + else + flash.now[:error] = "Try again." + render :new + end + else + flash[:error] = "Register New Account" + redirect_to new_user_path + end end def destroy + session[:user_id] = nil + redirect_to root_path end - end From 8dfaf6aaf6fbf2adb9810c789f64ef5d45c331e2 Mon Sep 17 00:00:00 2001 From: Kelly Date: Mon, 14 Dec 2015 09:54:36 -0800 Subject: [PATCH 130/299] Update sessions#create --- app/controllers/sessions_controller.rb | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 6905e5ceee..19ad6a2293 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -5,22 +5,19 @@ def new def create data = params[:session_data] @user = User.find_by_username(data[:username]) - if !@user.nil? - if @user.authenticate(data[:password]) - session[:user_id] = @user.id - redirect_to root_path - else - flash.now[:error] = "Try again." - render :new - end + if !@user.nil? && @user.authenticate(data[:password]) + session[:user_id] = @user.id + flash[:success] = "You are now logged in." + redirect_to root_path else - flash[:error] = "Register New Account" - redirect_to new_user_path + flash.now[:error] = "Invalid username and password combination." + render :new end end def destroy session[:user_id] = nil + flash[:success] = "You are now logged out." redirect_to root_path end end From 466bb290f72ec7b0cab200395c8b2c15e78dfb5b Mon Sep 17 00:00:00 2001 From: Kelly Date: Mon, 14 Dec 2015 10:01:05 -0800 Subject: [PATCH 131/299] define current_user and require_login methods in application controller --- app/controllers/application_controller.rb | 11 +++++++++++ app/controllers/sessions_controller.rb | 1 + 2 files changed, 12 insertions(+) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index d83690e1b9..695f9c1d43 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,4 +2,15 @@ class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception + + def current_user + @current_user ||= User.find(session[:user_id]) if session[:user_id] + end + + def require_login + if current_user.nil? + flash[:error] = "You must be logged in." + redirect_to login_path + end + end end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 19ad6a2293..0c733c3a4e 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -16,6 +16,7 @@ def create end def destroy + @current_user = nil session[:user_id] = nil flash[:success] = "You are now logged out." redirect_to root_path From a2dc8e9eff3aa54714a61bdb19c7fa2e7985cb21 Mon Sep 17 00:00:00 2001 From: Kelly Date: Mon, 14 Dec 2015 10:13:28 -0800 Subject: [PATCH 132/299] add has_many through relationship between products and orders --- app/models/order.rb | 1 + app/models/product.rb | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/order.rb b/app/models/order.rb index 4b31051be0..4686bb1569 100644 --- a/app/models/order.rb +++ b/app/models/order.rb @@ -1,5 +1,6 @@ class Order < ActiveRecord::Base has_many :order_items + has_many :products, through: :order_items validates_numericality_of :zip, :cc_num, allow_nil: true validates_length_of :zip, is: 5, allow_nil: true validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i }, allow_nil: true diff --git a/app/models/product.rb b/app/models/product.rb index d5c5d1beb2..8157180df3 100644 --- a/app/models/product.rb +++ b/app/models/product.rb @@ -1,6 +1,7 @@ class Product < ActiveRecord::Base belongs_to :user - has_many :orders + has_many :order_items + has_many :orders, through: :order_items has_many :reviews has_and_belongs_to_many :categories From 45b6211c2de7a09e0690dcd59bae04096e225b7d Mon Sep 17 00:00:00 2001 From: Kelly Date: Mon, 14 Dec 2015 11:42:48 -0800 Subject: [PATCH 133/299] Add order status field to Order model --- db/migrate/20151214193805_modify_order.rb | 5 +++++ db/schema.rb | 7 ++++--- 2 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 db/migrate/20151214193805_modify_order.rb diff --git a/db/migrate/20151214193805_modify_order.rb b/db/migrate/20151214193805_modify_order.rb new file mode 100644 index 0000000000..74f0fb9756 --- /dev/null +++ b/db/migrate/20151214193805_modify_order.rb @@ -0,0 +1,5 @@ +class ModifyOrder < ActiveRecord::Migration + def change + add_column :orders, :status, :string, :default => "paid" + end +end diff --git a/db/schema.rb b/db/schema.rb index 795cbc39b2..9ec3ab8493 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20151209220657) do +ActiveRecord::Schema.define(version: 20151214193805) do create_table "categories", force: :cascade do |t| t.string "name" @@ -46,8 +46,9 @@ t.date "cc_exp" t.integer "cc_cvv" t.string "cc_name" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "status", default: "paid" end create_table "products", force: :cascade do |t| From ea6b188e497551794ea175f1ee6a6afcb391db78 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Mon, 14 Dec 2015 12:02:23 -0800 Subject: [PATCH 134/299] change navbar according to logging in --- app/controllers/application_controller.rb | 6 ++++++ app/views/shared/_navbar.html.erb | 12 +++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 695f9c1d43..e3228da4c4 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,11 +2,17 @@ class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception + helper_method :current_user, :logged_in? def current_user @current_user ||= User.find(session[:user_id]) if session[:user_id] end + # Returns true if the user is logged in, false otherwise. + def logged_in? + !current_user.nil? + end + def require_login if current_user.nil? flash[:error] = "You must be logged in." diff --git a/app/views/shared/_navbar.html.erb b/app/views/shared/_navbar.html.erb index f0d15ef482..0bec150fcd 100644 --- a/app/views/shared/_navbar.html.erb +++ b/app/views/shared/_navbar.html.erb @@ -22,9 +22,15 @@
  • <%= link_to "All Users", users_path %>
  • -
  • <%= link_to "Register", new_user_path %>
  • -
  • <%= link_to "Log In", login_path %>
  • -
  • <%= link_to "Log Out", logout_path, method: :delete %>
  • + <% if logged_in? %> +
  • <%= link_to "Log Out", logout_path, method: :delete %>
  • +
  • <%= link_to "My Profile", user_path(current_user) %>
  • +
  • <%= link_to "My Orders", user_orders_path(current_user) %>
  • + <% else %> +
  • <%= link_to "Register", new_user_path %>
  • +
  • <%= link_to "Log In", login_path %>
  • + <% end %> +
  • My Cart
  • From 876d2dfe69e21d3c5581e65dde91571a8d8b399a Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Mon, 14 Dec 2015 12:14:13 -0800 Subject: [PATCH 135/299] remove review edit functionality --- app/controllers/reviews_controller.rb | 10 +++++----- app/views/reviews/edit.html.erb | 8 +++++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb index 63d88e6dc0..2fe10f7964 100644 --- a/app/controllers/reviews_controller.rb +++ b/app/controllers/reviews_controller.rb @@ -1,6 +1,6 @@ class ReviewsController < ApplicationController - before_action :find_review, only: [:show, :edit, :update, :destroy] - before_action :find_product, only: [:new, :edit, :update, :create] + before_action :find_review, only: [:show, :update, :destroy] + before_action :find_product, only: [:new, :update, :create] def index @reviews = Review.all @@ -15,9 +15,9 @@ def new @review = Review.new end - - def edit - end + # Since guests can create a review, nobody (for now) can edit it. Maybe for admin user later... + # def edit + # end def create diff --git a/app/views/reviews/edit.html.erb b/app/views/reviews/edit.html.erb index af1b2054d7..f10ae0dbce 100644 --- a/app/views/reviews/edit.html.erb +++ b/app/views/reviews/edit.html.erb @@ -1,7 +1,9 @@ -
    + + + - <%= link_to 'Back to all Reviews', user_product_reviews_path(@product.user, @product), class: "btn btn-primary" %> -
    + From b825fc3b5cffe586c9f8942d5422c5f96822c027 Mon Sep 17 00:00:00 2001 From: Kelly Date: Mon, 14 Dec 2015 13:45:25 -0800 Subject: [PATCH 136/299] Add has_many through relationships to User model for order_items and orders --- app/controllers/orders_controller.rb | 2 +- app/models/user.rb | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index 93f239aa45..f119cb7de8 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -2,8 +2,8 @@ class OrdersController < ApplicationController before_action :set_order, only: [:show, :edit, :update, :destroy] def index - @orders = Order.all @user = User.find(params[:user_id]) + @orders = @user.orders end diff --git a/app/models/user.rb b/app/models/user.rb index 30b7843a23..b9a618b6ca 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,5 +1,7 @@ class User < ActiveRecord::Base has_many :products + has_many :order_items, through: :products + has_many :orders, through: :order_items has_secure_password before_save { self.email = email.downcase } # ensures emails are all lowercase @@ -7,5 +9,4 @@ class User < ActiveRecord::Base validates :username, :email, presence: true validates :username, :email, uniqueness: true validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i } - end From b6d30f707869092d42543a5ca0f54d1458ca8304 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Mon, 14 Dec 2015 13:56:44 -0800 Subject: [PATCH 137/299] add before filters to require login for actions --- app/controllers/application_controller.rb | 14 ++++++++++++++ app/controllers/orders_controller.rb | 2 ++ app/controllers/products_controller.rb | 1 + app/controllers/sessions_controller.rb | 3 +++ app/controllers/users_controller.rb | 7 +++++-- app/views/shared/_navbar.html.erb | 12 +++++++++--- app/views/welcome/index.html.erb | 6 ++++++ 7 files changed, 40 insertions(+), 5 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index e3228da4c4..a4d9f35737 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -13,10 +13,24 @@ def logged_in? !current_user.nil? end + def correct_user + id = params[:id] || params[:user_id] + @user = User.find(id) + flash[:error] = "You do not have permission to access that page." + redirect_to(root_path) unless @user == current_user + end + def require_login if current_user.nil? flash[:error] = "You must be logged in." redirect_to login_path end end + + def require_logout + if !current_user.nil? + flash[:error] = "You are currently logged in. You must log out to complete that action." + redirect_to root_path + end + end end diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index 93f239aa45..bab86578af 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -1,5 +1,7 @@ class OrdersController < ApplicationController before_action :set_order, only: [:show, :edit, :update, :destroy] + before_action :require_login, only: [:index] + before_action :correct_user, only: [:index] def index @orders = Order.all diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index 7046758cb9..e16a852656 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -2,6 +2,7 @@ class ProductsController < ApplicationController before_action :find_product, only: [:show, :edit, :update] before_action :find_user, only: [:new, :edit, :create, :update] before_action :all_categories, only: [:new, :edit, :create, :update] + before_action :require_login, only: [:new, :edit, :create, :update] def index @products = Product.all.paginate(page: params[:page], per_page: 12) diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 0c733c3a4e..bd48ee4b46 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -1,4 +1,7 @@ class SessionsController < ApplicationController + before_action :require_login, only: [:destroy] + before_action :require_logout, only: [:new, :create] + def new end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index baa34868e4..d9d9d7e240 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,12 +1,13 @@ class UsersController < ApplicationController before_action :set_user, only: [:show, :edit, :update, :destroy, :products] - + before_action :require_login, only: [:update, :destroy, :edit] + before_action :correct_user, only: [:update, :destroy, :edit] + before_action :require_logout, only: [:new] def index @users = User.all end - def show end @@ -38,6 +39,8 @@ def update end end + # TODO: Maybe we shouldn't allow users to destroy. Only mark inactive? + def destroy @user.destroy respond_to do |format| diff --git a/app/views/shared/_navbar.html.erb b/app/views/shared/_navbar.html.erb index 0bec150fcd..4b0f14fc9e 100644 --- a/app/views/shared/_navbar.html.erb +++ b/app/views/shared/_navbar.html.erb @@ -23,9 +23,15 @@ <% if logged_in? %> -
  • <%= link_to "Log Out", logout_path, method: :delete %>
  • -
  • <%= link_to "My Profile", user_path(current_user) %>
  • -
  • <%= link_to "My Orders", user_orders_path(current_user) %>
  • + <% else %>
  • <%= link_to "Register", new_user_path %>
  • <%= link_to "Log In", login_path %>
  • diff --git a/app/views/welcome/index.html.erb b/app/views/welcome/index.html.erb index 4baf1e0d52..3c2d18ea91 100644 --- a/app/views/welcome/index.html.erb +++ b/app/views/welcome/index.html.erb @@ -8,6 +8,12 @@ <%= flash[:success] %>
    <% end %> + <% if !flash[:error].nil? %> +
    + + <%= flash[:error] %> +
    + <% end %>

    Find the Best Products for Fun Water Times


    <%= render 'shared/display_products' %> From 1ba7ec5887ea41ab9bb2472f578bbd8462ccf737 Mon Sep 17 00:00:00 2001 From: Kelly Date: Mon, 14 Dec 2015 14:29:43 -0800 Subject: [PATCH 138/299] order#index and order#show --- app/views/orders/index.html.erb | 40 +++++++++++------------------- app/views/orders/show.html.erb | 44 +++++++++++++++++---------------- 2 files changed, 38 insertions(+), 46 deletions(-) diff --git a/app/views/orders/index.html.erb b/app/views/orders/index.html.erb index b0d9c0da21..53c3649260 100644 --- a/app/views/orders/index.html.erb +++ b/app/views/orders/index.html.erb @@ -1,19 +1,12 @@

    <%= notice %>

    -

    Listing Orders

    +

    <%= @user.name %>'s Orders

    - - - - - - - - - + + @@ -21,23 +14,20 @@ <% @orders.each do |order| %> - - - - - - - - - - - - - + + + <% end %>
    EmailStreetCityStateZipCc numCc expCc cvvCc nameStatusOrder Items
    <%= order.email %><%= order.street %><%= order.city %><%= order.state %><%= order.zip %><%= order.cc_num %><%= order.cc_exp %><%= order.cc_cvv %><%= order.cc_name %><%= link_to 'Show', user_order_path(@user.id, order.id) %><%= link_to 'Edit', edit_user_order_path(@user.id, order.id) %><%= link_to 'Destroy', user_order_path(@user.id, order.id), method: :delete, data: { confirm: 'Are you sure?' } %><%= link_to 'Order items', user_order_order_items_path(@user.id, order.id) %> <%= order.status %><% order.order_items.each do |oi| %> + <% if oi.product.user == @user %> + <%= oi.product.name %>(<%= oi.quantity %>) +
    + <% end %> + <% end %> +
    + <%= link_to "View Order", user_order_path(@user.id, order.id) %> +
    - - +
    <%= link_to 'New Order', new_user_order_path %> diff --git a/app/views/orders/show.html.erb b/app/views/orders/show.html.erb index 3978e28da6..37727e9bd7 100644 --- a/app/views/orders/show.html.erb +++ b/app/views/orders/show.html.erb @@ -1,33 +1,34 @@

    <%= notice %>

    - Email: - <%= @order.email %> + Status: + <%= @order.status %>

    - Street: - <%= @order.street %> -

    - -

    - City: - <%= @order.city %> + Name: + <%= @order.cc_name %>

    - State: - <%= @order.state %> + Email: + <%= @order.email %>

    - Zip: - <%= @order.zip %> + Mailing Address: +
    + <%= @order.street %> +
    + <%= @order.city %>, <%= @order.state %> <%= @order.zip %>

    Cc num: - <%= @order.cc_num %> + <% (@order.cc_num.length - 4).times do %> + * + <% end %> + <%= @order.cc_num[(@order.cc_num.length - 4)..(@order.cc_num.length - 1)] %>

    @@ -36,13 +37,14 @@

    - Cc cvv: - <%= @order.cc_cvv %> -

    - -

    - Cc name: - <%= @order.cc_name %> + Order Items from <%= @user.name %>: +
    + <% @order.order_items.each do |oi| %> + <% if oi.product.user == @user %> + <%= oi.product.name %>(<%= oi.quantity %>) +
    + <% end %> + <% end %>

    <%= link_to 'Edit', edit_user_order_path(@user.id, @order.id) %> | From 41bf03024f43422cabed46f7e29a0a3ead27aa73 Mon Sep 17 00:00:00 2001 From: Tammy Date: Mon, 14 Dec 2015 14:41:38 -0800 Subject: [PATCH 139/299] wrote a bunch of methods in cart model and created cart controller for the show --- app/assets/javascripts/carts.coffee | 3 ++ app/assets/stylesheets/carts.scss | 3 ++ app/controllers/carts_controller.rb | 5 +++ app/helpers/carts_helper.rb | 2 + app/models/cart.rb | 48 +++++++++++++++++++++++ app/views/carts/show.html.erb | 1 + config/routes.rb | 1 + db/migrate/20151214214750_create_carts.rb | 8 ++++ spec/controllers/carts_controller_spec.rb | 5 +++ spec/helpers/carts_helper_spec.rb | 15 +++++++ spec/models/cart_spec.rb | 5 +++ 11 files changed, 96 insertions(+) create mode 100644 app/assets/javascripts/carts.coffee create mode 100644 app/assets/stylesheets/carts.scss create mode 100644 app/controllers/carts_controller.rb create mode 100644 app/helpers/carts_helper.rb create mode 100644 app/models/cart.rb create mode 100644 app/views/carts/show.html.erb create mode 100644 db/migrate/20151214214750_create_carts.rb create mode 100644 spec/controllers/carts_controller_spec.rb create mode 100644 spec/helpers/carts_helper_spec.rb create mode 100644 spec/models/cart_spec.rb diff --git a/app/assets/javascripts/carts.coffee b/app/assets/javascripts/carts.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/carts.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/carts.scss b/app/assets/stylesheets/carts.scss new file mode 100644 index 0000000000..62647c9dde --- /dev/null +++ b/app/assets/stylesheets/carts.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the carts 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/carts_controller.rb b/app/controllers/carts_controller.rb new file mode 100644 index 0000000000..4029763f57 --- /dev/null +++ b/app/controllers/carts_controller.rb @@ -0,0 +1,5 @@ +class CartsController < ApplicationController + + def show + end +end diff --git a/app/helpers/carts_helper.rb b/app/helpers/carts_helper.rb new file mode 100644 index 0000000000..d99c380cb5 --- /dev/null +++ b/app/helpers/carts_helper.rb @@ -0,0 +1,2 @@ +module CartsHelper +end diff --git a/app/models/cart.rb b/app/models/cart.rb new file mode 100644 index 0000000000..0e5a35a9e1 --- /dev/null +++ b/app/models/cart.rb @@ -0,0 +1,48 @@ +class Cart < ActiveRecord::Base + + def initialize(session) + @session = session + @session[:cart] ||= {} + end + + def cart_count + if @session[:cart]!= {} + return @session[:cart].count + else + return 0 + end + end + + #return an array of new (unsaved) order items + def new_order_items + order_items = [] + initialize + @session[:cart].each do |product, quantity| + order_items.push(OrderItem.new(:product_id => product, :quantity => quantity)) + end + return order_items + end + + #return an array of product objects that are in the cart + def find_products + product = [] + order_items = new_order_items + order_items.each do |order_item| + product = Product.find(order_item.product_id) + products.push(product) + end + end + + #Get subtotal of the cart items + + def subtotal + subtotal = 0 + @session[:cart].each do |product, quantity| + price = Product.find(product).price + subtotal += (price * quantity) + end + return subtotal + end + + +end diff --git a/app/views/carts/show.html.erb b/app/views/carts/show.html.erb new file mode 100644 index 0000000000..19c82bd50b --- /dev/null +++ b/app/views/carts/show.html.erb @@ -0,0 +1 @@ +

    Cart

    diff --git a/config/routes.rb b/config/routes.rb index ace19ab005..26c3a133a7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -14,6 +14,7 @@ end end + get 'cart/' => 'carts#show', as: :cart get 'products/' => 'products#index', as: :products get 'login/' => 'sessions#new', as: :login post 'login/' => 'sessions#create' diff --git a/db/migrate/20151214214750_create_carts.rb b/db/migrate/20151214214750_create_carts.rb new file mode 100644 index 0000000000..638a8507dc --- /dev/null +++ b/db/migrate/20151214214750_create_carts.rb @@ -0,0 +1,8 @@ +class CreateCarts < ActiveRecord::Migration + def change + create_table :carts do |t| + + t.timestamps null: false + end + end +end diff --git a/spec/controllers/carts_controller_spec.rb b/spec/controllers/carts_controller_spec.rb new file mode 100644 index 0000000000..0ddc03dd6a --- /dev/null +++ b/spec/controllers/carts_controller_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe CartsController, type: :controller do + +end diff --git a/spec/helpers/carts_helper_spec.rb b/spec/helpers/carts_helper_spec.rb new file mode 100644 index 0000000000..c6408a3423 --- /dev/null +++ b/spec/helpers/carts_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the CartsHelper. For example: +# +# describe CartsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe CartsHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/cart_spec.rb b/spec/models/cart_spec.rb new file mode 100644 index 0000000000..598527707b --- /dev/null +++ b/spec/models/cart_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Cart, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end From 19b01064de21c824cd4ad4b642a591578bc756eb Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Mon, 14 Dec 2015 14:44:59 -0800 Subject: [PATCH 140/299] remove delete method for user --- app/controllers/users_controller.rb | 9 --------- app/views/users/index.html.erb | 1 - 2 files changed, 10 deletions(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index d9d9d7e240..6a7176b3c3 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -39,15 +39,6 @@ def update end end - # TODO: Maybe we shouldn't allow users to destroy. Only mark inactive? - - def destroy - @user.destroy - respond_to do |format| - format.html { redirect_to users_url, notice: 'User was successfully destroyed.' } - end - end - private def set_user diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb index bb6342973b..c14eaa11b1 100644 --- a/app/views/users/index.html.erb +++ b/app/views/users/index.html.erb @@ -20,7 +20,6 @@ <%= user.name %> <%= link_to 'Show', user %> <%= link_to 'Edit', edit_user_path(user) %> - <%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %> <%= link_to 'view my orders', user_orders_path(user.id) %> <% end %> From 641a54fb8d22f81e0fe266fa5e8dec786b4540cd Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Mon, 14 Dec 2015 14:45:14 -0800 Subject: [PATCH 141/299] update users controller for testing logging in --- spec/controllers/users_controller_spec.rb | 154 ++++++++++------------ 1 file changed, 68 insertions(+), 86 deletions(-) diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index c217ed6599..8ae13b4a5b 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -1,29 +1,17 @@ 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 UsersController, type: :controller do + let(:user) { FactoryGirl.create(:user) } + describe "GET 'index'" do it "is successful" do get :index expect(response.status).to eq 200 end + it "assigns all users as @users" do + get :index, id: user.id + expect(assigns(:users)).to eq([user]) + end end describe "GET 'new'" do @@ -31,36 +19,39 @@ get :new expect(subject).to render_template :new end + it "assigns a new user as @user" do + get :new, id: user.id + expect(assigns(:user)).to be_a_new(User) + end end describe "GET 'edit'" do - let(:user) do - User.create(name: "Nemo", username: "Nemo1", email: "nemo@gmail.com", password: "123", password_confirmation: "123") - end - it "renders edit view" do - get :edit, id: user.id + get :edit, {id: user.id}, user_id: user.id expect(subject).to render_template :edit end + it "assigns the requested user as @user" do + get :edit, {id: user.id}, user_id: user.id + expect(assigns(:user)).to eq(user) + end end describe "GET 'show'" do - let(:user) do - User.create(name: "Nemo", username: "Nemo1", email: "nemo@gmail.com", password: "123", password_confirmation: "123") - end - it "renders the show view" do get :show, id: user.id expect(subject).to render_template :show end + it "assigns the requested user as @user" do + get :show, id: user.id + expect(assigns(:user)).to eq(user) + end end describe "POST 'create'" do let(:good_params) do { user: { - name: "Nemo", username: "Nemo1", email: "nemo@gmail.com", password: "123", @@ -72,82 +63,73 @@ let(:bad_params) do { user: { - name: "", - username: "Nemo1", + username: "", email: "nemo@gmail.com", password: "1223", password_confirmation: "123" } } end + context "valid create params" do + it "redirect to index page" do + post :create, good_params + expect(subject).to redirect_to users_path + end + it "creates a new User" do + expect { + post :create, good_params + }.to change(User, :count).by(1) + end - it "redirect to index page" do - post :create, good_params - #success case - expect(subject).to redirect_to users_path + it "assigns a newly created review as @review" do + post :create, good_params + expect(assigns(:user)).to be_a(User) + expect(assigns(:user)).to be_persisted + end end - - it "render new template on error" do - #Error case - post :create, bad_params - expect(subject).to render_template :new + context "invalid create params" do + it "assigns a newly created but unsaved user as @user" do + post :create, bad_params + expect(assigns(:user)).to be_a_new(User) + end + it "render new template on error" do + post :create, bad_params + expect(subject).to render_template :new + end end end - describe "PATCH 'update'" do - let(:user) do - User.create(name: "Nemo", username: "Nemo1", email: "nemo@gmail.com", password: "123", password_confirmation: "123") - end - - let(:good_params) do - { - id: user.id, - user: { - name: "Nemo", - username: "Nemo1", - email: "nemo@gmail.com", - password: "123", - password_confirmation: "123" - } - } - end - - let(:bad_params) do - { - id: user.id, - user: { - name: "", - username: "Nemo1", - email: "nemo@gmail.com", - password: "1223", - password_confirmation: "123" - } - } - end - - it "redirect to index page" do - patch :update, good_params - expect(subject).to redirect_to users_path + let(:good_params) do + { id: user.id, + user: { email: "new_email@example.com"}} end - it "render edit template on error" do - patch :update, bad_params - expect(subject).to render_template "edit" + let(:bad_params) do + { id: user.id, + user: { email: "" }} end - end - - describe "DELETE 'destroy'" do - let(:user) do - User.create(name: "Nemo", username: "Nemo1", email: "nemo@gmail.com", password: "123", password_confirmation: "123") + context "with valid update params" do + it "assigns the requested user as @user" do + patch :update, good_params, user_id: user.id + expect(assigns(:user)).to eq(user) + end + it "redirects to index page" do + patch :update, good_params, user_id: user.id + expect(subject).to redirect_to users_path + end end - it "redirect to index after deleting" do - delete :destroy, id: user.id - expect(subject).to redirect_to users_path + context "with invalid update params" do + it "assigns the user as @user" do + patch :update, bad_params, user_id: user.id + expect(assigns(:user)).to eq(user) + end + it "re-renders edit template" do + patch :update, bad_params, user_id: user.id + expect(subject).to render_template "edit" + end end - end - end From d428c4d08c71e3a22121792e75da1ebbfa62fed8 Mon Sep 17 00:00:00 2001 From: Tammy Date: Mon, 14 Dec 2015 15:24:19 -0800 Subject: [PATCH 142/299] havn't tested yet, but added a few method. commit to pull so we could see if it works --- app/controllers/carts_controller.rb | 8 ++++++++ app/models/cart.rb | 18 +++++++----------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/app/controllers/carts_controller.rb b/app/controllers/carts_controller.rb index 4029763f57..b034f5fb8c 100644 --- a/app/controllers/carts_controller.rb +++ b/app/controllers/carts_controller.rb @@ -2,4 +2,12 @@ class CartsController < ApplicationController def show end + + def add_product + quantity = params[:quantity] + product_id = params[:product_id] + add_product(product_id, quantity) + redirect_to product_path(product_id) + end + end diff --git a/app/models/cart.rb b/app/models/cart.rb index 0e5a35a9e1..dcdfeea2e0 100644 --- a/app/models/cart.rb +++ b/app/models/cart.rb @@ -1,10 +1,16 @@ -class Cart < ActiveRecord::Base +class Cart def initialize(session) @session = session @session[:cart] ||= {} end + def add_product(product_id, quantity) + initialize + @session[:cart] = {:product_id => quantity } + end + + def cart_count if @session[:cart]!= {} return @session[:cart].count @@ -13,16 +19,6 @@ def cart_count end end - #return an array of new (unsaved) order items - def new_order_items - order_items = [] - initialize - @session[:cart].each do |product, quantity| - order_items.push(OrderItem.new(:product_id => product, :quantity => quantity)) - end - return order_items - end - #return an array of product objects that are in the cart def find_products product = [] From d8d274963e8e502a60e462513f05da13e4db9cae Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Mon, 14 Dec 2015 15:25:34 -0800 Subject: [PATCH 143/299] add test for capitalization for category model --- app/models/category.rb | 2 ++ spec/factories.rb | 1 - spec/models/category_spec.rb | 11 +++++++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/models/category.rb b/app/models/category.rb index 737e221b2e..2886ff737a 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -2,4 +2,6 @@ class Category < ActiveRecord::Base has_and_belongs_to_many :products validates :name, uniqueness: true validates :name, presence: true + + before_validation { self.name = name.downcase if self.name} end diff --git a/spec/factories.rb b/spec/factories.rb index 833f7534f4..992c793fd3 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -28,7 +28,6 @@ factory :category do name "toy" - product end end diff --git a/spec/models/category_spec.rb b/spec/models/category_spec.rb index a877297755..7ed5ea1d09 100644 --- a/spec/models/category_spec.rb +++ b/spec/models/category_spec.rb @@ -1,16 +1,19 @@ require 'rails_helper' RSpec.describe Category, type: :model do - describe ".validates" do + let (:category) { FactoryGirl.create(:category) } + describe ".validates" do it { is_expected.to validate_presence_of(:name) } - it "must have a unique name" do - Category.create(name: "sunscreen") - expect(Category.new(name: "sunscreen")).to_not be_valid + expect(Category.new(name: category.name)).to_not be_valid expect(Category.new(name: "babied sunscreen")).to be_valid end + it "downcases name before saving" do + expect(Category.new(name: category.name.upcase)).to_not be_valid + end + end end From f6bbc0556fe8a91ad325b78b18fd2fe6671e5b85 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Mon, 14 Dec 2015 15:29:05 -0800 Subject: [PATCH 144/299] update user model and specs to downcase email --- app/models/user.rb | 2 +- db/schema.rb | 7 ++++++- spec/models/user_spec.rb | 30 +++++++++++++++--------------- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index b9a618b6ca..a3e93b8c47 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -4,7 +4,7 @@ class User < ActiveRecord::Base has_many :orders, through: :order_items has_secure_password - before_save { self.email = email.downcase } # ensures emails are all lowercase + before_validation { self.email = email.downcase if self.email } # ensures emails are all lowercase validates :username, :email, presence: true validates :username, :email, uniqueness: true diff --git a/db/schema.rb b/db/schema.rb index 9ec3ab8493..82da53daca 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,12 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20151214193805) do +ActiveRecord::Schema.define(version: 20151214214750) do + + create_table "carts", force: :cascade do |t| + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end create_table "categories", force: :cascade do |t| t.string "name" diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index a6b4596248..0543d65252 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1,28 +1,28 @@ require 'rails_helper' - RSpec.describe User, type: :model do - - let(:user1) { - User.create(name: "Nemo", username: "Nemo1", email: "nemo@gmail.com", password: "123", password_confirmation: "123") - } + let (:user) { FactoryGirl.create(:user) } + it { is_expected.to have_secure_password } describe ".validates" do it { is_expected.to validate_presence_of(:email) } it "must have a unique email" do - User.create(name: "Bob", username: "bobi", email: "nemo@gmail.com", password: "333", password_confirmation: "333") - expect(User.new(name: "Nemo", username: "Nemo1", email: "nemo@gmail.com", password: "123", password_confirmation: "123")).to_not be_valid + expect(User.new(name: "Nemo", username: "Nemo1", email: user.email, password: "123", password_confirmation: "123")).to_not be_valid + end + + it "downcases email before checking validity" do + expect(User.new(name: "Nemo", username: "Nemo1", email: user.email.upcase, password: "123", password_confirmation: "123")).to_not be_valid end - it "must have a valid email " do - expect(User.create(email: 'nemo@foo,com', name: "Bob", username: "bobi", password: "333", password_confirmation: "333")).to_not be_valid - expect(User.create(email: 'nemo_at_foo.org', name: "Bob", username: "bobi", password: "333", password_confirmation: "333")).to_not be_valid - expect(User.create(email: 'nemo.user@foo.', name: "Bob", username: "bobi", password: "333", password_confirmation: "333")).to_not be_valid - expect(User.create(email: 'nemo@bar_baz.com', name: "Bob", username: "bobi", password: "333", password_confirmation: "333")).to_not be_valid - expect(User.create(email: 'nemo@bar+baz.com', name: "Bob", username: "bobi", password: "333", password_confirmation: "333")).to_not be_valid - expect(User.create(email: ' ', name: "Bob", username: "bobi", password: "333", password_confirmation: "333")).to_not be_valid - expect(User.create(email: 'nemo@nemo.com', name: "Bob", username: "bobi", password: "333", password_confirmation: "333")).to be_valid + it "must have a valid email" do + expect(User.new(email: 'nemo@foo,com', name: "Bob", username: "bobi", password: "333", password_confirmation: "333")).to_not be_valid + expect(User.new(email: 'nemo_at_foo.org', name: "Bob", username: "bobi", password: "333", password_confirmation: "333")).to_not be_valid + expect(User.new(email: 'nemo.user@foo.', name: "Bob", username: "bobi", password: "333", password_confirmation: "333")).to_not be_valid + expect(User.new(email: 'nemo@bar_baz.com', name: "Bob", username: "bobi", password: "333", password_confirmation: "333")).to_not be_valid + expect(User.new(email: 'nemo@bar+baz.com', name: "Bob", username: "bobi", password: "333", password_confirmation: "333")).to_not be_valid + expect(User.new(email: ' ', name: "Bob", username: "bobi", password: "333", password_confirmation: "333")).to_not be_valid + expect(User.new(email: 'nemo@nemo.com', name: "Bob", username: "bobi", password: "333", password_confirmation: "333")).to be_valid end end From 49c5fa0d92ef7b9773fdd3504d2e697febabaedf Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Mon, 14 Dec 2015 15:41:24 -0800 Subject: [PATCH 145/299] add product_id and order_id presence to orderitem model --- app/models/order_item.rb | 2 +- spec/factories.rb | 6 ++++-- spec/models/order_item_spec.rb | 8 +++++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/app/models/order_item.rb b/app/models/order_item.rb index 35bab80815..6e052fd2a0 100644 --- a/app/models/order_item.rb +++ b/app/models/order_item.rb @@ -2,6 +2,6 @@ class OrderItem < ActiveRecord::Base belongs_to :product belongs_to :order - validates :quantity, presence: true + validates :quantity, :product_id, :order_id, presence: true validates_numericality_of :quantity, :greater_than => 0 end diff --git a/spec/factories.rb b/spec/factories.rb index 992c793fd3..72a2284be3 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -22,8 +22,10 @@ association :product end - factory :orderitem do - + factory :orderitem, class: OrderItem do + quantity 4 + association :order + association :product end factory :category do diff --git a/spec/models/order_item_spec.rb b/spec/models/order_item_spec.rb index 720072bd57..a0c7249d4c 100644 --- a/spec/models/order_item_spec.rb +++ b/spec/models/order_item_spec.rb @@ -3,12 +3,14 @@ RSpec.describe OrderItem, type: :model do describe ".validates" do it { is_expected.to validate_presence_of(:quantity) } + it { is_expected.to validate_presence_of(:product_id) } + it { is_expected.to validate_presence_of(:order_id) } # don't need to validate numericality since it is an integer it "requires a quantity in correct range" do - expect(OrderItem.new(quantity: 5)).to be_valid - expect(OrderItem.new(quantity: 0)).to be_invalid - expect(OrderItem.new(quantity: -1)).to be_invalid + expect(FactoryGirl.build(:orderitem)).to be_valid + expect(OrderItem.new(product_id: 1, order_id: 1, quantity: 0)).to be_invalid + expect(OrderItem.new(product_id: 1, order_id: 1, quantity: -1)).to be_invalid end end end From 64a7f39cb00febc4e8757997b2b63b25fd98c867 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Mon, 14 Dec 2015 15:50:22 -0800 Subject: [PATCH 146/299] add user_id validation to product model --- app/models/product.rb | 2 +- spec/factories.rb | 2 +- spec/models/product_spec.rb | 9 ++++----- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/app/models/product.rb b/app/models/product.rb index 8157180df3..e439ee237a 100644 --- a/app/models/product.rb +++ b/app/models/product.rb @@ -5,7 +5,7 @@ class Product < ActiveRecord::Base has_many :reviews has_and_belongs_to_many :categories - validates :name, :price, presence: true + validates :name, :price, :user_id, presence: true validates :name, uniqueness: true validates_numericality_of :price, :greater_than => 0 validates_numericality_of :stock, :greater_than_or_equal_to => 0 diff --git a/spec/factories.rb b/spec/factories.rb index 72a2284be3..ab7abbba55 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -7,7 +7,7 @@ end factory :product do - name "Water Noodle" + name "Water bottle" price 500 stock 10 association :user diff --git a/spec/models/product_spec.rb b/spec/models/product_spec.rb index e6a3178181..a5381aac2d 100644 --- a/spec/models/product_spec.rb +++ b/spec/models/product_spec.rb @@ -1,16 +1,15 @@ require 'rails_helper' RSpec.describe Product, type: :model do - let(:sample_product) { - Product.create(name: "Water bottle", price: 10, stock: 5 ) - } + let(:sample_product) { FactoryGirl.create(:product) } + describe ".validates" do it { is_expected.to validate_presence_of(:name) } it { is_expected.to validate_presence_of(:price) } + it { is_expected.to validate_presence_of(:user_id) } it "must have a unique name" do - Product.create(name: "a", price: 10, stock: 5) - expect(Product.new(name: "a", price: 10, stock: 5)).to_not be_valid + expect(Product.new(name: sample_product.name, price: 10, stock: 5)).to_not be_valid end it "must have a numerical price" do expect(Product.new(name: "a", price: "a", stock: 5)).to_not be_valid From 82b6e44ef51c29d75c70fb19e06c4ef6ca3ac208 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Mon, 14 Dec 2015 15:52:40 -0800 Subject: [PATCH 147/299] add user_id presence validation to product model --- app/models/review.rb | 2 +- spec/models/review_spec.rb | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/models/review.rb b/app/models/review.rb index c6956125da..7fc048740a 100644 --- a/app/models/review.rb +++ b/app/models/review.rb @@ -1,6 +1,6 @@ class Review < ActiveRecord::Base belongs_to :product - validates :rating, presence: true + validates :rating, :product_id, presence: true validates :rating, numericality: { greater_than: 0, less_than: 6, message: "must be between 1 and 5" } end diff --git a/spec/models/review_spec.rb b/spec/models/review_spec.rb index baff1b73b1..4699e90166 100644 --- a/spec/models/review_spec.rb +++ b/spec/models/review_spec.rb @@ -3,10 +3,12 @@ RSpec.describe Review, type: :model do describe ".validates" do it { is_expected.to validate_presence_of(:rating) } + it { is_expected.to validate_presence_of(:product_id) } + it "requires a rating in correct range" do - expect(Review.new(rating: 5)).to be_valid - expect(Review.new(rating: 0)).to be_invalid - expect(Review.new(rating: 6)).to be_invalid + expect(Review.new(product_id: 1, rating: 5)).to be_valid + expect(Review.new(product_id: 1, rating: 0)).to be_invalid + expect(Review.new(product_id: 1, rating: 6)).to be_invalid end end From df1f6d9c7256399029c9b100cfbd79477870c072 Mon Sep 17 00:00:00 2001 From: Tammy Date: Mon, 14 Dec 2015 16:00:22 -0800 Subject: [PATCH 148/299] created a card view --- app/controllers/carts_controller.rb | 1 + app/models/cart.rb | 1 + app/views/carts/show.html.erb | 16 ++++++++++++++++ app/views/products/show.html.erb | 1 + db/schema.rb | 7 ++++++- 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/app/controllers/carts_controller.rb b/app/controllers/carts_controller.rb index b034f5fb8c..919111a70c 100644 --- a/app/controllers/carts_controller.rb +++ b/app/controllers/carts_controller.rb @@ -6,6 +6,7 @@ def show def add_product quantity = params[:quantity] product_id = params[:product_id] + add_product(product_id, quantity) redirect_to product_path(product_id) end diff --git a/app/models/cart.rb b/app/models/cart.rb index dcdfeea2e0..fb6efdbf48 100644 --- a/app/models/cart.rb +++ b/app/models/cart.rb @@ -27,6 +27,7 @@ def find_products product = Product.find(order_item.product_id) products.push(product) end + return products end #Get subtotal of the cart items diff --git a/app/views/carts/show.html.erb b/app/views/carts/show.html.erb index 19c82bd50b..92150369a0 100644 --- a/app/views/carts/show.html.erb +++ b/app/views/carts/show.html.erb @@ -1 +1,17 @@

    Cart

    +<% products = find_products %> + + + + + <% products.each do |product| %> + + + + + + + <% end %> +
    Product Description Price
    <%= link_to product.name, user_product(product.user_id, product.id) %> <%= product.description %> <%= product.price %> <%= link_to 'remove-NOT WORKING', cart_path %>
    + +

    Item total $<%= subtotal %>

    diff --git a/app/views/products/show.html.erb b/app/views/products/show.html.erb index 81547a4e73..bb9b40b644 100644 --- a/app/views/products/show.html.erb +++ b/app/views/products/show.html.erb @@ -45,3 +45,4 @@ <%= link_to 'Edit', edit_user_product_path(@product.user_id, @product.id) %> | <%= link_to 'Back', user_products_path(@product.user_id) %> <%= link_to 'Reviews', user_product_reviews_path(@product.user_id, @product.id) %> +<%= link_to 'Add to Cart', cart_path %> diff --git a/db/schema.rb b/db/schema.rb index 9ec3ab8493..82da53daca 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,12 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20151214193805) do +ActiveRecord::Schema.define(version: 20151214214750) do + + create_table "carts", force: :cascade do |t| + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end create_table "categories", force: :cascade do |t| t.string "name" From beb7adf861b41b26820153f9275e22926be7f51b Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Mon, 14 Dec 2015 16:07:40 -0800 Subject: [PATCH 149/299] add index to foreign keys --- db/migrate/20151214235744_add_index_to_foreign_keys.rb | 8 ++++++++ db/schema.rb | 9 ++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20151214235744_add_index_to_foreign_keys.rb diff --git a/db/migrate/20151214235744_add_index_to_foreign_keys.rb b/db/migrate/20151214235744_add_index_to_foreign_keys.rb new file mode 100644 index 0000000000..062ef3a922 --- /dev/null +++ b/db/migrate/20151214235744_add_index_to_foreign_keys.rb @@ -0,0 +1,8 @@ +class AddIndexToForeignKeys < ActiveRecord::Migration + def change + add_index :order_items, :product_id + add_index :order_items, :order_id + add_index :products, :user_id + add_index :reviews, :product_id + end +end diff --git a/db/schema.rb b/db/schema.rb index 82da53daca..96a5ddc548 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20151214214750) do +ActiveRecord::Schema.define(version: 20151214235744) do create_table "carts", force: :cascade do |t| t.datetime "created_at", null: false @@ -41,6 +41,9 @@ t.boolean "shipped", default: false end + add_index "order_items", ["order_id"], name: "index_order_items_on_order_id" + add_index "order_items", ["product_id"], name: "index_order_items_on_product_id" + create_table "orders", force: :cascade do |t| t.string "email" t.string "street" @@ -68,6 +71,8 @@ t.datetime "updated_at", null: false end + add_index "products", ["user_id"], name: "index_products_on_user_id" + create_table "reviews", force: :cascade do |t| t.integer "rating" t.integer "product_id" @@ -76,6 +81,8 @@ t.datetime "updated_at", null: false end + add_index "reviews", ["product_id"], name: "index_reviews_on_product_id" + create_table "users", force: :cascade do |t| t.string "username" t.string "email" From 937888814a84aab6f1185cfd7b1a854b7188f74f Mon Sep 17 00:00:00 2001 From: Kelly Date: Mon, 14 Dec 2015 16:10:48 -0800 Subject: [PATCH 150/299] Complete orders#create, remove orders#destroy, edit, and update --- app/controllers/orders_controller.rb | 64 ++++++++++------------------ app/views/orders/_form.html.erb | 53 ----------------------- app/views/orders/edit.html.erb | 6 --- app/views/orders/new.html.erb | 64 +++++++++++++++++++++++++++- 4 files changed, 84 insertions(+), 103 deletions(-) delete mode 100644 app/views/orders/_form.html.erb delete mode 100644 app/views/orders/edit.html.erb diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index 59bd30a41d..b48e470850 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -1,69 +1,49 @@ class OrdersController < ApplicationController - before_action :set_order, only: [:show, :edit, :update, :destroy] before_action :require_login, only: [:index] before_action :correct_user, only: [:index] + before_action :order_items, only: [:new, :create] + before_action :find_user def index - @user = User.find(params[:user_id]) @orders = @user.orders end - def show - @user = User.find(params[:user_id]) + @order = Order.find(params[:id]) end def new @order = Order.new end - def edit - @user = User.find(params[:user_id]) - end - - def create @order = Order.new(order_params) - - respond_to do |format| - if @order.save - redirect_to user_orders_path - else - render "new" - end + @order_items.each do |oi| + oi.save + @order.order_items << oi end - end - - - def update - respond_to do |format| - if @order.update(order_params) - format.html { redirect_to @order, notice: 'Order was successfully updated.' } - - else - format.html { render :edit } - - end - end - end - - - def destroy - @order.destroy - respond_to do |format| - format.html { redirect_to orders_url, notice: 'Order was successfully destroyed.' } - + if @order.save + redirect_to user_orders_path + else + render :new end end private - def set_order - @order = Order.find(params[:id]) + def order_items + # session[:cart] = { 1 => 2, 3 => 4 } + @order_items = [] + session[:cart].each do |product, quantity| + @order_items.push(OrderItem.new(:product_id => product, :quantity => quantity)) end + end + def find_user + @user = User.find(params[:user_id]) + end - def order_params - params.require(:order).permit(:email, :street, :city, :state, :zip, :cc_num, :cc_exp, :cc_cvv, :cc_name) - end + def order_params + params.require(:order).permit(:email, :street, :city, :state, :zip, :cc_num, :cc_exp, :cc_cvv, :cc_name) + end end diff --git a/app/views/orders/_form.html.erb b/app/views/orders/_form.html.erb deleted file mode 100644 index aa5db6d095..0000000000 --- a/app/views/orders/_form.html.erb +++ /dev/null @@ -1,53 +0,0 @@ -<%= form_for [@user, @order] do |f| %> - <% if @order.errors.any? %> -
    -

    <%= pluralize(@order.errors.count, "error") %> prohibited this order from being saved:

    - -
      - <% @order.errors.full_messages.each do |message| %> -
    • <%= message %>
    • - <% end %> -
    -
    - <% end %> - -
    - <%= f.label :email %>
    - <%= f.text_field :email %> -
    -
    - <%= f.label :street %>
    - <%= f.text_field :street %> -
    -
    - <%= f.label :city %>
    - <%= f.text_field :city %> -
    -
    - <%= f.label :state %>
    - <%= f.text_field :state %> -
    -
    - <%= f.label :zip %>
    - <%= f.text_field :zip %> -
    -
    - <%= f.label :cc_num %>
    - <%= f.text_field :cc_num %> -
    -
    - <%= f.label :cc_exp %>
    - <%= f.date_select :cc_exp %> -
    -
    - <%= f.label :cc_cvv %>
    - <%= f.number_field :cc_cvv %> -
    -
    - <%= f.label :cc_name %>
    - <%= f.text_field :cc_name %> -
    -
    - <%= f.submit %> -
    -<% end %> diff --git a/app/views/orders/edit.html.erb b/app/views/orders/edit.html.erb deleted file mode 100644 index 37f5975e16..0000000000 --- a/app/views/orders/edit.html.erb +++ /dev/null @@ -1,6 +0,0 @@ -

    Editing Order

    - -<%= render 'form' %> - -<%= link_to 'Show', user_order(@order, @user) %> | -<%= link_to 'Back', user_orders(@order, @user) %> diff --git a/app/views/orders/new.html.erb b/app/views/orders/new.html.erb index 006bd0ff4a..af19d0d25f 100644 --- a/app/views/orders/new.html.erb +++ b/app/views/orders/new.html.erb @@ -1,5 +1,65 @@ -

    New Order

    +

    Checkout

    + +

    Purchase Items

    +
      + <% @order_items.each do |oi| %> + <%= oi.product.name %>: <%= oi.quantity %> +
      + <% end %> +
    + +

    Payment Details

    +<%= form_for [@user, @order] do |f| %> + <% if @order.errors.any? %> +
    +
      + <% @order.errors.full_messages.each do |message| %> +
    • <%= message %>
    • + <% end %> +
    +
    + <% end %> + +
    + <%= f.label :email %>
    + <%= f.text_field :email %> +
    +
    + <%= f.label :street %>
    + <%= f.text_field :street %> +
    +
    + <%= f.label :city %>
    + <%= f.text_field :city %> +
    +
    + <%= f.label :state %>
    + <%= f.text_field :state %> +
    +
    + <%= f.label :zip %>
    + <%= f.text_field :zip %> +
    +
    + <%= f.label :cc_num %>
    + <%= f.text_field :cc_num %> +
    +
    + <%= f.label :cc_exp %>
    + <%= f.date_select :cc_exp %> +
    +
    + <%= f.label :cc_cvv %>
    + <%= f.number_field :cc_cvv %> +
    +
    + <%= f.label :cc_name %>
    + <%= f.text_field :cc_name %> +
    +
    + <%= f.submit %> +
    +<% end %> -<%= render 'form' %> <%= link_to 'Back', user_orders_path(@user.id, @order.id) %> From dd4d0e2e0920e3df735da36b5b676c59a20348e7 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Mon, 14 Dec 2015 16:15:00 -0800 Subject: [PATCH 151/299] change default password for users --- seeds_csvs/users.csv | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/seeds_csvs/users.csv b/seeds_csvs/users.csv index ed45bc149a..b729c3723c 100644 --- a/seeds_csvs/users.csv +++ b/seeds_csvs/users.csv @@ -1,11 +1,11 @@ username,email,password,password_confirmation,name -user1,user1@example.com,zAJeq7zugu,zAJeq7zugu,User One -user2,user2@example.com,breha8uMaF,breha8uMaF,User Two -user3,user3@example.com,tHu5etudru,tHu5etudru,User Three -user4,user4@example.com,pesA7raket,pesA7raket,User Four -user5,user5@example.com,wrucast7sW,wrucast7sW,User Five -user6,user6@example.com,TreSwe6erE,TreSwe6erE,User Six -user7,user7@example.com,PeJaVa7ewr,PeJaVa7ewr,User Seven -user8,user8@example.com,TRu2hutRuf,TRu2hutRuf,User Eight -user9,user9@example.com,tute6Eqagu,tute6Eqagu,User Nine -user10,user10@example.com,Wref8AQeye,Wref8AQeye,User Ten +user1,user1@example.com,password,password,User One +user2,user2@example.com,password,password,User Two +user3,user3@example.com,password,password,User Three +user4,user4@example.com,password,password,User Four +user5,user5@example.com,password,password,User Five +user6,user6@example.com,password,password,User Six +user7,user7@example.com,password,password,User Seven +user8,user8@example.com,password,password,User Eight +user9,user9@example.com,password,password,User Nine +user10,user10@example.com,password,password,User Ten From b0b3e020a8d1ca8eb0d16268b7d2cad078b080ec Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Mon, 14 Dec 2015 16:41:09 -0800 Subject: [PATCH 152/299] update products controller for logging in --- spec/controllers/products_controller_spec.rb | 62 ++++++++++++-------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/spec/controllers/products_controller_spec.rb b/spec/controllers/products_controller_spec.rb index 631a45875c..2cf8549a39 100644 --- a/spec/controllers/products_controller_spec.rb +++ b/spec/controllers/products_controller_spec.rb @@ -1,16 +1,18 @@ require 'rails_helper' RSpec.describe ProductsController, type: :controller do - let (:sample_user) { - User.create(username: "Kelly", email: "Kelly@kelly.com", password: "password") - } + let (:product) { FactoryGirl.create(:product) } - let (:sample_product) { - Product.create(name: "Rubber ducky", price: "500", stock: "1", user_id: sample_user.id) - } + # let (:sample_user) { + # User.create(username: "Kelly", email: "Kelly@kelly.com", password: "password") + # } + # + # let (:product) { + # Product.create(name: "Rubber ducky", price: "500", stock: "1", user_id: sample_user.id) + # } let (:bad_params) { - { user_id: sample_user.id, + { user_id: product.user.id, product: { price: "zzz" } } } @@ -24,7 +26,7 @@ } let (:good_params) { - { user_id: sample_user.id, categories: [sample_category_1.id, sample_category_2.id], product: { name: "Loofah", price: "600", stock: "2", photo_url: "hi.jpg" } } + { user_id: product.user.id, categories: [sample_category_1.id, sample_category_2.id], product: { name: "Loofah", price: "600", stock: "2", photo_url: "hi.jpg" } } } describe "GET 'index'" do @@ -36,48 +38,58 @@ describe "GET 'show'" do it "renders the show view" do - get :show, id: sample_product.id, user_id: sample_product.user_id + get :show, {id: product.id, user_id: product.user.id}, user_id: product.user.id expect(subject).to render_template :show end + # it "redirects to root if not correct user" do + # get :show, {id: product.id, user_id: product.user.id + 1 }, user_id: product.user.id + # expect(subject).to redirect_to root_path + # end end describe "GET 'new'" do it "renders new view" do - get :new, user_id: sample_user.id + get :new, {user_id: product.user.id}, {user_id: product.user.id} expect(subject).to render_template :new end end describe "POST 'create'" do - it "redirects to users's products page" do - post :create, good_params - expect(subject).to redirect_to user_products_path(Product.all.last.user_id) + context "with valid create params" do + it "redirects to users's products page" do + post :create, good_params, user_id: product.user.id + expect(subject).to redirect_to user_products_path(product.user.id) + end end - it "renders new template on error" do - post :create, bad_params - expect(subject).to render_template :new + context "with invalid create params" do + it "re-renders new template" do + post :create, bad_params, user_id: product.user.id + expect(subject).to render_template :new + end end end describe "GET 'edit'" do it "renders edit view" do - get :edit, id: sample_product.id, user_id: sample_product.user_id + get :edit, { id: product.id, user_id: product.user.id }, user_id: product.user.id expect(subject).to render_template :edit end end describe "PATCH 'update'" do - it "redirects to users's products page" do - patch :update, good_params.merge({id: sample_product.id}) - expect(subject).to redirect_to user_products_path(sample_product.user) - expect(Product.all.last.name).to eq "Loofah" + context "with valid update params" do + it "redirects to users's products page" do + patch :update, good_params.merge({id: product.id}), user_id: product.user.id + expect(subject).to redirect_to user_products_path(product.user) + end end - it "renders edit template on error" do - patch :update, bad_params.merge({id: sample_product.id}) - expect(subject).to render_template :edit - expect(Product.all.last.name).to eq "Rubber ducky" + context "with invalid update params" do + it "renders edit template on error" do + patch :update, bad_params.merge({id: product.id}), user_id: product.user.id + expect(subject).to render_template :edit + end end end end From 6549eef19e86d96c618a7f2a74371d785eb98734 Mon Sep 17 00:00:00 2001 From: Kelly Date: Mon, 14 Dec 2015 17:13:32 -0800 Subject: [PATCH 153/299] Update order controller specs --- spec/controllers/orders_controller_spec.rb | 73 +++++++++++++--------- 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/spec/controllers/orders_controller_spec.rb b/spec/controllers/orders_controller_spec.rb index 51670cd9b8..00f3d17878 100644 --- a/spec/controllers/orders_controller_spec.rb +++ b/spec/controllers/orders_controller_spec.rb @@ -1,6 +1,18 @@ require 'rails_helper' RSpec.describe OrdersController, type: :controller do + let (:sample_user) { + User.create(username: "Kelly", email: "Kelly@kelly.com", password: "password") + } + + let (:sample_product) { + Product.create(name: "Rubber ducky", price: "500", stock: "1", user_id: sample_user.id) + } + + let (:sample_order_item) { + User.create(product_id: sample_product.id, order_id: sample_order.id, quantity: "3") + } + let (:sample_order) { Order.create } @@ -13,28 +25,31 @@ describe "GET 'index'" do it "is successful" do - get :index + session[:user_id] = sample_user.id + get :index, user_id: sample_user.id expect(response.status).to eq 200 end end describe "GET 'show'" do it "renders the show view" do - get :show, id: sample_order.id + get :show, id: sample_order.id, user_id: sample_user.id expect(subject).to render_template :show end end describe "GET 'new'" do it "renders new view" do - get :new + session[:cart] = { 1 => 2, 3 => 4 } + get :new, user_id: sample_user.id expect(subject).to render_template :new end end describe "POST 'create'" do it "redirects to index page" do - post :create + session[:cart] = { 1 => 2, 3 => 4 } + post :create, { user_id: sample_user.id } expect(subject).to redirect_to orders_path end @@ -44,31 +59,31 @@ end end - describe "GET 'edit'" do - it "renders edit view" do - get :edit, id: sample_order.id - expect(subject).to render_template :edit - end - end - - describe "PATCH 'update'" do - it "redirects to index page" do - patch :update, { order: { zip: "02780" } } - expect(subject).to redirect_to orders_path - expect(Order.all.last.zip).to eq "02780" - end + # describe "GET 'edit'" do + # it "renders edit view" do + # get :edit, id: sample_order.id + # expect(subject).to render_template :edit + # end + # end - it "renders edit template on error" do - patch :update, bad_params - expect(subject).to render_template :edit - expect(Order.all.last.zip).to eq nil - end - end + # describe "PATCH 'update'" do + # it "redirects to index page" do + # patch :update, { order: { zip: "02780" } } + # expect(subject).to redirect_to orders_path + # expect(Order.all.last.zip).to eq "02780" + # end + # + # it "renders edit template on error" do + # patch :update, bad_params + # expect(subject).to render_template :edit + # expect(Order.all.last.zip).to eq nil + # end + # end - describe "DELETE 'destroy'" do - it "redirects to index page" do - delete :destroy, id: sample_order.id - expect(subject).to redirect_to orders_path - end - end + # describe "DELETE 'destroy'" do + # it "redirects to index page" do + # delete :destroy, id: sample_order.id + # expect(subject).to redirect_to orders_path + # end + # end end From 2b512c4d838f4de9460c256aae84b137bd140921 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Mon, 14 Dec 2015 20:28:17 -0800 Subject: [PATCH 154/299] refactor layout container div --- app/views/layouts/application.html.erb | 2 +- app/views/reviews/new.html.erb | 10 +-- app/views/sessions/new.html.erb | 29 ++++---- app/views/shared/_display_products.html.erb | 82 ++++++++++----------- app/views/shared/_products.html.erb | 57 +++++++------- app/views/users/edit.html.erb | 10 +-- app/views/users/new.html.erb | 6 +- app/views/welcome/index.html.erb | 2 - 8 files changed, 92 insertions(+), 106 deletions(-) diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 8272ecda37..7fa315ca18 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -9,7 +9,7 @@
    <%= render 'shared/navbar' %> + <%= yield %>
    - <%= yield %> diff --git a/app/views/reviews/new.html.erb b/app/views/reviews/new.html.erb index ee9d89a708..e66e52c643 100644 --- a/app/views/reviews/new.html.erb +++ b/app/views/reviews/new.html.erb @@ -1,6 +1,4 @@ -
    -

    New Review

    - <%= render 'form' %> -
    - <%= link_to 'Back', user_product_reviews_path(@product.user, @product), class: "btn btn-primary" %> -
    +

    New Review

    +<%= render 'form' %> +
    +<%= link_to 'Back', user_product_reviews_path(@product.user, @product), class: "btn btn-primary" %> diff --git a/app/views/sessions/new.html.erb b/app/views/sessions/new.html.erb index 31aa7ca22a..6c86ea6fb1 100644 --- a/app/views/sessions/new.html.erb +++ b/app/views/sessions/new.html.erb @@ -1,16 +1,13 @@ -
    - <%= form_for(:session_data, url: login_path, :html => {:class => "form-signin"}) do |f| %> - <% if !flash.now[:danger].nil? %> -

    <%= flash.now[:danger] %>

    - <% end %> - - <%= f.label :username, class: "sr-only" %> - <%= f.text_field :username, class: "form-control", placeholder: "Username" %> -
    - <%= f.label :password, class: "sr-only" %> - <%= f.password_field :password, class: "form-control", placeholder: "Password" %> -
    - <%= f.submit "Sign in", class: "btn btn-lg btn-primary btn-block" %> - <% end %> - -
    +<%= form_for(:session_data, url: login_path, :html => {:class => "form-signin"}) do |f| %> +<% if !flash.now[:danger].nil? %> +

    <%= flash.now[:danger] %>

    +<% end %> + + <%= f.label :username, class: "sr-only" %> + <%= f.text_field :username, class: "form-control", placeholder: "Username" %> +
    + <%= f.label :password, class: "sr-only" %> + <%= f.password_field :password, class: "form-control", placeholder: "Password" %> +
    + <%= f.submit "Sign in", class: "btn btn-lg btn-primary btn-block" %> + <% end %> diff --git a/app/views/shared/_display_products.html.erb b/app/views/shared/_display_products.html.erb index 4b93c314f2..1d658eaca2 100644 --- a/app/views/shared/_display_products.html.erb +++ b/app/views/shared/_display_products.html.erb @@ -1,45 +1,43 @@ -
    - <% if @products.respond_to?(:total_pages) %> - <%= will_paginate @products %> - <% end %> - <% @products.to_ary.in_groups_of(4, false) do |group| %> -
    - <% group.each do |product| %> -
    -
    -
    - <%= image_tag product.photo_url, alt: "product photo" %> -
    -
    -
    <%= dollar_price(product.price) %>
    -
    <%= link_to product.name, user_product_path(product.user_id, product.id) %> -
    -

    - <% if !product.description.nil? %> - <%= product.description %> - <% else %> -
    - <% end %> -

    -

    <%= product.stock %> Available

    -
    -
    -

    <%= pluralize(product.reviews.count, "Review") %>

    -

    - <% product.review_rounded.times do %> - - <% end %> - <% (5 - product.review_rounded).times do %> - +<% if @products.respond_to?(:total_pages) %> + <%= will_paginate @products %> +<% end %> +<% @products.to_ary.in_groups_of(4, false) do |group| %> +

    + <% group.each do |product| %> +
    +
    +
    + <%= image_tag product.photo_url, alt: "product photo" %> +
    +
    +
    <%= dollar_price(product.price) %>
    +
    <%= link_to product.name, user_product_path(product.user_id, product.id) %> +
    +

    + <% if !product.description.nil? %> + <%= product.description %> + <% else %> +
    <% end %>

    -
    -
    +

    <%= product.stock %> Available

    +
    +
    +

    <%= pluralize(product.reviews.count, "Review") %>

    +

    + <% product.review_rounded.times do %> + + <% end %> + <% (5 - product.review_rounded).times do %> + + <% end %> +

    +
    - <% end %> -
    - <% end %> - <% if @products.respond_to?(:total_pages) %> - <%= will_paginate @products %> - <% end %> -
    +
    + <% end %> +
    +<% end %> +<% if @products.respond_to?(:total_pages) %> + <%= will_paginate @products %> +<% end %> diff --git a/app/views/shared/_products.html.erb b/app/views/shared/_products.html.erb index 1a71f0a1c1..8083a6ffcb 100644 --- a/app/views/shared/_products.html.erb +++ b/app/views/shared/_products.html.erb @@ -1,34 +1,33 @@ <%= will_paginate @products %> -
    - <% @products.to_ary.in_groups_of(4, false) do |group| %> -
    - <% group.each do |product| %> -
    -
    -
    - <%= image_tag product.photo_url, alt: "product photo" %> -
    -
    -
    <%= dollar_price(product.price) %>
    -
    <%= link_to product.name, user_product_path(product.user_id, product.id) %> -
    -

    - <% if !product.description.nil? %> - <%= product.description %> - <% else %> -
    - <% end %> -

    -

    <%= product.stock %> Available

    -

    - <%= link_to "Edit item", edit_user_product_path(product.user.id, product.id) %> -

    -

    <%= link_to "View Reviews", user_product_reviews_path(product.user.id, product.id) %>

    -
    +<% @products.to_ary.in_groups_of(4, false) do |group| %> +
    + <% group.each do |product| %> +
    +
    +
    + <%= image_tag product.photo_url, alt: "product photo" %>
    +
    +
    <%= dollar_price(product.price) %>
    +
    <%= link_to product.name, user_product_path(product.user_id, product.id) %> +
    +

    + <% if !product.description.nil? %> + <%= product.description %> + <% else %> +
    + <% end %> +

    +

    <%= product.stock %> Available

    +

    + <%= link_to "Edit item", edit_user_product_path(product.user.id, product.id) %> +

    +

    <%= link_to "View Reviews", user_product_reviews_path(product.user.id, product.id) %>

    +
    - <% end %> -
    - <% end %> +
    + <% end %> +
    +<% end %> <%= will_paginate @products %> diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb index d4a005c8ed..ebc4f5dbb0 100644 --- a/app/views/users/edit.html.erb +++ b/app/views/users/edit.html.erb @@ -1,6 +1,4 @@ -
    -

    Update Your Profile

    - <%= render partial: 'form', locals: { submit_text: "Update My Profile" } %> -
    - <%= link_to 'Cancel', @user, class: "btn btn-primary" %> -
    +

    Update Your Profile

    +<%= render partial: 'form', locals: { submit_text: "Update My Profile" } %> +
    +<%= link_to 'Cancel', @user, class: "btn btn-primary" %> diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb index 58ae321665..ba431a12b1 100644 --- a/app/views/users/new.html.erb +++ b/app/views/users/new.html.erb @@ -1,4 +1,2 @@ -
    -

    New User

    - <%= render partial: 'form', locals: {submit_text: "Create My Account"} %> -
    +

    New User

    +<%= render partial: 'form', locals: {submit_text: "Create My Account"} %> diff --git a/app/views/welcome/index.html.erb b/app/views/welcome/index.html.erb index 3c2d18ea91..5d1b5ecc67 100644 --- a/app/views/welcome/index.html.erb +++ b/app/views/welcome/index.html.erb @@ -1,7 +1,6 @@

    Wetsy Homepage

    -
    <% if !flash[:success].nil? %>
    @@ -17,4 +16,3 @@

    Find the Best Products for Fun Water Times


    <%= render 'shared/display_products' %> -
    From ce7b98e563a11e7e9b00e9ecccaea0b8c900d3e8 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Mon, 14 Dec 2015 20:42:09 -0800 Subject: [PATCH 155/299] create flash message partial --- app/controllers/application_controller.rb | 2 +- app/helpers/application_helper.rb | 15 +++++++++++++++ app/views/layouts/application.html.erb | 1 + app/views/shared/_flash_messages.html.erb | 6 ++++++ app/views/welcome/index.html.erb | 18 +++--------------- 5 files changed, 26 insertions(+), 16 deletions(-) create mode 100644 app/views/shared/_flash_messages.html.erb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index a4d9f35737..a6071ab928 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -22,7 +22,7 @@ def correct_user def require_login if current_user.nil? - flash[:error] = "You must be logged in." + flash[:error] = "You must be logged in to complete that action." redirect_to login_path end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index d7cff93e87..a4026cd5b3 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -2,4 +2,19 @@ module ApplicationHelper def dollar_price(amount) number_to_currency(amount / 100.0) end + + def bootstrap_class_for flash_type + case flash_type + when "success" + "alert-success" + when "error" + "alert-danger" + when "alert" + "alert-block" + when "notice" + "alert-info" + else + flash_type.to_s + end + end end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 7fa315ca18..fb188d741d 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -9,6 +9,7 @@
    <%= render 'shared/navbar' %> + <%= render partial: "shared/flash_messages", flash: flash %> <%= yield %>
    diff --git a/app/views/shared/_flash_messages.html.erb b/app/views/shared/_flash_messages.html.erb new file mode 100644 index 0000000000..23a19059f9 --- /dev/null +++ b/app/views/shared/_flash_messages.html.erb @@ -0,0 +1,6 @@ +<% flash.each do |type, message| %> +
    + + <%= message %> +
    +<% end %> diff --git a/app/views/welcome/index.html.erb b/app/views/welcome/index.html.erb index 5d1b5ecc67..c1f5971c2b 100644 --- a/app/views/welcome/index.html.erb +++ b/app/views/welcome/index.html.erb @@ -1,18 +1,6 @@

    Wetsy Homepage

    - <% if !flash[:success].nil? %> -
    - - <%= flash[:success] %> -
    - <% end %> - <% if !flash[:error].nil? %> -
    - - <%= flash[:error] %> -
    - <% end %> -

    Find the Best Products for Fun Water Times

    -
    - <%= render 'shared/display_products' %> +

    Find the Best Products for Fun Water Times

    +
    +<%= render 'shared/display_products' %> From ddb4e94843cd9d675f5938e8582f14c2894e08ac Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Mon, 14 Dec 2015 20:56:20 -0800 Subject: [PATCH 156/299] show correct product display for user/guest on user products page --- app/controllers/products_controller.rb | 1 + app/views/users/products.html.erb | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index e16a852656..d58df04b49 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -3,6 +3,7 @@ class ProductsController < ApplicationController before_action :find_user, only: [:new, :edit, :create, :update] before_action :all_categories, only: [:new, :edit, :create, :update] before_action :require_login, only: [:new, :edit, :create, :update] + before_action :correct_user, only: [:new, :edit, :create, :update] def index @products = Product.all.paginate(page: params[:page], per_page: 12) diff --git a/app/views/users/products.html.erb b/app/views/users/products.html.erb index 65e7cdadee..27d32d45cd 100644 --- a/app/views/users/products.html.erb +++ b/app/views/users/products.html.erb @@ -1,3 +1,10 @@ -

    <%= @user.name %>'s Products

    -<%= render partial: 'shared/products' %> -<%= link_to "Add a Product", new_user_product_path(@user) %> +

    <%= @user.name %>'s Products +<% if logged_in? && current_user == @user %> + <%= link_to "Add a Product", new_user_product_path(@user) %> +<% end %> +

    +<% if logged_in? && current_user == @user %> + <%= render partial: 'shared/products' %> +<% else %> + <%= render partial: 'shared/display_products' %> +<% end %> From ab803e59dd68ce89a24403d68e4e3c1e869bbb61 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Mon, 14 Dec 2015 21:15:10 -0800 Subject: [PATCH 157/299] create line for under navbar --- app/assets/stylesheets/application.scss | 20 +++++++++++++++++++- app/views/shared/_navbar.html.erb | 2 +- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 8708f9d922..6a1bf55d05 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -21,6 +21,9 @@ $header_font: 'Slabo 27px', serif; $small_header_font: 'Lora', serif; $body-font: 'Lato', sans-serif; +$dark-blue: rgb(10, 74, 121); +$light-blue: rgb(0, 112, 172); + h1 { font-family: $header_font; @@ -46,7 +49,22 @@ h5 { .navbar-clear { background-color: rgba(248, 248, 248, 0); - border-color: rgba(248, 248, 248, 0); + border: 0px solid transparent; + border-radius: 0px; + border-bottom: 1px solid #e7e7e7; + // border-color: rgba(248, 248, 248, 0); +} + +.navbar-default { + .navbar-brand { + font-family: $header_font; + font-size: 2em; + font-weight: bold; + color: $light-blue; + a:hover { + color: $dark-blue; + } + } } .thumbnail img { diff --git a/app/views/shared/_navbar.html.erb b/app/views/shared/_navbar.html.erb index 4b0f14fc9e..82bb67aed9 100644 --- a/app/views/shared/_navbar.html.erb +++ b/app/views/shared/_navbar.html.erb @@ -8,7 +8,7 @@ - Wetsy +
    From 18a9538db7051cd18754f3374676c5c480d0f082 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Mon, 14 Dec 2015 22:00:42 -0800 Subject: [PATCH 158/299] style show page --- app/views/products/show.html.erb | 93 ++++++++++++++++---------------- config/routes.rb | 2 + 2 files changed, 47 insertions(+), 48 deletions(-) diff --git a/app/views/products/show.html.erb b/app/views/products/show.html.erb index bb9b40b644..43ffa51a20 100644 --- a/app/views/products/show.html.erb +++ b/app/views/products/show.html.erb @@ -1,48 +1,45 @@ -

    <%= notice %>

    - -

    - Name: - <%= @product.name %> -

    - -

    - Price: - <%= @product.price %> -

    - -

    - User: - <%= @product.user_id %> -

    - -

    - Photo url: - <%= @product.photo_url %> -

    - -

    - Stock: - <%= @product.stock %> -

    - -

    - Description: - <%= @product.description %> -

    - -

    - Categories: - <% @product.categories.each do |c| %> - <%= c.name %> - <% end %> -

    - -

    - Active: - <%= @product.active %> -

    - -<%= link_to 'Edit', edit_user_product_path(@product.user_id, @product.id) %> | -<%= link_to 'Back', user_products_path(@product.user_id) %> -<%= link_to 'Reviews', user_product_reviews_path(@product.user_id, @product.id) %> -<%= link_to 'Add to Cart', cart_path %> +
    +
    +

    Merchant: <%= link_to @product.user.name, user_path(@product.user.id) %>

    +
    +
    +
    +
    +
      + <% @product.categories.each do |cat| %> + <%= link_to cat.name, category_path(cat.id) %> + <% end %> +
    +
    +
    +
    +
    +
    +
    + <%= image_tag @product.photo_url, alt: "product photo" %> +
    +
    +
    +
    + +

    <%= @product.name %> +

    +

    <%= dollar_price(@product.price) %>

    +

    <%= @product.description %>

    +

    <%= @product.stock %> Available

    + <%= form_tag({controller: "carts", action: "add_product"}, method: :post) do %> + <%= submit_tag "Add to Cart", class: "btn btn-lg btn-primary btn-block" %> + <% end %> +
    +
    +
    +
    + +

    TODO: Add a form for adding a review

    +
    +
    + +

    TODO: Add the list of ratings

    +

    +
    +
    diff --git a/config/routes.rb b/config/routes.rb index 26c3a133a7..61df9ccae8 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -14,6 +14,8 @@ end end + post 'cart/' => 'carts#add_product', as: :add_to_cart + get 'cart/' => 'carts#show', as: :cart get 'products/' => 'products#index', as: :products get 'login/' => 'sessions#new', as: :login From 1019cb8e8e47691cf97db7d452512720d75d5f89 Mon Sep 17 00:00:00 2001 From: Kelly Date: Mon, 14 Dec 2015 23:06:07 -0800 Subject: [PATCH 159/299] Complete order controller tests, except for create --- app/controllers/orders_controller.rb | 2 +- spec/controllers/orders_controller_spec.rb | 28 ++++++++++------------ 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index b48e470850..15e5b628a9 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -32,7 +32,7 @@ def create private def order_items - # session[:cart] = { 1 => 2, 3 => 4 } + session[:cart] = { 3 => 2, 5 => 4 } @order_items = [] session[:cart].each do |product, quantity| @order_items.push(OrderItem.new(:product_id => product, :quantity => quantity)) diff --git a/spec/controllers/orders_controller_spec.rb b/spec/controllers/orders_controller_spec.rb index 00f3d17878..4f617daf7c 100644 --- a/spec/controllers/orders_controller_spec.rb +++ b/spec/controllers/orders_controller_spec.rb @@ -5,20 +5,14 @@ User.create(username: "Kelly", email: "Kelly@kelly.com", password: "password") } - let (:sample_product) { - Product.create(name: "Rubber ducky", price: "500", stock: "1", user_id: sample_user.id) - } - - let (:sample_order_item) { - User.create(product_id: sample_product.id, order_id: sample_order.id, quantity: "3") - } - - let (:sample_order) { - Order.create + let (:good_params) { + { user_id: sample_user.id, + order: { email: "Kelly@kelly.com", street: "test" , city: "Seattle", state: "WA", zip: "98116", cc_num: "123", cc_cvv: "123", cc_name: "Kelly"} + } } let (:bad_params) { - { + { user_id: sample_user.id, order: { zip: "zzz" } } } @@ -33,6 +27,7 @@ describe "GET 'show'" do it "renders the show view" do + sample_order = Order.create(good_params[:order]) get :show, id: sample_order.id, user_id: sample_user.id expect(subject).to render_template :show end @@ -40,7 +35,7 @@ describe "GET 'new'" do it "renders new view" do - session[:cart] = { 1 => 2, 3 => 4 } + # session[:cart] = { 1 => 2, 3 => 4 } get :new, user_id: sample_user.id expect(subject).to render_template :new end @@ -48,12 +43,15 @@ describe "POST 'create'" do it "redirects to index page" do - session[:cart] = { 1 => 2, 3 => 4 } - post :create, { user_id: sample_user.id } - expect(subject).to redirect_to orders_path + # session[:cart] = { 1 => 2, 3 => 4 } + session[:user_id] = sample_user.id + binding.pry + post :create, good_params + expect(subject).to redirect_to user_orders_path end it "renders new template on error" do + session[:cart] = { 1 => 2, 3 => 4 } post :create, bad_params expect(subject).to render_template :new end From 28ae6f28c8f261a0f09b67df38be46a354be51da Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 15 Dec 2015 09:03:04 -0800 Subject: [PATCH 160/299] style categories browse page --- app/views/categories/index.html.erb | 71 +++++++++++++++++++---------- 1 file changed, 47 insertions(+), 24 deletions(-) diff --git a/app/views/categories/index.html.erb b/app/views/categories/index.html.erb index f0e18cca21..48f076dda4 100644 --- a/app/views/categories/index.html.erb +++ b/app/views/categories/index.html.erb @@ -1,27 +1,50 @@ -

    <%= notice %>

    - -

    Categories

    - - - - - - - - - - - <% @categories.each do |category| %> - - - - - - +
    +
    +

    Looking for Inspiration? Shop by Category

    +
    +
    +
    +
    +
    +
    +
      + <% @categories.each do |cat| %> + <%= link_to cat.name, category_path(cat.id) %> + <% end %> +
    +
    +
    +
    + <% count = 0 %> + <% @categories.each do |category| %> + <% product = category.products.first %> +
    +

    <%= category.name.capitalize %>

    +

    Featured Product:

    +
    +
    + <%= image_tag product.photo_url, alt: "product photo" %> +
    +
    +
    <%= dollar_price(product.price) %>
    +
    <%= link_to product.name, user_product_path(product.user_id, product.id) %> +
    +

    + <% if !product.description.nil? %> + <%= product.description %> + <% else %> +
    + <% end %> +

    +

    <%= product.stock %> Available

    +
    +
    +
    + <% count += 1 %> + <% if count % 4 == 0 %> +
    +
    <% end %> -
    -
    Name
    <%= category.name %><%= link_to 'Show', category %><%= link_to 'Edit', edit_category_path(category) %><%= link_to 'Destroy', category_path(category), method: :delete, data: { confirm: 'Are you sure?' } %>
    - -
    + <% end %> <%= link_to 'New Category', new_category_path %> From 145c7f28db0096eb6b4e9ca963e11e9cbab51478 Mon Sep 17 00:00:00 2001 From: Tammy Date: Tue, 15 Dec 2015 09:53:56 -0800 Subject: [PATCH 161/299] I think we have a working cart --- app/controllers/carts_controller.rb | 29 ++++++++++++++++++++---- app/models/cart.rb | 35 ++--------------------------- app/views/carts/index.html.erb | 18 +++++++++++++++ app/views/carts/show.html.erb | 17 -------------- config/routes.rb | 2 +- 5 files changed, 46 insertions(+), 55 deletions(-) create mode 100644 app/views/carts/index.html.erb delete mode 100644 app/views/carts/show.html.erb diff --git a/app/controllers/carts_controller.rb b/app/controllers/carts_controller.rb index 919111a70c..ca093a338d 100644 --- a/app/controllers/carts_controller.rb +++ b/app/controllers/carts_controller.rb @@ -1,14 +1,35 @@ class CartsController < ApplicationController - def show + def index + if session[:cart] + @cart = session[:cart] + else + @cart = {} + end end - def add_product - quantity = params[:quantity] + def add product_id = params[:product_id] + if session[:cart] + cart = session[:cart] + else + session[:cart] = {} + cart = session[:cart] + end + # if the cart already has the product -> just add one + # if not -> set the quantity to one + if cart[product_id] + cart[product_id] = cart[product_id] + 1 + else + cart[product_id] = 1 + end - add_product(product_id, quantity) redirect_to product_path(product_id) end + def clearCart + session[:cart] = nil + redirect_to index + end + end diff --git a/app/models/cart.rb b/app/models/cart.rb index fb6efdbf48..493a9521f3 100644 --- a/app/models/cart.rb +++ b/app/models/cart.rb @@ -1,40 +1,9 @@ class Cart - - def initialize(session) - @session = session - @session[:cart] ||= {} - end - - def add_product(product_id, quantity) - initialize - @session[:cart] = {:product_id => quantity } - end - - - def cart_count - if @session[:cart]!= {} - return @session[:cart].count - else - return 0 - end - end - - #return an array of product objects that are in the cart - def find_products - product = [] - order_items = new_order_items - order_items.each do |order_item| - product = Product.find(order_item.product_id) - products.push(product) - end - return products - end - #Get subtotal of the cart items - def subtotal + def self.subtotal(cart) subtotal = 0 - @session[:cart].each do |product, quantity| + cart.each do |product, quantity| price = Product.find(product).price subtotal += (price * quantity) end diff --git a/app/views/carts/index.html.erb b/app/views/carts/index.html.erb new file mode 100644 index 0000000000..1b7b154ae0 --- /dev/null +++ b/app/views/carts/index.html.erb @@ -0,0 +1,18 @@ +

    Cart

    + +<% @cart.each do |product_id, quantity| %> + <% product = Product.find(product_id) %> + + + + + + + + + + + <% end %> +
    Product Description Price
    <%= link_to product.name, user_product(product.user_id, product.id) %> <%= product.description %> <%= product.price %> <%= link_to 'remove-NOT WORKING', cart_path %>
    + +

    Items total $<%= Cart.subtotal(@cart) %>

    diff --git a/app/views/carts/show.html.erb b/app/views/carts/show.html.erb deleted file mode 100644 index 92150369a0..0000000000 --- a/app/views/carts/show.html.erb +++ /dev/null @@ -1,17 +0,0 @@ -

    Cart

    -<% products = find_products %> - - - - - <% products.each do |product| %> - - - - - - - <% end %> -
    Product Description Price
    <%= link_to product.name, user_product(product.user_id, product.id) %> <%= product.description %> <%= product.price %> <%= link_to 'remove-NOT WORKING', cart_path %>
    - -

    Item total $<%= subtotal %>

    diff --git a/config/routes.rb b/config/routes.rb index 26c3a133a7..30d794367f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -14,7 +14,7 @@ end end - get 'cart/' => 'carts#show', as: :cart + get 'cart/' => 'carts#index', as: :cart get 'products/' => 'products#index', as: :products get 'login/' => 'sessions#new', as: :login post 'login/' => 'sessions#create' From a541bec9215d375dbfe58dacc425304fa9b350cf Mon Sep 17 00:00:00 2001 From: Tammy Date: Tue, 15 Dec 2015 09:57:47 -0800 Subject: [PATCH 162/299] fixed the routes --- config/routes.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index 04f9924c1b..2d69eac178 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -14,13 +14,9 @@ end end -<<<<<<< HEAD + get 'cart/' => 'carts#index', as: :cart -======= post 'cart/' => 'carts#add_product', as: :add_to_cart - - get 'cart/' => 'carts#show', as: :cart ->>>>>>> 28ae6f28c8f261a0f09b67df38be46a354be51da get 'products/' => 'products#index', as: :products get 'login/' => 'sessions#new', as: :login post 'login/' => 'sessions#create' From 9a3dbd3d6a356801526116d6d2840eaa8f9332e0 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 15 Dec 2015 10:17:33 -0800 Subject: [PATCH 163/299] style product show page --- app/controllers/products_controller.rb | 1 + app/controllers/reviews_controller.rb | 2 +- app/helpers/application_helper.rb | 4 ++ app/views/products/show.html.erb | 51 ++++++++++++++++++-------- app/views/reviews/_form.html.erb | 2 +- 5 files changed, 42 insertions(+), 18 deletions(-) diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index d58df04b49..aa06a9c2f7 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -10,6 +10,7 @@ def index end def show + @review = Review.new end def new diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb index 2fe10f7964..8a58663bf4 100644 --- a/app/controllers/reviews_controller.rb +++ b/app/controllers/reviews_controller.rb @@ -25,7 +25,7 @@ def create r.product_id = params[:product_id] end if @review.save - redirect_to user_product_reviews_path(@review.product.user, @review.product) + redirect_to user_product_path(@review.product.user, @review.product) else render :new end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index a4026cd5b3..a1163162da 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -17,4 +17,8 @@ def bootstrap_class_for flash_type flash_type.to_s end end + + def readable_date(date) + date.strftime('%b %-e, %Y') + end end diff --git a/app/views/products/show.html.erb b/app/views/products/show.html.erb index 43ffa51a20..1db6e0dd8f 100644 --- a/app/views/products/show.html.erb +++ b/app/views/products/show.html.erb @@ -14,32 +14,51 @@
    -
    -
    - <%= image_tag @product.photo_url, alt: "product photo" %> -
    -
    + <%= image_tag @product.photo_url, alt: "product photo", class: "img-responsive" %>
    -
    - -

    <%= @product.name %> -

    +
    +

    <%= @product.name %>

    <%= dollar_price(@product.price) %>

    <%= @product.description %>

    <%= @product.stock %> Available

    <%= form_tag({controller: "carts", action: "add_product"}, method: :post) do %> - <%= submit_tag "Add to Cart", class: "btn btn-lg btn-primary btn-block" %> + <%= submit_tag "Add to Cart", class: "btn btn-lg btn-success btn-block" %> <% end %>
    -
    - -

    TODO: Add a form for adding a review

    +
    +

    Purchased this Product? Leave a Review:

    + + <%= render "reviews/form", :review => @review, :product => @product %>
    -
    +
    +

    Product Reviews

    -

    TODO: Add the list of ratings

    -

    + <% @product.reviews.each do |review| %> +
    +
    +

    + <% review.rating.times do %> + + <% end %> + <% (5 - review.rating).times do %> + + <% end %> +

    +
    +
    +

    <%= readable_date(review.updated_at) %>

    +
    +
    + <% if review.description %> +
    +
    +

    <%= review.description %>

    +
    +
    + <% end %> +
    + <% end %>
    diff --git a/app/views/reviews/_form.html.erb b/app/views/reviews/_form.html.erb index 88d2caf062..12be60db35 100644 --- a/app/views/reviews/_form.html.erb +++ b/app/views/reviews/_form.html.erb @@ -7,7 +7,7 @@
    -
    +
    <%= form_for [@product.user, @product, @review], class: "form-group" do |f| %> <%= f.label :rating, "Rating (1-5)" %>
    <%= f.number_field :rating, class: 'form-control', :required => true%> From 08da19fe44f0b40825b8139e6f44a46e383f601c Mon Sep 17 00:00:00 2001 From: Tammy Date: Tue, 15 Dec 2015 10:30:32 -0800 Subject: [PATCH 164/299] changed the add to cart route --- app/controllers/carts_controller.rb | 5 +++-- app/views/products/show.html.erb | 2 +- config/routes.rb | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/controllers/carts_controller.rb b/app/controllers/carts_controller.rb index ca093a338d..184be23c47 100644 --- a/app/controllers/carts_controller.rb +++ b/app/controllers/carts_controller.rb @@ -9,7 +9,8 @@ def index end def add - product_id = params[:product_id] + product = Product.find(params[:id]) + product_id = params[:id] if session[:cart] cart = session[:cart] else @@ -24,7 +25,7 @@ def add cart[product_id] = 1 end - redirect_to product_path(product_id) + redirect_to user_product_path(product.user_id, product.id) end def clearCart diff --git a/app/views/products/show.html.erb b/app/views/products/show.html.erb index 43ffa51a20..edd5899bc0 100644 --- a/app/views/products/show.html.erb +++ b/app/views/products/show.html.erb @@ -27,7 +27,7 @@

    <%= dollar_price(@product.price) %>

    <%= @product.description %>

    <%= @product.stock %> Available

    - <%= form_tag({controller: "carts", action: "add_product"}, method: :post) do %> + <%= form_tag({controller: "carts", action: "add"}, method: :post , id: @product_id ) do %> <%= submit_tag "Add to Cart", class: "btn btn-lg btn-primary btn-block" %> <% end %>
    diff --git a/config/routes.rb b/config/routes.rb index 2d69eac178..227e449b8e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -16,7 +16,7 @@ get 'cart/' => 'carts#index', as: :cart - post 'cart/' => 'carts#add_product', as: :add_to_cart + post 'cart/' => 'carts#add', as: :add_to_cart get 'products/' => 'products#index', as: :products get 'login/' => 'sessions#new', as: :login post 'login/' => 'sessions#create' From c3b8d7b760f524062dd0bb46e51d7fc2a1cdf675 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 15 Dec 2015 10:31:43 -0800 Subject: [PATCH 165/299] remove new from review route --- config/routes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/routes.rb b/config/routes.rb index 2d69eac178..b42385d98f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -10,7 +10,7 @@ resources :order_items end resources :products, except: [:index, :destroy] do - resources :reviews + resources :reviews, except: [:new] end end From 7631d90c394655b1e1afbf34df592e49c97dfb29 Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 15 Dec 2015 10:35:07 -0800 Subject: [PATCH 166/299] Fix bug with flash notice in correct_user method --- app/controllers/application_controller.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index a6071ab928..485458e36b 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -16,8 +16,11 @@ def logged_in? def correct_user id = params[:id] || params[:user_id] @user = User.find(id) - flash[:error] = "You do not have permission to access that page." - redirect_to(root_path) unless @user == current_user + if @user == current_user + else + flash[:error] = "You do not have permission to access that page." + redirect_to(root_path) + end end def require_login From eac33776dfd586d8304582e241bec5e404a2fa11 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 15 Dec 2015 10:37:41 -0800 Subject: [PATCH 167/299] fix add to cart route --- config/routes.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/config/routes.rb b/config/routes.rb index 7f7ac95b5f..621eb4ffc8 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -11,12 +11,15 @@ end resources :products, except: [:index, :destroy] do resources :reviews, except: [:new] + member do + post 'cart/' => 'carts#add', as: :add_to_cart + end end end get 'cart/' => 'carts#index', as: :cart - post 'cart/' => 'carts#add', as: :add_to_cart + get 'products/' => 'products#index', as: :products get 'login/' => 'sessions#new', as: :login post 'login/' => 'sessions#create' From 7a154eb1400a7d8b5f59b9572f8a0759fd9c157a Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 15 Dec 2015 10:38:06 -0800 Subject: [PATCH 168/299] Fix bug in application#correct_user --- app/controllers/application_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 485458e36b..b03912aa03 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -14,7 +14,7 @@ def logged_in? end def correct_user - id = params[:id] || params[:user_id] + id = params[:user_id] || params[:id] @user = User.find(id) if @user == current_user else From 6e1e014d4689947d03afdec1aea27da0b5f2f22c Mon Sep 17 00:00:00 2001 From: Tammy Date: Tue, 15 Dec 2015 10:49:53 -0800 Subject: [PATCH 169/299] the cart looks working, just need to fix the price display and remove item --- app/controllers/carts_controller.rb | 2 +- app/views/carts/index.html.erb | 9 ++++++--- app/views/products/show.html.erb | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/controllers/carts_controller.rb b/app/controllers/carts_controller.rb index 184be23c47..6a505f1837 100644 --- a/app/controllers/carts_controller.rb +++ b/app/controllers/carts_controller.rb @@ -25,7 +25,7 @@ def add cart[product_id] = 1 end - redirect_to user_product_path(product.user_id, product.id) + redirect_to cart_path end def clearCart diff --git a/app/views/carts/index.html.erb b/app/views/carts/index.html.erb index 1b7b154ae0..107e582855 100644 --- a/app/views/carts/index.html.erb +++ b/app/views/carts/index.html.erb @@ -1,15 +1,18 @@

    Cart

    -<% @cart.each do |product_id, quantity| %> - <% product = Product.find(product_id) %> + + + <% @cart.each do |product_id, quantity| %> + <% product = Product.find(product_id) %> - + + <% end %> diff --git a/app/views/products/show.html.erb b/app/views/products/show.html.erb index a8732fb69b..1790bd07fe 100644 --- a/app/views/products/show.html.erb +++ b/app/views/products/show.html.erb @@ -21,7 +21,7 @@

    <%= dollar_price(@product.price) %>

    <%= @product.description %>

    <%= @product.stock %> Available

    - <%= form_tag({controller: "carts", action: "add"}, method: :post , id: @product_id ) do %> + <%= form_tag({controller: "carts", action: "add"}, method: :post ) do %> <%= submit_tag "Add to Cart", class: "btn btn-lg btn-success btn-block" %> <% end %> From 66296203fbb8a7e656bb9b9903cd776e715f3718 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 15 Dec 2015 10:50:47 -0800 Subject: [PATCH 170/299] remove new view and action for review --- app/controllers/reviews_controller.rb | 4 ---- app/views/reviews/new.html.erb | 4 ---- 2 files changed, 8 deletions(-) delete mode 100644 app/views/reviews/new.html.erb diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb index 8a58663bf4..05267b6aba 100644 --- a/app/controllers/reviews_controller.rb +++ b/app/controllers/reviews_controller.rb @@ -11,10 +11,6 @@ def index def show end - def new - @review = Review.new - end - # Since guests can create a review, nobody (for now) can edit it. Maybe for admin user later... # def edit # end diff --git a/app/views/reviews/new.html.erb b/app/views/reviews/new.html.erb deleted file mode 100644 index e66e52c643..0000000000 --- a/app/views/reviews/new.html.erb +++ /dev/null @@ -1,4 +0,0 @@ -

    New Review

    -<%= render 'form' %> -
    -<%= link_to 'Back', user_product_reviews_path(@product.user, @product), class: "btn btn-primary" %> From 5462292a0db2fa649ff0ad5a2702464ed0e63aa4 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 15 Dec 2015 10:50:59 -0800 Subject: [PATCH 171/299] update tests for review form in product show --- spec/controllers/products_controller_spec.rb | 12 ++++-------- spec/controllers/reviews_controller_spec.rb | 13 ------------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/spec/controllers/products_controller_spec.rb b/spec/controllers/products_controller_spec.rb index 2cf8549a39..bda039af7a 100644 --- a/spec/controllers/products_controller_spec.rb +++ b/spec/controllers/products_controller_spec.rb @@ -3,14 +3,6 @@ RSpec.describe ProductsController, type: :controller do let (:product) { FactoryGirl.create(:product) } - # let (:sample_user) { - # User.create(username: "Kelly", email: "Kelly@kelly.com", password: "password") - # } - # - # let (:product) { - # Product.create(name: "Rubber ducky", price: "500", stock: "1", user_id: sample_user.id) - # } - let (:bad_params) { { user_id: product.user.id, product: { price: "zzz" } @@ -45,6 +37,10 @@ # get :show, {id: product.id, user_id: product.user.id + 1 }, user_id: product.user.id # expect(subject).to redirect_to root_path # end + it "assigns a new review as @review" do + get :show, {id: product.id, user_id: product.user.id}, user_id: product.user.id + expect(assigns(:review)).to be_a_new(Review) + end end describe "GET 'new'" do diff --git a/spec/controllers/reviews_controller_spec.rb b/spec/controllers/reviews_controller_spec.rb index d6ef61c1da..03402c2ddc 100644 --- a/spec/controllers/reviews_controller_spec.rb +++ b/spec/controllers/reviews_controller_spec.rb @@ -14,19 +14,6 @@ end end - describe "GET 'new'" do - it "renders the new page" do - get :new, product_id: review.product_id, user_id: review.product.user_id - expect(subject).to render_template :new - end - - it "assigns a new review as @review" do - get :new, product_id: review.product_id, user_id: review.product.user_id - expect(assigns(:review)).to be_a_new(Review) - end - - end - describe "GET 'edit'" do it "renders edit page" do get :edit, product_id: review.product_id, user_id: review.product.user_id, id: review.id From 9366ce1d539a2a16c0d12264450475dd519a582a Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 15 Dec 2015 11:04:16 -0800 Subject: [PATCH 172/299] Update orders show view and add presence validations to Order model --- app/models/order.rb | 1 + app/views/orders/show.html.erb | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/app/models/order.rb b/app/models/order.rb index 4686bb1569..6a513bc67d 100644 --- a/app/models/order.rb +++ b/app/models/order.rb @@ -1,6 +1,7 @@ class Order < ActiveRecord::Base has_many :order_items has_many :products, through: :order_items + validates :email, :street, :city, :state, :zip, :cc_num, :cc_exp, :cc_cvv, :cc_name, presence: true validates_numericality_of :zip, :cc_num, allow_nil: true validates_length_of :zip, is: 5, allow_nil: true validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i }, allow_nil: true diff --git a/app/views/orders/show.html.erb b/app/views/orders/show.html.erb index 37727e9bd7..1f0556b3c4 100644 --- a/app/views/orders/show.html.erb +++ b/app/views/orders/show.html.erb @@ -24,15 +24,19 @@

    - Cc num: - <% (@order.cc_num.length - 4).times do %> - * + Credit Card: + <% if @order.cc_num.length <= 4 %> + <%= @order.cc_num %> + <% else %> + <% (@order.cc_num.length - 4).times do %> + * + <% end %> + <%= @order.cc_num[(@order.cc_num.length - 4)..(@order.cc_num.length - 1)] %> <% end %> - <%= @order.cc_num[(@order.cc_num.length - 4)..(@order.cc_num.length - 1)] %>

    - Cc exp: + Credit Card Expiration: <%= @order.cc_exp %>

    @@ -47,6 +51,5 @@ <% end %>

    -<%= link_to 'Edit', edit_user_order_path(@user.id, @order.id) %> | <%= link_to 'Back', user_orders_path(@user.id, @order.id) %> <%= link_to 'Order Item', user_order_order_items_path(@user.id, @order.id) %> From 40cdc266b02cd69fb4c6342e3649964923839779 Mon Sep 17 00:00:00 2001 From: Tammy Date: Tue, 15 Dec 2015 11:07:50 -0800 Subject: [PATCH 173/299] remove item from cart is working --- app/controllers/carts_controller.rb | 9 ++++++++- app/models/cart.rb | 16 ++++++++-------- app/views/carts/index.html.erb | 4 ++-- config/routes.rb | 1 + 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/app/controllers/carts_controller.rb b/app/controllers/carts_controller.rb index 6a505f1837..3ada861fa4 100644 --- a/app/controllers/carts_controller.rb +++ b/app/controllers/carts_controller.rb @@ -19,7 +19,7 @@ def add end # if the cart already has the product -> just add one # if not -> set the quantity to one - if cart[product_id] + if cart[product_id]!= 0 cart[product_id] = cart[product_id] + 1 else cart[product_id] = 1 @@ -33,4 +33,11 @@ def clearCart redirect_to index end + def destroy + cart = session[:cart] + product_id = params[:id] + cart.delete(product_id) + redirect_to cart_path + end + end diff --git a/app/models/cart.rb b/app/models/cart.rb index 493a9521f3..23bdf50128 100644 --- a/app/models/cart.rb +++ b/app/models/cart.rb @@ -1,14 +1,14 @@ class Cart #Get subtotal of the cart items - def self.subtotal(cart) - subtotal = 0 - cart.each do |product, quantity| - price = Product.find(product).price - subtotal += (price * quantity) - end - return subtotal - end + # def self.subtotal(cart) + # subtotal = 0 + # cart.each do |product, quantity| + # price = Product.find(product).price.to_i + # subtotal += (price * quantity.to_it) + # end + # return subtotal + # end end diff --git a/app/views/carts/index.html.erb b/app/views/carts/index.html.erb index 107e582855..4a580fc1fe 100644 --- a/app/views/carts/index.html.erb +++ b/app/views/carts/index.html.erb @@ -13,9 +13,9 @@
    - + <% end %>
    Product Description Price quantity
    <%= link_to product.name, user_product(product.user_id, product.id) %> <%= link_to product.name, user_product_path(product.user_id, product.id) %> <%= product.description %> <%= product.price %> <%= quantity %> <%= link_to 'remove-NOT WORKING', cart_path %>
    <%= product.description %> <%= product.price %> <%= quantity %> <%= link_to 'remove-NOT WORKING', cart_path %> <%= link_to 'Remove', remove_user_product_path(product.user_id, product.id), method: :delete, data: { confirm: 'Are you sure?' } %>
    -

    Items total $<%= Cart.subtotal(@cart) %>

    + diff --git a/config/routes.rb b/config/routes.rb index 621eb4ffc8..982f867a0d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -13,6 +13,7 @@ resources :reviews, except: [:new] member do post 'cart/' => 'carts#add', as: :add_to_cart + delete 'cart/' => 'carts#destroy', as: :remove end end end From 9b8bdbd215cca88449472122181943382fc0abe6 Mon Sep 17 00:00:00 2001 From: Tammy Date: Tue, 15 Dec 2015 11:12:29 -0800 Subject: [PATCH 174/299] almost done with the cart --- app/controllers/carts_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/carts_controller.rb b/app/controllers/carts_controller.rb index 3ada861fa4..747875d418 100644 --- a/app/controllers/carts_controller.rb +++ b/app/controllers/carts_controller.rb @@ -19,7 +19,7 @@ def add end # if the cart already has the product -> just add one # if not -> set the quantity to one - if cart[product_id]!= 0 + if cart[product_id] cart[product_id] = cart[product_id] + 1 else cart[product_id] = 1 From e48955dc3422c5230e4698f437259d1fb8ac1640 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 15 Dec 2015 11:18:36 -0800 Subject: [PATCH 175/299] move creating new category form to category list page --- app/controllers/categories_controller.rb | 12 +++--- app/views/categories/_form.html.erb | 13 +++---- app/views/categories/index.html.erb | 49 ++++++++++++++---------- app/views/reviews/_form.html.erb | 4 +- config/routes.rb | 2 +- 5 files changed, 43 insertions(+), 37 deletions(-) diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb index 373be73fe0..dc971f586f 100644 --- a/app/controllers/categories_controller.rb +++ b/app/controllers/categories_controller.rb @@ -3,6 +3,7 @@ class CategoriesController < ApplicationController def index @categories = Category.all + @category = Category.new end @@ -10,10 +11,10 @@ def show @products = @category.products.paginate(page: params[:page], per_page: 12) end - - def new - @category = Category.new - end + # + # def new + # @category = Category.new + # end def edit @@ -24,7 +25,8 @@ def create if @category.save redirect_to categories_path else - render :new + @categories = Category.all + render :index end end diff --git a/app/views/categories/_form.html.erb b/app/views/categories/_form.html.erb index d244c9eac7..81615eb3bc 100644 --- a/app/views/categories/_form.html.erb +++ b/app/views/categories/_form.html.erb @@ -1,4 +1,4 @@ -<%= form_for(@category) do |f| %> +<%= form_for @category, :html => {:class => "form-inline"} do |f| %> <% if @category.errors.any? %>
      @@ -8,12 +8,9 @@
    <% end %> - -
    - <%= f.label :name %>
    - <%= f.text_field :name %> -
    -
    - <%= f.submit %> +
    + <%= f.label :name, class: "sr-only" %>
    + <%= f.text_field :name, placeholder: "Category name", class: 'form-control', :required => true %> + <%= f.submit value: "Add Category", class: "btn btn-success" %>
    <% end %> diff --git a/app/views/categories/index.html.erb b/app/views/categories/index.html.erb index 48f076dda4..de7668209e 100644 --- a/app/views/categories/index.html.erb +++ b/app/views/categories/index.html.erb @@ -3,6 +3,9 @@

    Looking for Inspiration? Shop by Category

    + <% if logged_in? %> + <%= render 'categories/form' %> + <% end %>
    @@ -17,28 +20,32 @@
    <% count = 0 %> <% @categories.each do |category| %> - <% product = category.products.first %> -
    -

    <%= category.name.capitalize %>

    -

    Featured Product:

    -
    -
    - <%= image_tag product.photo_url, alt: "product photo" %> -
    -
    -
    <%= dollar_price(product.price) %>
    -
    <%= link_to product.name, user_product_path(product.user_id, product.id) %> -
    -

    - <% if !product.description.nil? %> - <%= product.description %> - <% else %> -
    - <% end %> -

    -

    <%= product.stock %> Available

    + <% if category.products.exists? %> + + <% product = category.products.first %> +
    +

    <%= category.name.capitalize %>

    +

    Featured Product:

    +
    +
    + <%= image_tag product.photo_url, alt: "product photo" %> +
    +
    +
    <%= dollar_price(product.price) %>
    +
    <%= link_to product.name, user_product_path(product.user_id, product.id) %> +
    +

    + <% if !product.description.nil? %> + <%= product.description %> + <% else %> +
    + <% end %> +

    +

    <%= product.stock %> Available

    +
    -
    + + <% end %>
    <% count += 1 %> <% if count % 4 == 0 %> diff --git a/app/views/reviews/_form.html.erb b/app/views/reviews/_form.html.erb index 12be60db35..0f81898c08 100644 --- a/app/views/reviews/_form.html.erb +++ b/app/views/reviews/_form.html.erb @@ -8,9 +8,9 @@
    - <%= form_for [@product.user, @product, @review], class: "form-group" do |f| %> + <%= form_for [@product.user, @product, @review], :html => {:class => "form-group"} do |f| %> <%= f.label :rating, "Rating (1-5)" %>
    - <%= f.number_field :rating, class: 'form-control', :required => true%> + <%= f.number_field :rating, class: 'form-control', :required => true %> <%= f.label :description %>
    <%= f.text_field :description, class: 'form-control' %>
    diff --git a/config/routes.rb b/config/routes.rb index 621eb4ffc8..5876a42f41 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -4,7 +4,7 @@ get "/users/:id/products" => "users#products", as: :user_products - resources :categories + resources :categories, except: [:new] resources :users do resources :orders do resources :order_items From b14be2ec0cf7b538d450bfbbf25d86727abfbb46 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 15 Dec 2015 11:27:08 -0800 Subject: [PATCH 176/299] bugfix on category index page --- app/controllers/categories_controller.rb | 6 ------ app/views/categories/index.html.erb | 2 -- 2 files changed, 8 deletions(-) diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb index dc971f586f..198683235e 100644 --- a/app/controllers/categories_controller.rb +++ b/app/controllers/categories_controller.rb @@ -11,12 +11,6 @@ def show @products = @category.products.paginate(page: params[:page], per_page: 12) end - # - # def new - # @category = Category.new - # end - - def edit end diff --git a/app/views/categories/index.html.erb b/app/views/categories/index.html.erb index de7668209e..ad1a7466b8 100644 --- a/app/views/categories/index.html.erb +++ b/app/views/categories/index.html.erb @@ -53,5 +53,3 @@
    <% end %> <% end %> - -<%= link_to 'New Category', new_category_path %> From f8f8ecdc8e3cc66cdfb59ab96a6381e3cde8028a Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 15 Dec 2015 11:37:54 -0800 Subject: [PATCH 177/299] Update order controller routes, create link to checkout in carts index page --- app/controllers/orders_controller.rb | 2 +- app/views/carts/index.html.erb | 2 ++ app/views/orders/new.html.erb | 4 ++-- config/routes.rb | 5 ++++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index 15e5b628a9..41367d5eb0 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -2,7 +2,7 @@ class OrdersController < ApplicationController before_action :require_login, only: [:index] before_action :correct_user, only: [:index] before_action :order_items, only: [:new, :create] - before_action :find_user + before_action :find_user, except: [:new, :create] def index @orders = @user.orders diff --git a/app/views/carts/index.html.erb b/app/views/carts/index.html.erb index 4a580fc1fe..0322ea4be9 100644 --- a/app/views/carts/index.html.erb +++ b/app/views/carts/index.html.erb @@ -18,4 +18,6 @@ <% end %> + <%= link_to "Proceed to Checkout", checkout_new_path %> + diff --git a/app/views/orders/new.html.erb b/app/views/orders/new.html.erb index af19d0d25f..4f90f411bb 100644 --- a/app/views/orders/new.html.erb +++ b/app/views/orders/new.html.erb @@ -9,7 +9,7 @@

    Payment Details

    -<%= form_for [@user, @order] do |f| %> +<%= form_for @order, url: checkout_submit_path do |f| %> <% if @order.errors.any? %>
      @@ -62,4 +62,4 @@ <% end %> -<%= link_to 'Back', user_orders_path(@user.id, @order.id) %> +<%= link_to 'Back to Cart', cart_path %> diff --git a/config/routes.rb b/config/routes.rb index 982f867a0d..c1366be00e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -6,7 +6,7 @@ resources :categories resources :users do - resources :orders do + resources :orders, only: [:index, :show] do resources :order_items end resources :products, except: [:index, :destroy] do @@ -25,6 +25,9 @@ get 'login/' => 'sessions#new', as: :login post 'login/' => 'sessions#create' delete 'logout/' => 'sessions#destroy', as: :logout + get 'checkout/' => 'orders#new', as: :checkout_new + post 'checkout/' => 'orders#create', as: :checkout_submit + # The priority is based upon order of creation: first created -> highest priority. # See how all your routes lay out with "rake routes". From ef10859a80eb898ee99e147747aede5053200789 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 15 Dec 2015 11:46:32 -0800 Subject: [PATCH 178/299] complete categories test and form errors --- app/views/categories/_form.html.erb | 6 +- .../controllers/categories_controller_spec.rb | 169 +++++++----------- spec/controllers/reviews_controller_spec.rb | 1 - 3 files changed, 68 insertions(+), 108 deletions(-) diff --git a/app/views/categories/_form.html.erb b/app/views/categories/_form.html.erb index 81615eb3bc..bf7fc33946 100644 --- a/app/views/categories/_form.html.erb +++ b/app/views/categories/_form.html.erb @@ -1,11 +1,9 @@ <%= form_for @category, :html => {:class => "form-inline"} do |f| %> <% if @category.errors.any? %> -
      -
        +
        <% @category.errors.full_messages.each do |message| %> -
      • <%= message %>
      • +

        Error: <%= message %>

        <% end %> -
      <% end %>
      diff --git a/spec/controllers/categories_controller_spec.rb b/spec/controllers/categories_controller_spec.rb index 563674b47f..e410c6ec6f 100644 --- a/spec/controllers/categories_controller_spec.rb +++ b/spec/controllers/categories_controller_spec.rb @@ -1,105 +1,68 @@ -# 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) { -# skip("Add a hash of attributes valid for your model") -# } -# -# let(:invalid_attributes) { -# skip("Add a hash of attributes invalid for your model") -# } -# -# # 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, {}, 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, {:id => category.to_param}, valid_session -# expect(assigns(:category)).to eq(category) -# end -# end -# -# describe "GET #new" do -# it "assigns a new category as @category" do -# get :new, {}, 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, {:id => category.to_param}, 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, {:category => valid_attributes}, valid_session -# }.to change(Category, :count).by(1) -# end -# -# it "assigns a newly created category as @category" do -# post :create, {:category => valid_attributes}, 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, {:category => valid_attributes}, 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, {:category => invalid_attributes}, valid_session -# expect(assigns(:category)).to be_a_new(Category) -# end -# -# it "re-renders the 'new' template" do -# post :create, {:category => invalid_attributes}, valid_session -# expect(response).to render_template("new") -# end -# end -# end -# +require 'rails_helper' + +RSpec.describe CategoriesController, type: :controller do + let(:category) { FactoryGirl.create(:category) } + let(:valid_attributes) {{ name: "New category" }} + let(:invalid_attributes) {{ name: "" }} + + describe "GET 'index'" do + it "is successful" do + get :index + expect(response.status).to eq 200 + end + it "assigns all categories as @categories" do + get :index + expect(assigns(:categories)).to eq([category]) + end + end + + describe "GET #show" do + it "assigns the requested category as @category" do + get :show, :id => category.id + expect(assigns(:category)).to eq(category) + end + end + + describe "GET #edit" do + it "assigns the requested category as @category" do + get :edit, :id => category.id + 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, {:category => valid_attributes}, user_id: 1 + }.to change(Category, :count).by(1) + end + + it "assigns a newly created category as @category" do + post :create, {:category => valid_attributes}, user_id: 1 + expect(assigns(:category)).to be_a(Category) + expect(assigns(:category)).to be_persisted + end + + it "redirects to the category index" do + post :create, {:category => valid_attributes}, user_id: 1 + expect(response).to redirect_to(categories_path) + end + end + + context "with invalid params" do + it "assigns a newly created but unsaved category as @category" do + post :create, {:category => invalid_attributes}, user_id: 1 + expect(assigns(:category)).to be_a_new(Category) + end + + it "re-renders the 'index' template" do + post :create, {:category => invalid_attributes}, user_id: 1 + expect(response).to render_template("index") + end + end + end + # describe "PUT #update" do # context "with valid params" do # let(:new_attributes) { @@ -156,4 +119,4 @@ # end # end # -# end +end diff --git a/spec/controllers/reviews_controller_spec.rb b/spec/controllers/reviews_controller_spec.rb index 03402c2ddc..04322dd769 100644 --- a/spec/controllers/reviews_controller_spec.rb +++ b/spec/controllers/reviews_controller_spec.rb @@ -1,5 +1,4 @@ require 'rails_helper' -require 'pry' RSpec.describe ReviewsController, type: :controller do let(:review) { FactoryGirl.create(:review) } From ef5a74b7a9909fc650331d3ddd10700ce3af5d03 Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 15 Dec 2015 12:01:38 -0800 Subject: [PATCH 179/299] Complete orders#create method --- app/controllers/orders_controller.rb | 10 ++++++---- app/models/order_item.rb | 2 +- app/views/orders/confirm.html.erb | 1 + app/views/orders/index.html.erb | 1 - config/routes.rb | 1 + 5 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 app/views/orders/confirm.html.erb diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index 41367d5eb0..c0322e5685 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -2,7 +2,7 @@ class OrdersController < ApplicationController before_action :require_login, only: [:index] before_action :correct_user, only: [:index] before_action :order_items, only: [:new, :create] - before_action :find_user, except: [:new, :create] + before_action :find_user, except: [:new, :create, :confirm] def index @orders = @user.orders @@ -19,20 +19,22 @@ def new def create @order = Order.new(order_params) @order_items.each do |oi| - oi.save @order.order_items << oi + oi.save end if @order.save - redirect_to user_orders_path + redirect_to confirmation_path(@order) else render :new end end + def confirm + end + private def order_items - session[:cart] = { 3 => 2, 5 => 4 } @order_items = [] session[:cart].each do |product, quantity| @order_items.push(OrderItem.new(:product_id => product, :quantity => quantity)) diff --git a/app/models/order_item.rb b/app/models/order_item.rb index 6e052fd2a0..d1ae171b44 100644 --- a/app/models/order_item.rb +++ b/app/models/order_item.rb @@ -2,6 +2,6 @@ class OrderItem < ActiveRecord::Base belongs_to :product belongs_to :order - validates :quantity, :product_id, :order_id, presence: true + validates :quantity, :product_id, presence: true validates_numericality_of :quantity, :greater_than => 0 end diff --git a/app/views/orders/confirm.html.erb b/app/views/orders/confirm.html.erb new file mode 100644 index 0000000000..74901e0b84 --- /dev/null +++ b/app/views/orders/confirm.html.erb @@ -0,0 +1 @@ +

      Thank you for shopping on Wetsy!

      diff --git a/app/views/orders/index.html.erb b/app/views/orders/index.html.erb index 53c3649260..92d6d6f5ae 100644 --- a/app/views/orders/index.html.erb +++ b/app/views/orders/index.html.erb @@ -30,4 +30,3 @@
      -<%= link_to 'New Order', new_user_order_path %> diff --git a/config/routes.rb b/config/routes.rb index 7b75195b1d..1bd22a1898 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -27,6 +27,7 @@ delete 'logout/' => 'sessions#destroy', as: :logout get 'checkout/' => 'orders#new', as: :checkout_new post 'checkout/' => 'orders#create', as: :checkout_submit + get 'checkout/:order_id' => 'orders#confirm', as: :confirmation # The priority is based upon order of creation: first created -> highest priority. # See how all your routes lay out with "rake routes". From 8123acf214b978fb535bf6da2afd73da7d077e82 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 15 Dec 2015 12:16:50 -0800 Subject: [PATCH 180/299] fix redirect issue with error in review form and update test --- app/controllers/reviews_controller.rb | 3 +- spec/controllers/reviews_controller_spec.rb | 32 ++++++++++----------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb index 05267b6aba..1281f03aab 100644 --- a/app/controllers/reviews_controller.rb +++ b/app/controllers/reviews_controller.rb @@ -23,7 +23,8 @@ def create if @review.save redirect_to user_product_path(@review.product.user, @review.product) else - render :new + flash[:error] = @review.errors.full_messages.first + redirect_to user_product_path(@review.product.user, @review.product) end end diff --git a/spec/controllers/reviews_controller_spec.rb b/spec/controllers/reviews_controller_spec.rb index 04322dd769..974cd89c2a 100644 --- a/spec/controllers/reviews_controller_spec.rb +++ b/spec/controllers/reviews_controller_spec.rb @@ -13,18 +13,18 @@ end end - describe "GET 'edit'" do - it "renders edit page" do - get :edit, product_id: review.product_id, user_id: review.product.user_id, id: review.id - expect(subject).to render_template :edit - end - - it "assigns the requested review as @review" do - get :edit, product_id: review.product_id, user_id: review.product.user_id, id: review.id - expect(assigns(:review)).to eq(review) - end - - end + # describe "GET 'edit'" do + # it "renders edit page" do + # get :edit, product_id: review.product_id, user_id: review.product.user_id, id: review.id + # expect(subject).to render_template :edit + # end + # + # it "assigns the requested review as @review" do + # get :edit, product_id: review.product_id, user_id: review.product.user_id, id: review.id + # expect(assigns(:review)).to eq(review) + # end + # + # end describe "GET 'show'" do it "renders show page" do @@ -55,10 +55,10 @@ } } context "with valid params" do - it "redirects to user_product_reviews" do + it "redirects to product show page" do post :create, valid_create_attributes new_review = Review.last - expect(subject).to redirect_to user_product_reviews_path(new_review.product.user_id, new_review.product_id) + expect(subject).to redirect_to user_product_path(new_review.product.user_id, new_review.product_id) end it "creates a new Review" do expect { @@ -77,9 +77,9 @@ post :create, invalid_create_attributes expect(assigns(:review)).to be_a_new(Review) end - it "re-renders the new template" do + it "re-renders the product show template" do post :create, invalid_create_attributes - expect(subject).to render_template :new + expect(subject).to redirect_to user_product_path(product.user_id, product.id) end end end From 0b1ebee389a8dde1ebc5952462cf467fdc9e14a3 Mon Sep 17 00:00:00 2001 From: Tammy Date: Tue, 15 Dec 2015 12:24:21 -0800 Subject: [PATCH 181/299] pull to finish the care with total --- spec/controllers/carts_controller_spec.rb | 10 ++++++++++ spec/controllers/orders_controller_spec.rb | 1 - 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/spec/controllers/carts_controller_spec.rb b/spec/controllers/carts_controller_spec.rb index 0ddc03dd6a..2e9400cd63 100644 --- a/spec/controllers/carts_controller_spec.rb +++ b/spec/controllers/carts_controller_spec.rb @@ -2,4 +2,14 @@ RSpec.describe CartsController, type: :controller do + + + describe "GET 'index'" do + it "is successful" do + get :index + expect(response.status).to eq 200 + end + end + + end diff --git a/spec/controllers/orders_controller_spec.rb b/spec/controllers/orders_controller_spec.rb index 4f617daf7c..f8aadf2afb 100644 --- a/spec/controllers/orders_controller_spec.rb +++ b/spec/controllers/orders_controller_spec.rb @@ -45,7 +45,6 @@ it "redirects to index page" do # session[:cart] = { 1 => 2, 3 => 4 } session[:user_id] = sample_user.id - binding.pry post :create, good_params expect(subject).to redirect_to user_orders_path end From a7ce4c5f610507cb7c1a637c1df16a5ddd177c22 Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 15 Dec 2015 12:25:25 -0800 Subject: [PATCH 182/299] Update order model specs --- spec/models/order_spec.rb | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/spec/models/order_spec.rb b/spec/models/order_spec.rb index 46b0928484..1066a2f32c 100644 --- a/spec/models/order_spec.rb +++ b/spec/models/order_spec.rb @@ -1,20 +1,31 @@ require 'rails_helper' RSpec.describe Order, type: :model do + let (:good_params) { + {street: "test" , city: "Seattle", state: "WA", zip: "98116", cc_num: "12345678", cc_cvv: "123", cc_name: "Kelly", cc_exp: "20151215"} + } + describe ".validates" do it { is_expected.to validate_numericality_of(:zip) } it { is_expected.to validate_numericality_of(:cc_num) } it { is_expected.to validate_length_of(:zip) } + it { is_expected.to validate_presence_of(:email) } + it { is_expected.to validate_presence_of(:street) } + it { is_expected.to validate_presence_of(:city) } + it { is_expected.to validate_presence_of(:state) } + it { is_expected.to validate_presence_of(:zip) } + it { is_expected.to validate_presence_of(:cc_num) } + it { is_expected.to validate_presence_of(:cc_exp) } + it { is_expected.to validate_presence_of(:cc_cvv) } + it { is_expected.to validate_presence_of(:cc_name) } - it "must have a nil or valid email " do - expect(Order.create(email: 'user@foo,com')).to_not be_valid - expect(Order.create(email: 'user_at_foo.org')).to_not be_valid - expect(Order.create(email: 'example.user@foo.')).to_not be_valid - expect(Order.create(email: 'foo@bar_baz.com')).to_not be_valid - expect(Order.create(email: 'foo@bar+baz.com')).to_not be_valid - expect(Order.create(email: ' ')).to_not be_valid - expect(Order.create(email: 'kelly@kelly.com')).to be_valid - expect(Order.create(email: nil)).to be_valid + it "must have a valid email " do + expect(Order.create(good_params.merge(email: "user_at_foo.org"))).to_not be_valid + expect(Order.create(good_params.merge(email: "example.user@foo."))).to_not be_valid + expect(Order.create(good_params.merge(email: "foo@bar_baz.com"))).to_not be_valid + expect(Order.create(good_params.merge(email: "foo@bar+baz.com"))).to_not be_valid + expect(Order.create(good_params.merge(email: " "))).to_not be_valid + expect(Order.create(good_params.merge(email: "kelly@kelly.com"))).to be_valid end end end From d851152f69de2aefbe5173b5ca62f91c5cb2a9a9 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 15 Dec 2015 12:26:46 -0800 Subject: [PATCH 183/299] feature user cannot review own product --- app/views/products/show.html.erb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/views/products/show.html.erb b/app/views/products/show.html.erb index 1790bd07fe..0c8bd5fcea 100644 --- a/app/views/products/show.html.erb +++ b/app/views/products/show.html.erb @@ -28,9 +28,11 @@
      -

      Purchased this Product? Leave a Review:

      - - <%= render "reviews/form", :review => @review, :product => @product %> + <% if !logged_in? || current_user.id != params[:user_id].to_i %> +

      Purchased this Product? Leave a Review:

      + + <%= render "reviews/form", :review => @review, :product => @product %> + <% end %>

      Product Reviews

      From 4f74091cdb3eb2c1c8909f8ea02c98bd54d1a29f Mon Sep 17 00:00:00 2001 From: Tammy Date: Tue, 15 Dec 2015 12:28:34 -0800 Subject: [PATCH 184/299] can see the subtotal --- app/models/cart.rb | 17 ++++++++--------- app/views/carts/index.html.erb | 4 +--- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/app/models/cart.rb b/app/models/cart.rb index 23bdf50128..98eadb641d 100644 --- a/app/models/cart.rb +++ b/app/models/cart.rb @@ -1,14 +1,13 @@ class Cart - #Get subtotal of the cart items - # def self.subtotal(cart) - # subtotal = 0 - # cart.each do |product, quantity| - # price = Product.find(product).price.to_i - # subtotal += (price * quantity.to_it) - # end - # return subtotal - # end + def self.subtotal(cart) + subtotal = 0 + cart.each do |product, quantity| + price = Product.find(product).price.to_i + subtotal += (price * quantity) + end + return subtotal + end end diff --git a/app/views/carts/index.html.erb b/app/views/carts/index.html.erb index 0322ea4be9..66a6d2bec6 100644 --- a/app/views/carts/index.html.erb +++ b/app/views/carts/index.html.erb @@ -17,7 +17,5 @@ <% end %> - +

      Items total $ <%= Cart.subtotal(@cart) %>

      <%= link_to "Proceed to Checkout", checkout_new_path %> - - From 08f67b06e71797cc5bdc6090ad584c239f4f6c59 Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 15 Dec 2015 12:34:51 -0800 Subject: [PATCH 185/299] Complete orders_controller rspec tests --- spec/controllers/orders_controller_spec.rb | 39 +++------------------- 1 file changed, 5 insertions(+), 34 deletions(-) diff --git a/spec/controllers/orders_controller_spec.rb b/spec/controllers/orders_controller_spec.rb index 4f617daf7c..516342d7b5 100644 --- a/spec/controllers/orders_controller_spec.rb +++ b/spec/controllers/orders_controller_spec.rb @@ -7,7 +7,7 @@ let (:good_params) { { user_id: sample_user.id, - order: { email: "Kelly@kelly.com", street: "test" , city: "Seattle", state: "WA", zip: "98116", cc_num: "123", cc_cvv: "123", cc_name: "Kelly"} + order: { email: "Kelly@kelly.com", street: "test" , city: "Seattle", state: "WA", zip: "98116", cc_num: "123", cc_cvv: "123", cc_name: "Kelly", cc_exp: "20151215"} } } @@ -35,19 +35,18 @@ describe "GET 'new'" do it "renders new view" do - # session[:cart] = { 1 => 2, 3 => 4 } + session[:cart] = { 1 => 2, 3 => 4 } get :new, user_id: sample_user.id expect(subject).to render_template :new end end describe "POST 'create'" do - it "redirects to index page" do - # session[:cart] = { 1 => 2, 3 => 4 } + it "redirects to checkout confirmation page" do + session[:cart] = { 1 => 2, 3 => 4 } session[:user_id] = sample_user.id - binding.pry post :create, good_params - expect(subject).to redirect_to user_orders_path + expect(subject).to redirect_to confirmation_path(Order.all.last) end it "renders new template on error" do @@ -56,32 +55,4 @@ expect(subject).to render_template :new end end - - # describe "GET 'edit'" do - # it "renders edit view" do - # get :edit, id: sample_order.id - # expect(subject).to render_template :edit - # end - # end - - # describe "PATCH 'update'" do - # it "redirects to index page" do - # patch :update, { order: { zip: "02780" } } - # expect(subject).to redirect_to orders_path - # expect(Order.all.last.zip).to eq "02780" - # end - # - # it "renders edit template on error" do - # patch :update, bad_params - # expect(subject).to render_template :edit - # expect(Order.all.last.zip).to eq nil - # end - # end - - # describe "DELETE 'destroy'" do - # it "redirects to index page" do - # delete :destroy, id: sample_order.id - # expect(subject).to redirect_to orders_path - # end - # end end From 71b90c1b4949f348488f07f2f7d7117ade433614 Mon Sep 17 00:00:00 2001 From: Tammy Date: Tue, 15 Dec 2015 14:19:57 -0800 Subject: [PATCH 186/299] if product is not is stock - you won't be able to add it to the cart --- app/controllers/carts_controller.rb | 11 +++++++++-- app/views/carts/index.html.erb | 3 +++ app/views/products/show.html.erb | 7 ++++++- spec/controllers/carts_controller_spec.rb | 17 ++++++++++++++++- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/app/controllers/carts_controller.rb b/app/controllers/carts_controller.rb index 747875d418..3ba589a957 100644 --- a/app/controllers/carts_controller.rb +++ b/app/controllers/carts_controller.rb @@ -20,12 +20,19 @@ def add # if the cart already has the product -> just add one # if not -> set the quantity to one if cart[product_id] - cart[product_id] = cart[product_id] + 1 + #check that the product is on stock + if product.stock >= cart[product_id] + 1 + cart[product_id] = cart[product_id] + 1 + redirect_to cart_path + else + flash[:error] = "The product is not on stock" + redirect_to user_product_path(product.user_id, product.id) + end else cart[product_id] = 1 + redirect_to cart_path end - redirect_to cart_path end def clearCart diff --git a/app/views/carts/index.html.erb b/app/views/carts/index.html.erb index 66a6d2bec6..ae1eef82b2 100644 --- a/app/views/carts/index.html.erb +++ b/app/views/carts/index.html.erb @@ -1,5 +1,8 @@

      Cart

      +<% if !flash.now[:error].nil? %> + <%= flash.now[:error] %> +<% end %> diff --git a/app/views/products/show.html.erb b/app/views/products/show.html.erb index 0c8bd5fcea..2ee14be248 100644 --- a/app/views/products/show.html.erb +++ b/app/views/products/show.html.erb @@ -23,7 +23,12 @@

      <%= @product.stock %> Available

      <%= form_tag({controller: "carts", action: "add"}, method: :post ) do %> <%= submit_tag "Add to Cart", class: "btn btn-lg btn-success btn-block" %> - <% end %> + <% end %> + + <% if !flash[:error].nil? %> + <%= flash[:error] %> + <% end %> +
      diff --git a/spec/controllers/carts_controller_spec.rb b/spec/controllers/carts_controller_spec.rb index 2e9400cd63..63bf4e7a7f 100644 --- a/spec/controllers/carts_controller_spec.rb +++ b/spec/controllers/carts_controller_spec.rb @@ -3,7 +3,6 @@ RSpec.describe CartsController, type: :controller do - describe "GET 'index'" do it "is successful" do get :index @@ -11,5 +10,21 @@ end end + # describe "#destroy" do + # it "remove the product from the cart" do + # let :cart do + # { 1 => 6, 2 => 1, 5 => 3 } + # end + # let(:session[:cart] = cart) + # before :each do + # get "/delete", {}, { :cart => { :product_id => 2 }} # the first hash is params, second is session + # end + # + # it "remove the product from the cart" do + # session[:cart][:product_id].should be_nil + # end + # + # end + # end end From f807e9d0183940d238692d44c73fa40d9bdef272 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 15 Dec 2015 14:24:33 -0800 Subject: [PATCH 187/299] format new product page --- Gemfile | 2 + Gemfile.lock | 3 + app/assets/stylesheets/application.scss | 1 + app/views/products/_form.html.erb | 21 +- app/views/products/new.html.erb | 4 +- .../awesome-bootstrap-checkbox.scss | 1736 +++++++++++++++++ 6 files changed, 1756 insertions(+), 11 deletions(-) create mode 100644 vendor/assets/stylesheets/awesome-bootstrap-checkbox.scss diff --git a/Gemfile b/Gemfile index 9bce13d60b..1151810b15 100644 --- a/Gemfile +++ b/Gemfile @@ -31,6 +31,8 @@ gem 'simplecov', :require => false, :group => :test gem 'will_paginate' +gem "font-awesome-rails" + # Use Unicorn as the app server # gem 'unicorn' diff --git a/Gemfile.lock b/Gemfile.lock index 66aca29fc2..9fb23046fd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -71,6 +71,8 @@ GEM factory_girl_rails (4.5.0) factory_girl (~> 4.5.0) railties (>= 3.0.0) + font-awesome-rails (4.5.0.0) + railties (>= 3.2, < 5.0) globalid (0.3.6) activesupport (>= 4.1.0) i18n (0.7.0) @@ -201,6 +203,7 @@ DEPENDENCIES byebug coffee-rails (~> 4.1.0) factory_girl_rails (~> 4.0) + font-awesome-rails jbuilder (~> 2.0) jquery-rails pg diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 6a1bf55d05..378bd4ec37 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -14,6 +14,7 @@ @import "bootstrap-sprockets"; @import "bootstrap"; + @import "font-awesome"; @import url(https://fonts.googleapis.com/css?family=Slabo+27px); @import url(https://fonts.googleapis.com/css?family=Lato); @import url(https://fonts.googleapis.com/css?family=Lora); diff --git a/app/views/products/_form.html.erb b/app/views/products/_form.html.erb index 81d25244ab..6e3cd8abf0 100644 --- a/app/views/products/_form.html.erb +++ b/app/views/products/_form.html.erb @@ -1,4 +1,4 @@ -<%= form_for [@user, @product] do |f| %> +<%= form_for [@user, @product], :html => {:class => "form-group" } do |f| %> <% if @product.errors.any? %>
        @@ -12,28 +12,31 @@
        <%= f.label :name %> - <%= f.text_field :name %> + <%= f.text_field :name, class: 'form-control', :required => true %> <%= f.label :price %> - <%= f.number_field :price %> + <%= f.number_field :price, class: 'form-control', :required => true %> <%= f.label :photo_url %> - <%= f.text_field :photo_url %> + <%= f.text_field :photo_url, class: 'form-control' %> <%= f.label :stock %> - <%= f.number_field :stock %> + <%= f.number_field :stock, class: 'form-control', :required => true %> <%= f.label :description %> - <%= f.text_field :description %> + <%= f.text_field :description, class: 'form-control' %> + +
        + <%= f.check_box :active %> + <%= f.label :active %> +
        - <%= f.label :active %> - <%= f.check_box :active %>
        <%= f.label "Categories:" %> <% @categories.each do |c| %> <%= check_box_tag "categories[]", c.id, @product.categories.include?(c) %> <%= label_tag c.name %> <% end %> - <%= f.submit %> + <%= f.submit value: "Add Product", class: "btn btn-primary" %>
        <% end %> diff --git a/app/views/products/new.html.erb b/app/views/products/new.html.erb index 60c4a84a61..3deee5bd4b 100644 --- a/app/views/products/new.html.erb +++ b/app/views/products/new.html.erb @@ -1,5 +1,5 @@ -

        New Product

        +

        Add a Product

        <%= render 'form' %> -<%= link_to 'Back', user_products_path(@user) %> +<%= link_to 'View My Products', user_products_path(@user) %> diff --git a/vendor/assets/stylesheets/awesome-bootstrap-checkbox.scss b/vendor/assets/stylesheets/awesome-bootstrap-checkbox.scss new file mode 100644 index 0000000000..225443ef86 --- /dev/null +++ b/vendor/assets/stylesheets/awesome-bootstrap-checkbox.scss @@ -0,0 +1,1736 @@ + + + + + + + + + + + + + + awesome-bootstrap-checkbox/awesome-bootstrap-checkbox.scss at master · flatlogic/awesome-bootstrap-checkbox + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + + + + + + + + + + + + +
        + +
        +
        + + +
        +
        +
        + +
        +
        + + + +
          + +
        • +
          + +
          + + + + Watch + + + + +
          + +
          +
          + +
        • + +
        • + +
          + +
          + + + +
          + + +
          + +
        • + +
        • + + + Fork + + + + + +
        • +
        + +

        + + /awesome-bootstrap-checkbox + + + + + +

        + +
        + +
        + +
        +
        + + + + + + + +
        + +
        + + + +
        + +
        + + Find file + + +
        + +
        + + +
        + + + 6e8e262 + + + + + + + + +
        + +
        +
        +
        + +
        + Raw + Blame + History +
        + + + + + +
        + +
        + +
        + +
        + 214 lines (179 sloc) + + 4.11 KB +
        +
        + + + +
        +
      Product
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      //
      // Checkboxes
      // --------------------------------------------------
      +
      +
      $font-family-icon: 'FontAwesome' !default;
      $fa-var-check: "\f00c" !default;
      $check-icon: $fa-var-check !default;
      +
      @mixin checkbox-variant($parent, $color) {
      #{$parent} input[type="checkbox"]:checked + label,
      #{$parent} input[type="radio"]:checked + label {
      &::before {
      background-color: $color;
      border-color: $color;
      }
      &::after{
      color: #fff;
      }
      }
      }
      +
      +
      .checkbox{
      padding-left: 20px;
      +
      label{
      display: inline-block;
      vertical-align: middle;
      position: relative;
      padding-left: 5px;
      +
      &::before{
      content: "";
      display: inline-block;
      position: absolute;
      width: 17px;
      height: 17px;
      left: 0;
      margin-left: -20px;
      border: 1px solid $input-border;
      border-radius: 3px;
      background-color: #fff;
      @include transition(border 0.15s ease-in-out, color 0.15s ease-in-out);
      }
      +
      &::after{
      display: inline-block;
      position: absolute;
      width: 16px;
      height: 16px;
      left: 0;
      top: 0;
      margin-left: -20px;
      padding-left: 3px;
      padding-top: 1px;
      font-size: 11px;
      color: $input-color;
      }
      }
      +
      input[type="checkbox"],
      input[type="radio"] {
      opacity: 0;
      z-index: 1;
      +
      &:focus + label::before{
      @include tab-focus();
      }
      +
      &:checked + label::after{
      font-family: $font-family-icon;
      content: $check-icon;
      }
      +
      &:disabled + label{
      opacity: 0.65;
      +
      &::before{
      background-color: $input-bg-disabled;
      cursor: not-allowed;
      }
      }
      +
      }
      +
      &.checkbox-circle label::before{
      border-radius: 50%;
      }
      +
      &.checkbox-inline{
      margin-top: 0;
      }
      }
      +
      @include checkbox-variant('.checkbox-primary', $brand-primary);
      @include checkbox-variant('.checkbox-danger', $brand-danger);
      @include checkbox-variant('.checkbox-info', $brand-info);
      @include checkbox-variant('.checkbox-warning', $brand-warning);
      @include checkbox-variant('.checkbox-success', $brand-success);
      +
      //
      // Radios
      // --------------------------------------------------
      +
      @mixin radio-variant($parent, $color) {
      #{$parent} input[type="radio"]{
      + label{
      &::after{
      background-color: $color;
      }
      }
      &:checked + label{
      &::before {
      border-color: $color;
      }
      &::after{
      background-color: $color;
      }
      }
      }
      }
      +
      .radio{
      padding-left: 20px;
      +
      label{
      display: inline-block;
      vertical-align: middle;
      position: relative;
      padding-left: 5px;
      +
      &::before{
      content: "";
      display: inline-block;
      position: absolute;
      width: 17px;
      height: 17px;
      left: 0;
      margin-left: -20px;
      border: 1px solid $input-border;
      border-radius: 50%;
      background-color: #fff;
      @include transition(border 0.15s ease-in-out);
      }
      +
      &::after{
      display: inline-block;
      position: absolute;
      content: " ";
      width: 11px;
      height: 11px;
      left: 3px;
      top: 3px;
      margin-left: -20px;
      border-radius: 50%;
      background-color: $input-color;
      @include scale(0, 0);
      +
      @include transition-transform(.1s cubic-bezier(.8,-0.33,.2,1.33));
      //curve - http://cubic-bezier.com/#.8,-0.33,.2,1.33
      }
      }
      +
      input[type="radio"]{
      opacity: 0;
      z-index: 1;
      +
      &:focus + label::before{
      @include tab-focus();
      }
      +
      &:checked + label::after{
      @include scale(1, 1);
      }
      +
      &:disabled + label{
      opacity: 0.65;
      +
      &::before{
      cursor: not-allowed;
      }
      }
      +
      }
      +
      &.radio-inline{
      margin-top: 0;
      }
      }
      +
      @include radio-variant('.radio-primary', $brand-primary);
      @include radio-variant('.radio-danger', $brand-danger);
      @include radio-variant('.radio-info', $brand-info);
      @include radio-variant('.radio-warning', $brand-warning);
      @include radio-variant('.radio-success', $brand-success);
      +
      +
      input[type="checkbox"],
      input[type="radio"] {
      &.styled:checked + label:after {
      font-family: $font-family-icon;
      content: $check-icon;
      }
      .styled:checked + label {
      &::before {
      color: #fff;
      }
      &::after {
      color: #fff;
      }
      }
      }
      + +
      + +
      + +Jump to Line + + +
    + +
    + +
    +
    + +
    + +
    + +
    + + + + + + + +
    + + + Something went wrong with that request. Please try again. +
    + + + + + + + + + + + From 6c5016a11b74352530da3b4687c67218562d136b Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 15 Dec 2015 14:39:56 -0800 Subject: [PATCH 188/299] Complete order confirmation page, clear cart when an order is submitted --- app/controllers/orders_controller.rb | 3 +++ app/helpers/application_helper.rb | 4 ++++ app/models/order.rb | 8 +++++++ app/views/orders/confirm.html.erb | 32 ++++++++++++++++++++++++++++ 4 files changed, 47 insertions(+) diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index c0322e5685..b74e32b048 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -23,6 +23,7 @@ def create oi.save end if @order.save + session[:cart] = nil redirect_to confirmation_path(@order) else render :new @@ -30,6 +31,8 @@ def create end def confirm + @order = Order.find(params[:order_id]) + @total = @order.total_cost end private diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index a1163162da..b7b6d6a7a8 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -21,4 +21,8 @@ def bootstrap_class_for flash_type def readable_date(date) date.strftime('%b %-e, %Y') end + + def readable_time(date) + date.strftime("%l:%M%p") + end end diff --git a/app/models/order.rb b/app/models/order.rb index 6a513bc67d..a6d57c852d 100644 --- a/app/models/order.rb +++ b/app/models/order.rb @@ -5,4 +5,12 @@ class Order < ActiveRecord::Base validates_numericality_of :zip, :cc_num, allow_nil: true validates_length_of :zip, is: 5, allow_nil: true validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i }, allow_nil: true + + def total_cost + total = 0 + self.order_items.each do |oi| + total += (oi.product.price * oi.quantity) + end + return total + end end diff --git a/app/views/orders/confirm.html.erb b/app/views/orders/confirm.html.erb index 74901e0b84..467ced6169 100644 --- a/app/views/orders/confirm.html.erb +++ b/app/views/orders/confirm.html.erb @@ -1 +1,33 @@

    Thank you for shopping on Wetsy!

    +

    + + + + + <% @order.order_items.each do |oi| %> + + + + + <% end %> + +
    + Items purchased + + Quantity + + Subtotal +
    <%= link_to oi.product.name, user_product_path(oi.product.user, oi.product) %><%= oi.quantity %><%= dollar_price(oi.quantity * oi.product.price) %>
    +

    +

    + Order Total: + <%= dollar_price(@total) %> +

    +

    + Purchased: + <%= readable_date(@order.created_at) %> at <%= readable_time(@order.created_at) %> +

    +

    + Status: + <%= @order.status %> +

    From dd48d34f60f59aa6a8208e4d2fc15ddc4f394d1b Mon Sep 17 00:00:00 2001 From: Tammy Date: Tue, 15 Dec 2015 14:47:44 -0800 Subject: [PATCH 189/299] still canot update quantity in the cart --- app/controllers/carts_controller.rb | 2 +- app/views/carts/index.html.erb | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/app/controllers/carts_controller.rb b/app/controllers/carts_controller.rb index 3ba589a957..aa80ead096 100644 --- a/app/controllers/carts_controller.rb +++ b/app/controllers/carts_controller.rb @@ -25,7 +25,7 @@ def add cart[product_id] = cart[product_id] + 1 redirect_to cart_path else - flash[:error] = "The product is not on stock" + flash[:error] = "The product is out of stock" redirect_to user_product_path(product.user_id, product.id) end else diff --git a/app/views/carts/index.html.erb b/app/views/carts/index.html.erb index ae1eef82b2..f921569ed8 100644 --- a/app/views/carts/index.html.erb +++ b/app/views/carts/index.html.erb @@ -1,9 +1,4 @@

    Cart

    - -<% if !flash.now[:error].nil? %> - <%= flash.now[:error] %> -<% end %> - From 807137b95b2bc7c6e5993707447edb30f63c4f7b Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 15 Dec 2015 14:58:56 -0800 Subject: [PATCH 190/299] Update cart index view to handle empty cart, update cart#destroy to clear session[:cart] when all products are removed --- app/controllers/carts_controller.rb | 2 +- app/views/carts/index.html.erb | 41 ++++++++++++++++++----------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/app/controllers/carts_controller.rb b/app/controllers/carts_controller.rb index aa80ead096..61b537cdd1 100644 --- a/app/controllers/carts_controller.rb +++ b/app/controllers/carts_controller.rb @@ -44,7 +44,7 @@ def destroy cart = session[:cart] product_id = params[:id] cart.delete(product_id) + session[:cart] = nil if session[:cart] == {} redirect_to cart_path end - end diff --git a/app/views/carts/index.html.erb b/app/views/carts/index.html.erb index f921569ed8..efcec4a8e5 100644 --- a/app/views/carts/index.html.erb +++ b/app/views/carts/index.html.erb @@ -1,19 +1,28 @@

    Cart

    -
    Product Description
    - - - - - <% @cart.each do |product_id, quantity| %> - <% product = Product.find(product_id) %> - - - - - - - - <% end %> +<% if session[:cart] == nil %> +

    + Cart is empty! +

    +<% else %> +
    Product Description Price quantity
    <%= link_to product.name, user_product_path(product.user_id, product.id) %> <%= product.description %> <%= product.price %> <%= quantity %> <%= link_to 'Remove', remove_user_product_path(product.user_id, product.id), method: :delete, data: { confirm: 'Are you sure?' } %>
    + + + + + <% @cart.each do |product_id, quantity| %> + <% product = Product.find(product_id) %> + + + + + + + + <% end %>
    Product Description Price quantity
    <%= link_to product.name, user_product_path(product.user_id, product.id) %> <%= product.description %> <%= product.price %> <%= quantity %> <%= link_to 'Remove', remove_user_product_path(product.user_id, product.id), method: :delete, data: { confirm: 'Are you sure?' } %>
    -

    Items total $ <%= Cart.subtotal(@cart) %>

    +

    Items total <%= dollar_price(Cart.subtotal(@cart)) %>

    <%= link_to "Proceed to Checkout", checkout_new_path %> +<% end %> +

    + <%= link_to "Continue Shopping", products_path %> +

    From 7064e29e35669e9d78db4c7e64e0a8349fb4394c Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Tue, 15 Dec 2015 15:00:13 -0800 Subject: [PATCH 191/299] create browse by merchant page --- app/controllers/users_controller.rb | 2 +- app/models/product.rb | 6 ++- app/models/user.rb | 11 +++++ app/views/categories/index.html.erb | 2 +- app/views/shared/_navbar.html.erb | 2 +- app/views/users/index.html.erb | 71 ++++++++++++++++++----------- 6 files changed, 63 insertions(+), 31 deletions(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 6a7176b3c3..0d0d8b79f3 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -5,7 +5,7 @@ class UsersController < ApplicationController before_action :require_logout, only: [:new] def index - @users = User.all + @users = User.all.sort_by { |user| user.average_rating }.reverse! end def show diff --git a/app/models/product.rb b/app/models/product.rb index e439ee237a..c406f365a2 100644 --- a/app/models/product.rb +++ b/app/models/product.rb @@ -11,9 +11,13 @@ class Product < ActiveRecord::Base validates_numericality_of :stock, :greater_than_or_equal_to => 0 validates :photo_url, format: {with: /\.(png|jpg)\Z/i}, allow_nil: true + def review_total + return reviews.inject(0) { |sum, review| sum + review.rating } + end + def review_average if reviews.any? - total = reviews.inject(0) { |sum, review| sum + review.rating } + total = review_total return total * 1.0 / reviews.count else return 0 diff --git a/app/models/user.rb b/app/models/user.rb index a3e93b8c47..c5e3799d5e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -9,4 +9,15 @@ class User < ActiveRecord::Base validates :username, :email, presence: true validates :username, :email, uniqueness: true validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i } + + def average_rating + return 0 if products.count == 0 + total_rating = 0.0 + total_reviews = 0 + products.each do |product| + total_rating += product.review_total + total_reviews += product.reviews.count + end + return total_rating / total_reviews + end end diff --git a/app/views/categories/index.html.erb b/app/views/categories/index.html.erb index ad1a7466b8..97c7cac926 100644 --- a/app/views/categories/index.html.erb +++ b/app/views/categories/index.html.erb @@ -45,9 +45,9 @@
    + <% count += 1 %> <% end %>
    - <% count += 1 %> <% if count % 4 == 0 %>
    diff --git a/app/views/shared/_navbar.html.erb b/app/views/shared/_navbar.html.erb index 82bb67aed9..9b33837f27 100644 --- a/app/views/shared/_navbar.html.erb +++ b/app/views/shared/_navbar.html.erb @@ -19,7 +19,7 @@ <% if logged_in? %> diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb index c14eaa11b1..9c5d179b9d 100644 --- a/app/views/users/index.html.erb +++ b/app/views/users/index.html.erb @@ -1,31 +1,48 @@

    <%= notice %>

    -

    Listing Users

    +

    Browse by Merchant

    - - - - - - - - - - - - <% @users.each do |user| %> - - - - - - - - +
    + <% count = 0 %> + <% @users.each do |user| %> + <% if user.products.exists? %> + + <% product = user.products.max_by { |product| product.review_average } %> +
    +

    <%= link_to user.name.capitalize, user_products_path(user.id) %>

    +

    Average rating: <%= user.average_rating.round(1) %>

    +

    Most Popular Product:

    +
    +
    + <%= image_tag product.photo_url, alt: "product photo" %> +
    +
    +
    <%= dollar_price(product.price) %>
    +
    <%= link_to product.name, user_product_path(product.user_id, product.id) %> +
    +

    + <% if !product.description.nil? %> + <%= product.description %> + <% else %> +
    + <% end %> +

    +
    +
    +

    <%= product.stock %> Available

    +
    +
    +

    Average rating: <%= product.review_average.round(1) %>

    +
    +
    +
    +
    + + <% count += 1 %> + <% end %> +
    + <% if count % 4 == 0 %> +
    +
    <% end %> -
    -
    UsernameEmailName
    <%= user.username %><%= user.email %><%= user.name %><%= link_to 'Show', user %><%= link_to 'Edit', edit_user_path(user) %><%= link_to 'view my orders', user_orders_path(user.id) %>
    - -
    - -<%= link_to 'New User', new_user_path %> + <% end %> From 8235f0b32d192e841d9c986222b59e1b01af944b Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 15 Dec 2015 15:05:55 -0800 Subject: [PATCH 192/299] Update cart#index --- app/controllers/carts_controller.rb | 6 +----- app/views/orders/show.html.erb | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/app/controllers/carts_controller.rb b/app/controllers/carts_controller.rb index 61b537cdd1..d179985ecc 100644 --- a/app/controllers/carts_controller.rb +++ b/app/controllers/carts_controller.rb @@ -1,11 +1,7 @@ class CartsController < ApplicationController def index - if session[:cart] - @cart = session[:cart] - else - @cart = {} - end + @cart = session[:cart] end def add diff --git a/app/views/orders/show.html.erb b/app/views/orders/show.html.erb index 1f0556b3c4..c788f767cc 100644 --- a/app/views/orders/show.html.erb +++ b/app/views/orders/show.html.erb @@ -52,4 +52,3 @@

    <%= link_to 'Back', user_orders_path(@user.id, @order.id) %> -<%= link_to 'Order Item', user_order_order_items_path(@user.id, @order.id) %> From c40edcd7a8b26ee0b6fa65430fc4fc2702b0f457 Mon Sep 17 00:00:00 2001 From: Kelly Date: Tue, 15 Dec 2015 15:10:39 -0800 Subject: [PATCH 193/299] update My Cart link in nav bar --- app/views/shared/_navbar.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/shared/_navbar.html.erb b/app/views/shared/_navbar.html.erb index 82bb67aed9..b69c0392cc 100644 --- a/app/views/shared/_navbar.html.erb +++ b/app/views/shared/_navbar.html.erb @@ -37,7 +37,7 @@
  • <%= link_to "Log In", login_path %>
  • <% end %> -
  • My Cart
  • +
  • <%= link_to "My Cart", cart_path %>
  • From 701deb654f0efa8206bc8a84af84b244ad3b3e9b Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 17 Dec 2015 16:00:02 -0800 Subject: [PATCH 250/299] optimize page loading --- app/controllers/products_controller.rb | 2 +- app/controllers/welcome_controller.rb | 2 +- app/models/user.rb | 12 ++++-------- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index b8f5b835a6..a8e2efdbd2 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -6,7 +6,7 @@ class ProductsController < ApplicationController before_action :correct_user, only: [:new, :edit, :create, :update] def index - @products = Product.all.includes(:reviews).paginate(page: params[:page], per_page: 12) + @products = Product.all.paginate(page: params[:page], per_page: 12) end def show diff --git a/app/controllers/welcome_controller.rb b/app/controllers/welcome_controller.rb index fd1e7b9459..05d27d42be 100644 --- a/app/controllers/welcome_controller.rb +++ b/app/controllers/welcome_controller.rb @@ -1,5 +1,5 @@ class WelcomeController < ApplicationController def index - @products = Product.limit(12).includes(:reviews) + @products = Product.limit(12) end end diff --git a/app/models/user.rb b/app/models/user.rb index 32e48c97bf..398db03125 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -2,6 +2,7 @@ class User < ActiveRecord::Base has_many :products has_many :order_items, through: :products has_many :orders, through: :order_items + has_many :reviews, through: :products has_secure_password before_validation { self.email = email.downcase if self.email } # ensures emails are all lowercase @@ -11,13 +12,8 @@ class User < ActiveRecord::Base validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i } def average_rating - return 0 if products.count == 0 - total_rating = 0.0 - total_reviews = 0 - products.each do |product| - total_rating += product.review_total - total_reviews += product.reviews.count - end - total_reviews == 0 ? (return 0) : (return total_rating / total_reviews) + total_rating = reviews.sum(:rating) + total_reviews = reviews.count(:rating) + total_reviews == 0 ? (return 0) : (return total_rating * 1.0 / total_reviews) end end From fde616657cd54d401c0b6546b99f2dd4d0ad841d Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 17 Dec 2015 16:28:11 -0800 Subject: [PATCH 251/299] style the order fulfillment page --- app/controllers/orders_controller.rb | 2 +- app/views/orders/index.html.erb | 110 +++++++++++++++------------ 2 files changed, 61 insertions(+), 51 deletions(-) diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index 55a238561c..77224bf6e7 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -5,7 +5,7 @@ class OrdersController < ApplicationController before_action :find_user, except: [:new, :create, :confirm, :cancel] def index - orders = @user.orders.includes(:order_items) + orders = @user.orders @orders = orders.uniq.sort @paid_orders = Order.filter_orders(@orders, "paid") @completed_orders = Order.filter_orders(@orders, "shipped") diff --git a/app/views/orders/index.html.erb b/app/views/orders/index.html.erb index f7f1192a24..ee6adaca1c 100644 --- a/app/views/orders/index.html.erb +++ b/app/views/orders/index.html.erb @@ -1,37 +1,40 @@

    <%= notice %>

    <%= @user.name %>'s Order Fulfillment Page

    - -

    Revenue

    -

    - Total Revenue from Paid Orders (Not Shipped): <%= dollar_price(@paid_orders_revenue) %> -

    -

    - Total Revenue from Completed Orders (Shipped): <%= dollar_price(@completed_orders_revenue) %> -

    -

    - Total Revenue: <%= dollar_price(@total_revenue) %> -

    - -<%= link_to "Products to be shipped", not_shipped_yet_path(@user.id) %> -

    Orders

    -

    - Total Paid Orders (Not Shipped): <%= @paid_orders.count %> -

    -

    - Total Completed Orders (Shipped): <%= @completed_orders.count %> -

    -

    - Total Cancelled Orders: <%= @cancelled_orders.count %> -

    -

    - <%= form_tag '', :method => :get do %> - <%= select_tag "Status", options_for_select(["Paid", "Shipped", "Cancelled"]), prompt: "Select" %> - <%= submit_tag 'Filter by Order Status' %> - <% end %> -

    -
    -<% @orders.each do |order| %> +
    +
    + +

    Orders

    +

    Total Paid Orders (Not Shipped): <%= @paid_orders.count %>

    +

    Total Completed Orders (Shipped): <%= @completed_orders.count %>

    +

    Total Cancelled Orders: <%= @cancelled_orders.count %>

    +

    + <%= form_tag '', :method => :get do %> + <%= select_tag "Status", options_for_select(["Paid", "Shipped", "Cancelled"]), prompt: "Select" %> + <%= submit_tag 'Filter by Order Status' %> + <% end %> +

    +
    + +
    +
    + +

    Revenue

    +

    Total Revenue from Paid Orders (Not Shipped): <%= dollar_price(@paid_orders_revenue) %>

    +

    Total Revenue from Completed Orders (Shipped): <%= dollar_price(@completed_orders_revenue) %>

    +

    Total Revenue: <%= dollar_price(@total_revenue) %>

    + <%= link_to "Products to be shipped", not_shipped_yet_path(@user.id) %> + +
    +
    +
    +<% @orders.to_ary.in_groups_of(2, false) do |group| %> +
    + +<% group.each do |order| %> + +
    +

    Order <%= link_to "##{order.id}", user_order_path(@user.id, order.id) %>

    Status: <%= order.status %> @@ -53,25 +56,32 @@ - <% order.order_items.includes(product: [:user]).each do |order_item| %> - <% if order_item.product.user == @user %> - - <%= link_to order_item.product.name, user_product_path(order_item.product.user, order_item.product) %> - <%= order_item.quantity %> - <%= dollar_price(order_item.quantity * order_item.product.price) %> - <%= order_item.shipped ? "Shipped" : "Not Shipped" %> - - <% if order.status!= "cancelled" %> - <% if !order_item.shipped %> - <%= button_to "Mark as Shipped", shipped_path(@user.id, order.id, order_item.id), class:"btn btn-default" %> - <% else %> - <%= button_to "Cancel Shipping", shipped_path(@user.id, order.id, order_item.id), class:"btn btn-default" %> - <% end %> - <% end %> - - - <% end %> - <% end %> + <% order.order_items.includes(product: [:user]).each do |order_item| %> + <% if order_item.product.user == @user %> + + <%= link_to order_item.product.name, user_product_path(order_item.product.user, order_item.product) %> + <%= order_item.quantity %> + <%= dollar_price(order_item.quantity * order_item.product.price) %> + <%= order_item.shipped ? "Shipped" : "Not Shipped" %> + + <% if order.status!= "cancelled" %> + <% if !order_item.shipped %> + <%= button_to "Mark as Shipped", shipped_path(@user.id, order.id, order_item.id), class:"btn btn-default" %> + <% else %> + <%= button_to "Cancel Shipping", shipped_path(@user.id, order.id, order_item.id), class:"btn btn-default" %> + <% end %> + <% end %> + + + <% end %> + <% end %> + +

    + +<% end %> + +
    <% end %> + From 86a3bf125cd703f6dc3bc7a8d2c5e3d3fa3af24c Mon Sep 17 00:00:00 2001 From: Kelly Date: Thu, 17 Dec 2015 18:36:50 -0800 Subject: [PATCH 252/299] update order model tests --- spec/models/order_spec.rb | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/spec/models/order_spec.rb b/spec/models/order_spec.rb index 341395c909..8f3b2f6b69 100644 --- a/spec/models/order_spec.rb +++ b/spec/models/order_spec.rb @@ -9,11 +9,10 @@ let (:user_2) { User.create(email: 'nemo1@foo.com', name: "Bob1", username: "bobi1", password: "333", password_confirmation: "333") } let (:product_1) { Product.create(name: "Sample", price: 10, stock: 5, user_id: user_1.id) } let (:product_2) { Product.create(name: "Sample1", price: 15, stock: 5, user_id: user_2.id) } - let (:order_item_1) { OrderItem.create(product_id: product_1.id, quantity: 3) } - let (:order_item_2) { OrderItem.create(product_id: product_2.id, quantity: 2) } - let (:order_1) { Order.create(good_params.merge(email: "email1@email.com", order_items: [order_item_1])) } - let (:order_2) { Order.create(good_params.merge(email: "email1@email.com", order_items: [order_item_2])) } - let (:orders) { [order_1, order_2] } + let (:order_item_1) { OrderItem.create(product_id: product_1.id, quantity: 3, shipped: false) } + let (:order_item_2) { OrderItem.create(product_id: product_2.id, quantity: 2, shipped: true) } + let (:order_1) { Order.create(good_params.merge(email: "email1@email.com", order_items: [order_item_1], status: "paid")) } + let (:order_2) { Order.create(good_params.merge(email: "email1@email.com", order_items: [order_item_2], status: "complete")) } describe ".validates" do it { is_expected.to validate_length_of(:zip) } @@ -50,18 +49,18 @@ end describe ".user_orders_revenue" do + it "calculates a user's revenue from a collection of orders" do + orders = [order_1, order_2] expect(Order.user_orders_revenue(orders, user_1)).to eq(30) end end - describe ".check_order_shipped" do - it "updates the order status to 'shipped' if all order items have shipped" do - - end - - it "changes the order status back to 'paid' if an order item's shipment is cancelled" do - + describe '.filter_orders' do + it "returns orders with a status matching the status parameter" do + orders = [order_1, order_2] + expect(Order.filter_orders(orders, "paid").length).to eq 1 + expect(Order.filter_orders(orders, "paid")[0].id).to eq order_1.id end end end From 8e0d9bfddcf97a0b19b2f0bebb79f4187fe04a17 Mon Sep 17 00:00:00 2001 From: Kelly Date: Thu, 17 Dec 2015 19:25:00 -0800 Subject: [PATCH 253/299] Add tests for orders controller --- app/controllers/orders_controller.rb | 3 +- spec/controllers/orders_controller_spec.rb | 50 ++++++++++++++++------ 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index 77224bf6e7..52a39a6bed 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -25,7 +25,7 @@ def show def new not_enough_stock = false @order_items.each do |oi| - not_enough_stock = true if oi.product.stock < oi.quantity + not_enough_stock = true if Product.find(oi.product_id).stock < oi.quantity end if not_enough_stock flash[:error] = "There is not enough stock to complete your purchase. Please update your cart." @@ -35,7 +35,6 @@ def new end end - def cancel order = Order.find(params[:id]) order.update(:status => "cancelled") diff --git a/spec/controllers/orders_controller_spec.rb b/spec/controllers/orders_controller_spec.rb index 516342d7b5..7d318dd8a8 100644 --- a/spec/controllers/orders_controller_spec.rb +++ b/spec/controllers/orders_controller_spec.rb @@ -1,26 +1,28 @@ require 'rails_helper' RSpec.describe OrdersController, type: :controller do - let (:sample_user) { - User.create(username: "Kelly", email: "Kelly@kelly.com", password: "password") - } + + let (:product) { FactoryGirl.create(:product) } let (:good_params) { - { user_id: sample_user.id, + { user_id: product.user.id, order: { email: "Kelly@kelly.com", street: "test" , city: "Seattle", state: "WA", zip: "98116", cc_num: "123", cc_cvv: "123", cc_name: "Kelly", cc_exp: "20151215"} } } + let (:order) { Order.create(good_params[:order].merge(status: "paid")) } + let (:bad_params) { - { user_id: sample_user.id, + { user_id: product.user.id, order: { zip: "zzz" } } } + describe "GET 'index'" do it "is successful" do - session[:user_id] = sample_user.id - get :index, user_id: sample_user.id + session[:user_id] = product.user.id + get :index, user_id: product.user.id expect(response.status).to eq 200 end end @@ -28,31 +30,51 @@ describe "GET 'show'" do it "renders the show view" do sample_order = Order.create(good_params[:order]) - get :show, id: sample_order.id, user_id: sample_user.id + get :show, id: sample_order.id, user_id: product.user.id expect(subject).to render_template :show end end describe "GET 'new'" do - it "renders new view" do - session[:cart] = { 1 => 2, 3 => 4 } - get :new, user_id: sample_user.id + it "renders new view when there's enough stock" do + session[:cart] = { product.id => 2 } + get :new, user_id: product.user.id expect(subject).to render_template :new end + + it "redirects to cart page when there's not enough stock" do + session[:cart] = { product.id => 11 } + get :new, user_id: product.user.id + expect(subject).to redirect_to cart_path + end end describe "POST 'create'" do it "redirects to checkout confirmation page" do - session[:cart] = { 1 => 2, 3 => 4 } - session[:user_id] = sample_user.id + session[:cart] = { product.id => 2 } + session[:user_id] = product.user.id post :create, good_params expect(subject).to redirect_to confirmation_path(Order.all.last) end it "renders new template on error" do - session[:cart] = { 1 => 2, 3 => 4 } + session[:cart] = { product.id => 2 } post :create, bad_params expect(subject).to render_template :new end end + + describe "GET 'confirm'" do + it "is successful" do + get :confirm, order_id: order.id + expect(response.status).to eq 200 + end + end + + describe "POST 'cancel'" do + it "redirects to root_path" do + post :cancel, id: order.id + expect(subject).to redirect_to root_path + end + end end From ac269d76ed8034c93a5f419162faede08a99437e Mon Sep 17 00:00:00 2001 From: Kelly Date: Thu, 17 Dec 2015 20:17:41 -0800 Subject: [PATCH 254/299] Add retire product functionality --- app/controllers/products_controller.rb | 16 +++++++++++++--- app/controllers/users_controller.rb | 2 +- app/views/shared/_products.html.erb | 7 +++++++ config/routes.rb | 2 ++ spec/controllers/orders_controller_spec.rb | 1 - 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index a8e2efdbd2..39d924fd03 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -2,11 +2,11 @@ class ProductsController < ApplicationController before_action :find_product, only: [:show, :edit, :update] before_action :find_user, only: [:new, :edit, :create, :update] before_action :all_categories, only: [:new, :edit, :create, :update] - before_action :require_login, only: [:new, :edit, :create, :update] - before_action :correct_user, only: [:new, :edit, :create, :update] + before_action :require_login, only: [:new, :edit, :create, :update, :retire] + before_action :correct_user, only: [:new, :edit, :create, :update, :retire] def index - @products = Product.all.paginate(page: params[:page], per_page: 12) + @products = Product.all.paginate(page: params[:page], per_page: 12).where(active: true) end def show @@ -51,6 +51,16 @@ def update end end + def retire + product = Product.find(params[:id]) + if product.active + product.update(:active => false) + else + product.update(:active => true) + end + redirect_to user_products_path(product.user) + end + private def find_product diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index ad038ffeb9..fb9852a8f8 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -16,7 +16,7 @@ def new end def products - @products = @user.products.paginate(page: params[:page], per_page: 12) + @products = @user.products.paginate(page: params[:page], per_page: 12).order(active: :desc) end def edit diff --git a/app/views/shared/_products.html.erb b/app/views/shared/_products.html.erb index e20ab09296..df58aa258d 100644 --- a/app/views/shared/_products.html.erb +++ b/app/views/shared/_products.html.erb @@ -22,6 +22,13 @@

    <%= link_to "Edit item", edit_user_product_path(product.user.id, product.id) %>

    +

    + <% if product.active %> + <%= link_to "Retire item", retire_user_product_path(product.user.id, product.id), method: :post %> + <% else %> + <%= link_to "Activate item", retire_user_product_path(product.user.id, product.id), method: :post %> + <% end %> +

    diff --git a/config/routes.rb b/config/routes.rb index 7c465f0b76..f9bb7a6c6a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -12,11 +12,13 @@ resources :order_items, only: [:show] end resources :products, except: [:index, :destroy] do + resources :reviews, except: [:new] member do post 'cart/' => 'carts#add', as: :add_to_cart patch 'cart/' => 'carts#update' delete 'cart/' => 'carts#destroy', as: :remove + post '/' => 'products#retire', as: :retire end end end diff --git a/spec/controllers/orders_controller_spec.rb b/spec/controllers/orders_controller_spec.rb index 7d318dd8a8..b1f763f5af 100644 --- a/spec/controllers/orders_controller_spec.rb +++ b/spec/controllers/orders_controller_spec.rb @@ -18,7 +18,6 @@ } } - describe "GET 'index'" do it "is successful" do session[:user_id] = product.user.id From f00971f6fbe4f0779ca0f72c3b8ccc7a038274a8 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 17 Dec 2015 20:57:20 -0800 Subject: [PATCH 255/299] update navbar --- app/views/shared/_navbar.html.erb | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/app/views/shared/_navbar.html.erb b/app/views/shared/_navbar.html.erb index 60a950f4f3..7bdab46e2a 100644 --- a/app/views/shared/_navbar.html.erb +++ b/app/views/shared/_navbar.html.erb @@ -8,7 +8,7 @@ - + <%= link_to "Wetsy", root_path, class: "navbar-brand" %>
    @@ -40,13 +40,6 @@
  • <%= link_to "My Cart", cart_path %>
  • - -
    - -
    - - -
    From 85ed05ad6660c20625970adbe1ab9600ad65ee45 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 17 Dec 2015 20:57:26 -0800 Subject: [PATCH 256/299] change banner --- app/assets/images/banner2.jpg | Bin 0 -> 219945 bytes app/assets/stylesheets/application.scss | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 app/assets/images/banner2.jpg diff --git a/app/assets/images/banner2.jpg b/app/assets/images/banner2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8e51693100de63d9bb06df43eb4703055d0ea631 GIT binary patch literal 219945 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®PwA?LpbPHhGW}>lM!9B!sM4&%En&-c@ar;$T z7n4b&n$Ae2ujzkhxQW#q+)B9#E0DnY=a0&@!(ut&)%0D8N^#O#8c^9ys%Y^{w(wm| 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 Date: Thu, 17 Dec 2015 21:21:50 -0800 Subject: [PATCH 257/299] add styling to order fulfillment page --- app/assets/images/concrete_seamless.png | Bin 0 -> 81227 bytes app/assets/stylesheets/application.scss | 24 ++++++++++++++++++++++++ app/views/orders/index.html.erb | 2 ++ app/views/welcome/index.html.erb | 2 +- 4 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 app/assets/images/concrete_seamless.png diff --git a/app/assets/images/concrete_seamless.png b/app/assets/images/concrete_seamless.png new file mode 100644 index 0000000000000000000000000000000000000000..720549ee469d17c679c018f784f556cf594d3356 GIT binary patch literal 81227 zcmV)CK*GO?P)+J08>FMd{=;-qD^6>ER@9*#K?(XH~<>%+;-QC^d;^OM+>fYYo?e6XI@$u~K z?fLon($do7gwt2?dFMb2@9y~c_~PT@@$vBN?Ca#@GSjQ@$&NS@9*a3<@NRS^z`%V z>+0a(-}CbF_4W1K+}zmM*wE0>+1c6O-`~^I)7skF+uPgV;NaHQ*3Qn()YR11*Vpgw z@X^uH)z#JM>gm+g)bH@`=;-J0@$u*A=kD+B`uh3!`1kks_V)Gl%*@R4^6~EN?ez2W z@bU2L?Cay?FDU?<>c(^>+0+3$+UYwG_~boS8Fb>{O))n({iX?M2!gdt(ZO&3#FBqgG?y|CPA>7~g0&v=%)^BnLC2 zBGlf-{DioF(n4T;{uk5#vW)!cUp-{6F%kKj)e%9)GLPe+#y_PRe#=^bpW^#)Xkz{j zEh>&%K_>*Pf9<`7e(&)ITmL3H1Lr?uuo+@palK@j`R@;(D}etn9=9)1mW%(fV6BzOzYw)wL*Q@o0Qgt@ zCz;v9lq7=dH)7ZYvLNmaKs=~FQ#E$oZ%;Z!@AR=Is$|B0j`Co}e>wj0N7NtmUxhKz zns|O%+uJ00Hvj&=jsG6}ANiM(4`y$?eEa$&`s%e*thElth+5-`*Zop_WORJo9(}&6 zgd6g*)52gow8n^Vdi5|<0*RqY-tWa!Z(@;6BB2=kSXkzvzBVn0JeVhI(@}Oa`e(UZM!n%rwbesg<{0bcYMU ze#`Ft%o2TsNg0+RZ&yN~gtEO&{{8lIQhm%h!ll*i11c<{4+az`GAgtRY-70tzb#(alUszN45p&{Cpp3I{WLD$Lkky1ax2#aZaxlnN&N- z%sClFoBsb;&I1BXIr2W@dlLp$SgnmQKy8FGQzZjhCxL`W3l_Ou5Jf*RUytsKQr(`bGccnc$2dilq4B;40~sh&NNG8(WdtYM5ECZxedvj~A*$ zg-F{QQ6wBvikz!qp#%{=KmlmcXIDpQMY7szb-I!cP2Z9@w7g#@Di4aLgl8guJYpV} zn$i=?qqlmIv`W#$069C8vDAjAguZjd?~=4L{18*4qr`)9OIzpCsOigs9E_8O*&_3Kn&yxuWp1uwGM zule~@i}us4u%kLbICr{=q`vp`uuQg)q=*yIrz#I{A8pBJlft1u1i9Ay{_P(1-3VLRu0 z@SHxn2o}IJtS)=KuOc`{`64v(3!h%;I@_OeJTu{`C86#x5HRdVQO~u*P-%yz1%w zv4Xvz(3WpkVT~t0{rdg>d2;VB#z7=gHjn4k`^{-aY%!R}vyCyynD=iKDx!E_pUY7$5`Ou zL>@_#I?{UXr`RUXFi`2uEN&j~aeukJP918WdM4r@RpbR7m%>#Ul}YaBh{v7kW!eqI zlZR1~WjCoT(+>B)b3+nivsBk=`(p0=^1<2}XO?*#r7NY#d21Dg9=$2YS_VvOo%8F8 zbC~B`_xnj@=^$e5<6PoL0T-$S@-_5~r-Nrhh-Evse}}o zVua;BgsOBR$LH@m=3H%dg%iOYi)n^6N?7rRIN{evXs{3ils#IoL)XWWjJg-~GS<*6V16KnNCQp(+_?CwYGTaYvUFlO7?_<7K5QVgk7PTHFcJ&`!p&(ytvwR@p33 zB(o@j7Hla-;Glv-JCll#Syd(_DM{ZlI*1kZCIpoh+(x@y84NxFkmU3HQD1#w9FSzq zq{gHF(rk~IDTCoZqudX<_q$p{gL+Jf{ zSXHK7Ak9gUkX#BX$&$A-l)QZv1r*SJ;~#Ld)tC40{;R)OVY-g0tBj)I~Nf=-ugCbwP10vW+whViDL zlNQK>Vq&luvsWIsecQGa(gP$3()uz{o7nx6M2!q8IMz4lT*8|QH$>CV%&Dr}pB@jI zCRp=eg_t(TK5Pi@Sr<1Tt4 zFC&gFL{wf2LoO&_G|jj&mtyI}0L3jAfn=!+NoK7wtJ0N2>zRF-G|55HKVJH{C6%GP zZvOZ}9+vWqg-~}Dd=8B>51e9Y@l5Z0^~YGts-(}K*z5Y`c3XUITjy)Mt>+U=q$o3E z3mcKUIDTC^)Ym#fn9>SJ1w@Bx**`DD8UanPII-5D5VX$usHqr}j0jW>5=a3-6TPJ? z$X8QHP>EFA?lFNKAWe$p%3`6?Rc6q20jQD$nh7Eh_Ci+Ij=(Sf_}|~WC!QRY`?Z)E z9TUO>{J5oxUDemVg7fupJuxuGl`zVLC}5LZR7X&SL`hvN#TgXc#8Y=?R^@ZwRC{;tHDQlk#{ZUIv>QhuZOEP zv59FSS_Bk|DgYfZ`%+p_m4~yGSNgD+8LldLOEV2=Z$<+^kQrsh8@wh~>0CX1Rv$sp z4DBquzA0xbChvslwSGKij5EZPy$3-OT7KgkMOO8E&M?<|h|*ZEvR?WCyt@!KCs8P% z^2U@bk)}6q_X!q6(oS-VST{-^v)*#_<_I;7OZVcer+D4lb-iO5zY+voOvtUslwbk77R+D@4TTh4oqLT5Eu@{$F4z$Q5ifs;SgbmKrnB zsfbMgY#_=53$)Vmt__gRw92Hqz0kad1Zh8sSBQcT(V}Wf9Ou&d5n~_z^6Dor)LyS^ zm&R-T?94W?Oh$3MwY7+HhiDF|q9s=bpvpw<^<1UO>233+CR{^bl9daiMddD}(}#H@ zeOx3(It)6k6{|>66j>sy(o=k3Mf`xv{qW~siaedM7JxjWZ4-MV#>vONMG#PtsKK+u zMH1J+GbNf?C2AohL@R^y6>F|FvI4Bs%>EKY?I<0Ci_ zmxHf57XjZsvSzBQZV&V4{hw&a{_TWpDHS})o7ax zpO#vZ!evU$LPV6QD$7SxYA5h~tTk{wuj`s+ZtwR)Cvb!*2R%7$AjlE(s z(+5u|8ii71GEFdFHmL$kl{1~L%vmc)J1ZcxKQ0m4x1>rHOfol_X%;;~)l(@duv(>F z2O)vyEzX~r-{*uXhjhshz?eog_?7%c|0y}<-sB-aP zEF;3{Q?v>%F;G~cQ}O;W$91jac|0G);|dO#xyK4r7GW{HQV?>!@gJ zbV%;TD9z*K=aguAXMXbE|Ad@%jK9K87vKN^o;H8pHdPe9AO|t*Q_-wr)h>$BiThC^ zW9D8l6uEI@{rvsBrK5k=rExGv{&6{Vzw1@AN$9{jeq0EDe$7m$%t{rBh@g&Q4;4u| zq-(_-?fqAyh(G`uci4*PK&X%jp<=LjmV!7F%bGI+eIbScm}E#?&tt{-@$_b{%3Y@2 zA#ax;s`6&>1Qv@Bd5p-^^Kt(@9_xPm`gNcG^<&?frQ~(zrzrbOD!{>aA>~iAsj4RAcoUrIiN6!^jNK(mA_kI2~qkQL}7pmNomUL zM+2)_I%c7(Bh;E-K#81?8s(5B##r-=D}bTyfX9Fh31U};fum^AXGW1{C1pwFl4YRK z<9@ZJ<08$>4wuK9eXR9-AIFdHACKetN{RL4`VNv#pCZfV^qEzBJ`hv6U#S{&Yx_z9 zY0Q*P1i4wEu+#TQ8{RTPE|D4D=D7ueq;&f~QT;Xt5QMev8GCz|oaeum4#aaF2(XX- zOPp=pAAKX^@3>}gJ&rTWZSRXyH^@LWkzM5|h*k_!|BCq$-6QIIOcq2xqdfBiu! z)y~EGIVQI@(0jkT<=p&>jWY=?@r`-oxug5d`cE0f>n&*%oVWkqKJias2 z&b@#7tz=1b(WKa6O4Tgf99707$qAA+Xp)7vWsy`lW%Ay0p!z9ucL?D>){eQD1#%lC z*N@d@MxqL%&eDfHKie)?1n_=C3=x#f4xfa|^j`Ctq^)wUuW_aBI7QDG0d4jws^>iH-lJim{1Kmo=3X~mhwf{&>4_}}}c zgUUo4fKCAKVypiL`O-1@tz}ea>g*w5h4PT&0_V@3lm)>+EN4W z?O{s}uw+`1B+v}060-=EFxE=tr&9z8la?l=_q}2*>Nlr~)qy^)>&+C$WBv2`3@|>s zlqq4(IGy9!0h^98NvEs)c~NjNsMyc(x*wQ|_8bWb$ODOVK>*$UdXTZSQXTe|v$W?*0))jTF;nOnd zEpETc>3tfKUn*RqBf`~ijhJmAJBsdfg>f>U6LtQ4t*`P@GmcZ}UU94V+c_h1lY+?8 zJaJ{R(iJA7gOtACgp$NyYQ;8U(S3C!OlM=p)+j`cbA#vz%34R!8W?kgSi&@+KDxUF zs06KpqSrMw7>rO!(bO>l^82l&RV1lm5r}NLU{OV3Y3M*yUhku!=)U3#Y}-Lu%}KbM(k~$3T#o#oXU-=XN=?EvA(70we-1)G>CZKgU&8)%Bpr z%$vJ# z_wU0K1`FEj8Kw|p#3J$QAWhBr^N3nUMxDTq2jl4Ub(fs1=s1Lu69N>mIyBTV$ruBT z4)Xm3fR3Jul4?ZYSk}pomMiAtO-ZAv5UCOl=lWRjNlOYpRJ`5@&|;dB5D+Cw zD4QfRUy}J9)-mGZ{=T!)1=@Rna*cOYsz?+&N~fh3s=_`iGr36|&I(c1t`e0dv-koH zmG{@5H$?+s#Evj)ip=jf7dK0#C7gjef|{oqrBMDnXMdU!bqykcDk^s10*A;D(M~k^fIF8HwJ~n|;`b;1k$Q>SE_ZC=Dt!PBA zDky+j35gvfc}$c!=O)bpRO^U-hgNqANV}5Adk7&2l{{}EARxw|Bvr!}6;6P&|K(m4 zQv$c0k}UUO3l3J2wkyNc7LCvl6)zTGbNxMjL4{X(~>iIwZ9Y4ALzINcP z=XVUC6t}*kywg=EN%6VyIF1PvQzeeT6@RQX!Carc!q}f4>j3TCpMA6UYdhfQkyOY~ zEcDGmnjS@sr;}9;N#{&Eq$;AK1M+$vRkNdjbsZ0AwGb$J_nZ;v>WB`Bh%%H8CCOUg zQpvt}GLi&EN;Z3iD50T{Xi_0cZI}FfR|w}ch&go6R7J%>Iq2=C&J3u`J=DFqLPc%n zXS*2H1(GGc5YFhJgOmiZC3!~#*O4?NmF*nlRr|W9!hz#I^Oo-8b34W-i~R2^>lzkV z1fx{@`US?&Wt9Y=@DVgiZRb+;@hQ#s!JVJ1+%_V1=$3(Qa$O**dachExzTInRtOlH zAj*eueA9Bt>Sn#>aX^716dfbVKoplm)wtGb%yF!k1C&H2Gh|Wfb}@pxygxLpyrv*Z z>LE!yLIeB_Q50vZDxuV4)fi9ne)mN?A*owYP6kqPvvKCaTVg*$lAU!E4S6Shie*Sj z-m9b_1np*0o9-hXRJJ9^_N6m>R1{_ezW?75=JT=7Xex5%5%cyReUNEQoe}RNJyj(} zKv|y;bnv-sh+GvA?0v$=v3fjXUJo7r^-MkfGArYq-jcDOD9g7MZjWxvUs< zh&D~8nBj=XqLgmXnMtz(s_%CZRK)A$J}w#HEf@)ft(=OrZwz9pLq!U%h@(~Q%r8px z&Y%Ap@%8KP`}HH{*Drnk{PW-W{$^AZ1-kw}OMT3uU9v0*x@ln%Zf+Ts{^9hzEXeOJ z;z%VdC~btdHeIt%3JpCo|Ns9CY_4lA7?@;F6Z_E&bcDY34wP}aGF@Y^xbHD1SgVSi zRA(FlzLL@qd4G3o|HH?H$Aw(GhA%_OtAcy|3bDAgSSEtyyE zGDLu*1;f&1*RIz;bBcU+<<~%av69WHqi2$<_&|7IDHB-KrEEhfE67nacC-R7XV5&&{uw z)~;E2|F74&%?e;W-*FCyl^3u3sq9d0XQCB0s0)(SQgTsVd%}c%ZY6q819*K7lPI{u zS!FL`7<1J~6spwLFh&clTxDlR%Y(L4=uR@{VCHaOWy-p$IzHYy*?ooJEca)DQWYz^ zfOLhrM%Pza=-^Ttc}}ZjyXOrZ%iT^uYGN3IsI(N_a&M<)I~>vT#CG|7Jk@R;vfl#5 zj_c=q;2!_}2RYv{|2s#hKX9tTWvIW#MiIksGt=#_s`~FAIWxzndAc3l?qc9Yh4ZaH zo)ewJ?Kl-9yRGhZdyf6?#0DwD>4=me)J(ce*bdAxhO@-aPZcsmTgwTVM{lPG)rig{bphvp z{PX+T`{|JBNgI*bmu$iSoNN;&YmWDUn`xlOu&jp7=3M{?b86T$v~12aP$vc@mOGWn z&xyPS_Sdv5fXG(LZcXVFxeh=6Y=^}2 z5_|o=gbF33K672(UsXEJ&TdeqS=|M7OMdtD{jYyMmor>aWz*T8pJ~vckJr%Vc|IiD zA3ax^rk|B7xlzyO?{aoHv=+fP+)Y2*ntHb)-f(BZ=le*GIjIJ0BVmpnNeR9^SlJp4 zPZot;Wx#5(?LK?G1rnxYovDPiEWy>H6kY9^@-6LRbt`*YOpGSy;M{g%Wi&0MK>byN&^yj$8{XvuT}S& zYlf8d*_JZ9Pq)6+3J3Nl6CGXm-apTs4nv+p&e-=<_`dI63uWg`T^~Pv{{4T@7(g!2 zhKynoWj6l#Y^SdG=c6{_Tp_E4f8Q9-LoE9?)6wUB0pIABv(d5D-`6Uo8e}3HYAJzK z4ck_SRS<1-XWD8R_bMA>FJQiq*q>_z7auNq+?utzS8>P#aF8a*!T`!yuTBCBCfqRE zCf&(~!}b17xV3C2U96NHw0g~!lgzAvs&!5V(cNu*zc)g1D-qH0_1JBQYE{2T5@=9J z_i48~C@H=TK&19h!IcgGf#|NvdEfVX>gTU;+$%cq|9q^(|NigDchuNFwz8Z86QGMx z)v~({!P?QS?1=dHD^{>ooro(Cf$m(#ExFr1XrwSP7}!kMWJKGBfIa|}=;n~5Mack( z^ygl+);&S3Wvs7-me*_2KGi@eQDkbNvPCEW5(%~nhQQTLpw-k^d(V-~Zks^6BWRJe zN3B(OW?Gv2qIK8IyXtAg=|J08OYu>}N9)*qU3S)bV$w&g>}{U%SK*fMDvhPREhdZRK#}i%sKu9svn*PU{3_(qx((Kp3Xh4NrrlET~{$)im_8 zi5jd~T(v9|#9c@i`&2cDIh-IY_ zoGJ7BO~8zVh9yZIU^LWHf9ojVKAn~&LS5_iZ=Zs-ZaXrf>W~@VWcK=mYJ)Pr{`a#M zi8o*O{R(^A0hy1nW{pw%aa*>ml&HS6XJSk>gSEWQ^cS`U|%&RF0tfb(Xm>srkMPGg&7i6cqmF-y)AeZ+ubscqa z|Ibd@RdlG4a$IF3nXGcdj%a<=3f2;y>ub{2{Ji(Ce_pTo`f6JHj{g6BK*~%5*2f_7 z+gR3KCfPMYqv>!UG8iUIs&`fMn+04$+PX0)dmr9?1VuuQPmzO)FhZ< zXM0WU1PQ{u31yoQ0FosaIT!AgM2F^_C*bY~QtHT4^Z9}!?F~s;5FCZ# ztg$#@C8YG$My=_2=fZvC^ZBE`p4Y^$Um;`ttMp$Vduw5Z`r@w}Xm?yu!3A>zEYA`< z5mLKOUnVx9JEM8FwQA1Cr@GbZ?sj%=+l5w}6rv?K+s-0ji$erW7P$x}L3`XZAtf_G z*g$f6kYcTx-UKZ#xZsOL-Wqely@b@cE(1dbMrh|i&bUCja1XLuIcyUe;Ji!GPda}; zti?V8d_-kuw{5lBvecQah?Gdw>WeEvYDNG4<(4xRTZj7>%u>(7ykv&TVxE6~fAon| z6@ITfP^f*cKI5*nUbV1l%sck@STJ8dwv}JcuoH-D56oI~uf3CMfidIW@%Mu1V+A3Mf2B65)U>d;{S=`_tcWD^VT;?=QrL(aLPRjrWjlE}i zfOmmwg-Kv=zfKrHpe=QT70;5}2^vs!?Aic8mZJj-c{CFhE`S&g{l^i%M}6H>y~@Q^*msXf zuvU@&==)<=6(A}y4o7in&mu`~ptH+tv(=h+w_E4)r==KoOQCE=_gQ~m-w}{niW7aL zD-B%Hy$ll4fEt#fnXl(_QBDm@L!Df;-2ZvI%K}Z-1B`Uf1+U3k5XzAz@4_G|bHOAP z#d3m$v}uVRf?&DzfCO_6c zKO{s&D#YYx86?Y7$kH_$GL+UKv(+bGc3kNSb+mW4w038I=ZVI;S~}rwrQVmkIbQ~3 zsMG3B_uhq~CBuzGnug^8S2Q5bbU7P)(4RZoX*<(ZW3$?O+ZI&CNvfrRbPGlo;o)?I z6w2ExY!r7jsJf*pIEWS4cXG{$$-(YayIB%4nb##iN`)ml)K>JRkoC-zw0;8C>7=^b zDadnU|MRyR;y!5I@OXY@q!iP*?Md{^{bgbd`)+(~AZhsH^?kbcY#0(3o*XSTG3VNO zhAijoOSZa=PK6dA&}zqb%UPLmSGV)Tbs`8EH0-ZxwXI|;P6VL9lG@!PZ7|Xf4K(5) zm8rBzr@O}(;Al4^q(X46Ivlu~|n?)Ge-JSi+^)rm*0MJrx1sW)mQo%}d zDZ52>+qsx&GvU6BT{mA(r<6ARI2C{`X-zqytd=`ID_d5F8?;ll1rKCPCqRHZzWYxf zQ_*2&r=*T5)J@KX-HVI91$}%)I1`a(i)*d2#7$rzm;cv_kbYiQ8)k&t(D_?Z3wn38 zW$c&Z*(bhFTUFR6R%YceFA&t>Z3MiuPNpT}?-?dgQwc}`~_6KGg5J0f*_efLXH=v?pU zMn>GHxql<8+#E&(sP1HQWyAYM6FLL-TFX*)i0n3DrE*{_lSSYjpS5bNL8!q@R4uT$ z9;mD))~dz4mq$U|EBYU-T^nrI6o#EBEbP!l-ib>@ja8pFS{72UoXAd|qgESPIO>Kp z+?Kl?{auw(&U70{(~5{IWrX4G=uBX~KmOt^=T@%4Muqa+uxrETq-`~ceHYU6>-LA` zRPME)%s8v|qLGtpabDswrlq(f%>Q(GUm>v0qUCS8-%{m?fI5TSA8+-d^tl@v1rEB+ zk$k?;AtXu%LTwZO2+|gH^QAUMj~eiM99uEIs>L7 z-W}NoFs?whx?%O>_xGE2zI@?CcNP_|U#G7|x>=F3)L45JS@V4Szn5U>-ptW8-aY;N2JH&!mJ4@LM8wqtk3bEGYDx-#osYI4$4%S?@ zU9zyN^xRxXY`NVAjbbLygsxVme*e20e?-$#wyqoJeC;_6Xh2TKyU*9(v^=Ft31uhk zY-cKL+l4i7|6OvZqmftV_n*6*Hhihroi;4@a7Z6ef<@ObjG3`^Qe?s1Hmjo0a6Q?b zjuJZ%PWS}$^Yn_?PMq$rI)dkHR+300Oc>qMY+Fqz!BjW0?Q~)|mFgTx>gP+xG;F{o z*;Z+IJw;RQEaWowyeH}n>*t=V2L{$dY~J^xCgDApA|CG_4Z14Yu*ay0bV(|#qP-?- zu>c8PY@epZ*)|#jwlZ1Oz4yEU0k)A+U(bt-7}{8?Z8KyPWk&i{HsPFjy|Q0DIDA0RzKxtOZEI1L%PvV$$CX4OEqN=Xs& zC8^Wxq$uE|n-`Eip#V#60Ia3NVj5jURgFb?6x#+N0I~p*xt{0i-me-JBT?LQuC+*7 zCXGpP4755uI0pd~xj6{isA-3bqLmd}qK(Phr>WF1*mCY?Z#NK~`u%rj;#)pz7t*l1 zkEN6CbaorVP?{Pr9IcjxVT5BHS;>x$%uDK%`an|D34e@H1}d{#xY?~RI1(!Uhvk#E z+HUhpy?i>=lO6dTS{U$Ojm;h+Q#Zrc1n@s@D zE6i+J?(Tz-WVKrWJR-2M@ljYN3zzHa&!_G|fKaBm*4Mc%eo|sj;Zn~uWLsBX-F9}| z@y^UpXE+rdnab2&tDF>OUul^Qbwf28c>!fX-EFs6iy8|=i_Xpj+*vZ5L=`t-*y+U~ z>`i!4^Vw@t<#%N&zdv_^wARKV=G@%i>OoorUE3}ic0qPpIqy!vfHRRMQ*A9}LTo{l zv#suCVVjxJ?%IeSKm?Nh(8z>gqoQRLS(P=;^Zmz=&>=gb&`5NrsRG=9-o>m-bo zAKR!WCbs$yHpnqI_TxNJR+~~TwUpUtols_XXgJSzcSPFRYK5dLvW;vwZ59mFsP}a> z5(z>LXm45Z8{ZCXq>V z%io{>fE{pO-hI8hQ(**J5fKXG!dRj1zT6RZbW7RtX?NRVMkV3prRbBkR#m+_H5TEP zelOl>Kr&j$Sx_r+&wXQ;vkRlr8@90uD9~S@N}5&0Lftcg;wTX6T4@rgrord_dR>?c zOwD7U0;L2An|Y&&OKMY=jELYeS5CnJsiy4m&m?nN0R?TqlB z_UCdq6+|PDc|$3=Tj99WY28;h)ZGfTu|Hvc*pX`GwMvSy*BX4y-L#Y0@#lT3$;fDT zJA%5@>PsDB5}j^S=*Y9GP7IQ*neH~_QwLGZuL{^iPm^-zKVfVW7TWfMeA zmX~u)dx4BIZxbNL>jns~MWXgxSTAM9q+=}y*4p5>6PtFTO~ceGY*uj5BQ4OFVb!I<{M8`FlPCAd`LtvBR^RL`?tDRSn ztZ0!R?FPoLftm_Bz2^ORxeZuZqmNq{ZHJa+T8iinhvK03icYrP5pVTIsB@E8jP6ug zl5P1vx7||Q%OIgFxdB-Bv|!J~%1odh*GiN>$*Ozadk&Bc1D-BBL9D%YEl}@;wX2F4 zlk@(%?*+^upa|nbB|?X zy`A02pASnSJEc%Tv46dWx=>eiUv?{z-AnrH;nBIB2I_KS{#g2my(X_+b^LBZ zy0PyZ#YJT5D8sJ3;53%4nkjW!PWLIIB6NGvw63L)yqw1wN(0@kf&-PqBPF@_rtOKb z05z#3Oj`)eM$xKula2ZU7WcgO#NncAkRt~iaIQ^)B(gBQU&Asv>UsUX3yUpey5`(t z?0jgXDPv%*0#NLf7mP$(W!%+a3qs~;24_RrVQ;*z(HK>^zqr1v+C3ejHD#t0aayfp zsQW_L;@4tFB|AOJc|zTk4M;UlOl7YDMkiQihb42>4Oo^e zuhpD$bD@e}wTfe)IBA&K1+@{OeHT( zt|7yK4I8JOAQW@U^tqo!U7!4dyq-)*J`s0OJ!_0POu<~@Mvz^9w z^|D`_)4eeVoMYT(xV)I)26pHV2v8RBu_7$1Y7RjEh}(n)NB08|o+Hz28P|BSOu#FsHR1MOQJ2*;96d=bF#F# z_8csuiZDbqfDM=blb?4Dgqe!*`gt(t{q^(3WwMgK*S(jE9)^h${{M?*rBvM#hIzj{ zIfzUdShgfyO&BCNK(p>uReJs=(JU_y@ZOO?tZ1#&Q%~mfJKxIuXl2D z4;oGE?V@EAS?lxOYfYPLuUW6xTs4s_WN0H zoT?=devLAL{?HA@^rc0nuf9U(y58rdwp!n19Q zt0S9>fYMfLx?>Et%pvc}tg*^qqUUfbX#>Mx60iDA_N!YnoX`M zR6Q_DG1p%A=l$XuqY@srhQ|WjwULq`nQ*4FtA;^$hMAG6us)vJ3!|wfuTk1^!s~jd=`@Tak5rY-X2@`Yx+# z{ZVtE6MU8yi*P&FoWHH;ua|(5Wny}afl&3s4l2$KH(Tfil!>{ci5k`_u8taT?cB0e zO530XwF)e%=AhKNZ=nzkmiW2GT6^!>eD?E&EPBk5NpK_KH-Q_kSFH`yJ@;+aO8by| z%T?=hV@{{3`u!TDoutTu)9HlUP=iJl1hqDYq!bca1Z{hR>wfKeDm`nKzq&2k9xzBT z!HyW91+eL^E{EbRbp{6LA~4`c4q9qd3(XN}?DEH};(kSYT!@&HpFKY59J#j^GaE?V zPg@xWHK*OMM}uextIoqZ0Riq~%2tXhjPs6Dhdt5xRU^pGqPNH36pk`rSA0M)3c zY!16nS@)jQ^UOu9v7cc8xdl-v zBNF}BU&MU&t7G5Bujk$klov)n@2DEnANBe|bzm)c)_S({RI7mXPj}Q$qcws5ucbcg znKfCOKCiU!2sgJo>h^`{>Ewc3Tm(q41PKKa0+F@*t=@aR(4rCZJkQ_%J0Laacj}TI z{14oz0oobMibbkstT&>O*<8;Q1jepcsU=q{1S$aavLb|z&sicB5fMEKNHRurLu@f4 zWEw+5Y$#UG`E|pw1&&7QxZl0@$V8V zDym4d^j_~T77_D0$#T2e>YaJ0`(i;YsHLc4&_xD@5;0@!dr}}{hykD|se2UyP-{{N zOJlHh3;V{3wNMf;=Hxwbbp&d~zqke>B1X@=RUNx6+pTCf{(i<>^ZgE?rC1Tw(QB`c zV4@YXtr&DKWc2K-R6{P}t&+OH5hk3h0ng(6h8TM#p4iJSjKw@eL6tuwgKHzBet&1a z+sSkYEa!{i`|kCz)?wy%v#L+pHpLXz2)goHRLYLt@Y z{P@p5ge~K~Om|7iI5w4!XB594AP2vHT%TB>P||o*QG*hwA3s70YiJODUY*`NI}i5P~KbU-6K#-JvdiXh2rkO z0D!d@7os~9sEUZ#cWeb>zpr(VfGG#Z{l~xiW3OkSzV0~|1&FP9c84Q?(E$N$z_HXb z#t4KVFd&6oQZ;Rp3!!`R6dIpj|9nn~mK2Q8!Vg?y2{T|*B1N;riild@%#-Jnmropl zY5Fu^YR!86@z1<$pPwfA2qio>PWs+}%b^Nk>I8&$Ye!r}bVTe9XOe6849-=ipeTXm zbdoYGW3@X3No(D2AQ0-tyr1_5 z)H9?|#EwQp%vD%WP^!4%>-+hy@AVcEJwjtQ#IL(L0AY6^B1j1}BvdbaJpnrkf<|o7 z1j%BiTT%~D!al$L*rBRa=<9v=`)B`_*EHqOWke-i%v9mP*`sV*B$qOIkhmC?yzZ{( z=dRbQj*!+PM&Cb-u~CRpN-`Au^}fk93)q@}d=IJW^lukfPH-%h%CJ=|fuvxS&`|01 zxuY=}H%Yy32qhEH($GY!%Ot6$pds#72^LgwukIdu&X5OZ$Ltx6mTFn==$_qL5Hb}& z1Vb^lqC*%m?ucH$n;lT-BtfaaJ^_12I1ZY23q{=4`yOp2vi}a^VXH|({sfr?XLzlo6ssT1wb-!mc zWhx-An0l|OqS@WiA%ze{h!D)Zdd3*N0)bl7SR+=nU=Wi%*4+_;R1j5&RkgN!cUI`i z_uRd{12^`-vjspQ^j@oNvBj$Ki~&Tqg{ozJ@70LxHrMDOTg1R<%*La(v) zeB<67M4`h;cM~U_B1z#cc!qlMdT}EYtI|&S*4y{PNJhn&Q5BW{(?{K9YN1#5s)s%l zI_L9_27t!&y)j?}sWMN3j3b`CPcTu29FWYUBs1@}5kVIW-eIpOkZYsA-j|{~C{suZ zG$z$e#e`TbDb{M#oJ(>A*byDo6Y5ZPbVoEIposSqz(l-9qYB7W$gb_Fop$A?175VAVyFF5m)dr?uInSMuh}XLInEv`;VCFkSgp_<|y(w zlPHm4?DO+m=qfoO zA_#gw3l*M`MOG*X0JE@^3dD7Ydys%if`kgGmoR^hh;c7kBWn*w7>@9)Frted4x50UB<@09!z$zflkZRRkL7Cjbl48Sr6dG_ zd=5;I@%wk<9+#;5Ud0s2uL>!kcqcyvON#r{C6c2E5m9{P_kVKLfAohjdxs*rX9UrEVvQKlAISnn4=Ixr{1T!H zno(@${&w|!p#<=fSU8TN3UK1=byAWMP+)b)+)=Pste6e0uN`ak?&zBDj1Dn6Iv|FI zYRoYqO?`EP+~0R20IZ@0_82orL?jw0b_j^n9q$OBhg7ROTAA-JL_ih&j8sul2m=9v zRP=jmt#YiPZ8lH+(Aa7GAoY4 zE^y6wmw+}<1XXO|>+J+8I*5yf{T0njkC9d+XH=2Y+R>V?L{I~stnaUi`;NYY5Xe$Q zECv)&VF0uoXaGhjdJe}#RY@qbdZq$%hoTV}fi;o6BLYzoqUpMW72nw~%4>~iThPMT z-?fo?ruR2&iDPt z*P0wZV*x@3!45D%(Hi#_NRnn<$3At8m2|xP z4CFw-B~dgY%V{j~rIHE@_jfYu*<|43e8}rdQlxw``A|dH{e73?y`!UNL`N(YVrfQq zb+{OiB7lU7lwcmrl#RPfY8kdO6ieNs05nE_-wK7YVzh*iqJhHhLDr59VK7=9l6wXK z&S#77h9a=jt9#$O6^%wk2Lu#JkPzOCQ5v|I-%rUOm3nvF;Qi(7RdSY$h^-NbZa@$U z2(C$~t^&uo&@l~=@s@=lFWB+c@i*qoviqc;?1|G*%C`w8@3!iTm?MOLbu`8vBq zSHuAQ{KK*rU{pC{>gxxYq+#-U1j$4MW9aHG;ya*VA})c94q-+NQ~+N=4JjlfzdGZd z9hS4eCQGLPdSIzR?*KreoG}QHvLi;Q(NGISA`~T{0%|B`H?iQNqPyK|p}Ow1?*-w# z0=-N{1SCozO2E^kN`NHT0AsJ#JzwXZv!i+l9V*1VI-oh2KVqT)te@{TLnJxz1=qdQ zE38Ho+GIVyi{<`CQ1fR*+6iB1p_4Bl;^VE5ooYy8EKLQ*;KibyAB8{=bgN?ldLyEt zf(#KN#pt^SSKNUcQIbP8K+>oc5z%DN5YW*py65EY?t85c>5iT~qah$-5Dw7G+OnBa zNeLVbaqbo9%KHXZK#HseVt2>M2G31I6%c(tq05WZSkK|lb0sy%0fLog?FK6ay`}m0 zf^J`0EJCb&-p5tY_mA#C$fV?$!Cf5)iDrp%he*yh`_j9ed7}Kb5X|>ORiplXtNwas z%(eO)$|oXfgyfzfJ)eN1)a4J*7ma$iR7DA4l!AMiN^nb#4N!$9qCy3hLV(tY`hMfx z*!N&Tnlk`K3-9l$(H+4UBt;4#VZRaUp6JmtB3ADZYN7`uqrh5?|M(}d06-!vkvJ;s zC`ND$sRYUSrknQq@)``S{hYKmqw@2fC}@`>U!<}un)8zK|k^R9&!Ku2sVUL1T^LzH%oCZ zN&wUYJ>WE0EJg^F8H$2xAyAfzg3Q%ok&GMFJy$_dDy(L%xt^iuNdR+1KoAhxv*z9n zt`O`3Dx&xP>KVPpUUMk0L*V;+p}eO6fVgk`Cx59X7NYkUqK;Qq6~5m@YBYkSNYi3( z#fqv10%1|<%VUXYJ0dtX=|a>d5r|BYTJOMNtHm>S5xr-Ou6t3HQ7k7VDjHcOR(b?s znlckl7K2qZlW8HP?IW z9nn4NzO{i0391UH5GeXRwFfAS7%0XX(X9T_6P&0V!7fCs9t}A*tsnpe`W_WPNk9}v3`JYex6#8T+lJ8qqxjg8+^= zY$5{HB`;84MQ@-3oh=n2Ua>5c=y6piuw-X57$_2>AS7 z?}eWip6^ku36vvZ2u9UCinaQDoPgpoSh5F(dX}ZTi;4k3Q6q~Ea^wruThIUQ1CPi0 zK1>yZ_Lz{Utwx|bVy!XP_x}C<`{`37D%cz7a3FrawIWD^B?xm3vgCEEp!eS`#A+y1 zg#nI1i&_;Lb3}}-n(OP0(E}m}#JPJVPys_2TR+xb@7OWeYt2Rv0W5P7)l@zA&&{Z% zvY;|!;d?74Pl7>uqI&?|YCIPp0UgCLpe2<>q&aOro_}{TZD#{BMm(jdl34_1ml0`b zVZSerp%9!Cd><8*!1EdSzU}1P0ajU0Vr^H^F?7g0XGZceseSwrKlnnW`9NT;yRXcg zC9Z!)7OQHTw?e6nxxeH4=U-oTEWDfub4{yiZ~aZvE*1s#2vs>vM6w%#8mcKose{7? ztO$ESLI?L;5Z^OI?WQGlAOtDQn6c-*@3jN=dyTG%0s?f{9HJ|JyeV=85>Zx6%~Gv! zDMep9w46Kc1-?fFqDF)&A}cT~l!PpxUca9=QIs;|ZmkUkj{}gBxDBWfGP=0K$${GB z`@sxT~ySi_qzcE6bjIJ=(6M%0+?&X#6-|P zcYxFfK|29o5kno=EvO;fYcyKuA*fKS0Ltu$s$yX@YGpDC4ZqZQ+83dUu~u`^itoiD z5Kxg+RTOIO8L$*1-Vt0823-|uh!m?-RU*GC>3*-j`5Du*6jb+;r0%W0^H>`tffuo+ zrsXuNP_ntIFoDZxHqPVk3cSA?G=J{Lx_33t*81C@0fMw#YA{L?Fl*Og9F3?j)up}P z9fF|iQesn7M+Fo`3Id=gor^?(ijpMtl$>a@s0sHV1AQwR)@THe98tv!5fN$*C{{NF z&iCETu^UlLFD?4JoA92rF|5bL?KL8emfm2f7EeR(F+JVC6kR-z`Q|u?8|BlnSMOnJ8>hm}?+< ztW}O?2^1-c`G|MB(6UAsmlPy4&~S)wG}gXtPDD#CL=?~24K1rp(h z-_PLpdJ!kW)CKetdBaw%S>xroFs~GPsfC!*V#HU+y+XQ>J*6mVa1OAg1B((xrz1BR}{re(^KDJFtqzI{kOcISZ{f^rAEL|o=#MS-y;S!Jg zkN=^1E3odrzn`s8^Efl^Z^Tzhd6}VbR@H2-TZ}nv*k8@ylv(DGLQGNui^NFc6%oMz zL{xNHtP*wrp|$56s%D@fB33}o805SIzA&%sc}Fa8#jent^6XjU#9AGp!GKS5_vkg6 zf`Y^rPlaOojOY<7&wGk!q3==^rSWc|LqO1QrjROy?>FePcIf>(uW}wTbFV0)bd}Ak zZL8?CjSY3gdhdOY{k)S&#l;{6{! zB~8!gKYC7&h#QVF+7|?6(y!ynKt;2EOhg2!@OuW_0kvzQLS#`90lJEqQ$wMplF8^U z03m*fDfJQrLd_DO9Y|S8%-+u&2IV&urEk>S#9QjG8RdSBE zh(LF*0SJ&en4deCld9*sZ_Jmg?tO9(<vH(L5uUD95h$106H%Go-!W-11k(hfN^}KKV#8KTMN|Z$kjXfi}w%^nMbC1uzxzh_r15^o zkX95N5fTa_O)5}Qm~v4Hu&CbT?)gqY00j@3$mnWX-IE0GZ$M%NcZ=OYsZ)Z(e1n?D4ggBzmCa zL<4>V^at|TX=jO~&w2c67IMd&lDZ%h`|p3=vkw^Gdz2{Pbs!fN_vb^K44R-&kfIDne@wP%F%sOoy@qn2jHK6peyLH3XU6EG^I#tO$uz_v=*N z`_oi~YHqBPVqi0ZK;sTTLlV!%$w5h#nT#bM)aVoW64U4%(Fg~YJX*<2>OTH%lFCeX z4M;a8E}Hw6QosLVLn`n3+Y@rA#Y4V%+EY z`}xPyG??;K1eQM6hqejCwMDGeR=ES}CgCc@nx?8^MASqWQ?uBkBp`aNWeNeJiiI*z z5u-;`pd~4^rUIi^s!+ueX8_RGGGpAW030gO9s|Idq@_vhd40rJ@?pxUqL*~;XE<2#vCXLW_Z#QfDkkXj-n(2SNraHur6>lavS5D>52~0XT&n#WNWm#6c6kITkqVD!go=zXDZy>dsYZ$S zWPH=BT{jFRB@zX#_u~5t>sPMu8BooAi21lKcAPK~4y_&!J4^4UW6&v$-+r{O-OKOC z=lEN7Y6(a0hcc}^%(e2p+8IziGC2Pjt}!&YkP>#p?75e1TWOKr-vWkeJujvb04SQJ zOsn9sgAA4w6Fpkq9WqdiS^)u04bkG&EkcgKQaKT51ZJ^LQI3EB4ajx{M`sWQOvb`% zpYLt)69PrN)nk^OlhuFUK_yeX6(Irp*&&Uy^nXd6_(ly7GLS_96Rwflv|hh{Ff$3eaA^ zA9XM3y?rox-v3y6B+JPVi3(shv!Hxfqd|(|_QBT9~{ zD;3@EXH}4lfPAHjX}J1Usj3PDndfY2DR zt4hjBLP6CrOkw3EN@lTv4h-HmqHlvtA1%0qP;v2VsFDb32THv1svyQFv1-)UQ(tv9 zp8pE*EM&fp<^-&wf3D75K2)8PHD6wb^dn`SeE26Ht`b})s%t`; zyD`+AR=oqGOI(58(?W!ZC|-W~D`_;{DCF*Efw&)IuIom~FE7 z>we0z6Q!*q{CfR<+jzXZmh^qSQpd;8IVVr#=kn)dⅇG2z4QOlVCd3O(2(~DoX(( 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 z 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

    PQGjS1!+j6F^i>Yw-+N3)nqB~ncvaYy? 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 literal 0 HcmV?d00001 diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index c371986567..24944110d2 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -30,14 +30,38 @@ h1 { font-family: $header_font; } +.jumbotron h1, +.jumbotron .h1, +.homepage-header { + color: white; + text-shadow: 0px 4px 3px rgba(0,0,0,0.4), + 0px 8px 13px rgba(0,0,0,0.1), + 0px 18px 23px rgba(0,0,0,0.1); +} + body { font-family: $body-font; + background: image-url("concrete_seamless.png"); } h5 { font-family: $small_header_font; } +.order-table { + // border: 2px solid blue; + background-color: white; + // margin: 10px; + padding-top: 5px; + padding-left: 10px; + border-radius: 10px 10px 10px 10px; + -moz-border-radius: 10px 10px 10px 10px; + -webkit-border-radius: 10px 10px 10px 10px; + border: 0px solid #000000; + -webkit-box-shadow: 0px 0px 5px 1px rgba(0,0,0,0.45); + -moz-box-shadow: 0px 0px 5px 1px rgba(0,0,0,0.45); + box-shadow: 0px 0px 5px 1px rgba(0,0,0,0.45); +} .jumbotron { position: relative; diff --git a/app/views/orders/index.html.erb b/app/views/orders/index.html.erb index ee6adaca1c..d9c113a80f 100644 --- a/app/views/orders/index.html.erb +++ b/app/views/orders/index.html.erb @@ -34,6 +34,7 @@ <% group.each do |order| %>

    diff --git a/app/views/welcome/index.html.erb b/app/views/welcome/index.html.erb index c1f5971c2b..b2c8493632 100644 --- a/app/views/welcome/index.html.erb +++ b/app/views/welcome/index.html.erb @@ -1,5 +1,5 @@
    -

    Wetsy Homepage

    +

    Splash into Savings

    Find the Best Products for Fun Water Times


    From 80e7b81daec00f83b3b65eb82d5402abf12ba25c Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 17 Dec 2015 21:28:42 -0800 Subject: [PATCH 258/299] update some styling --- app/assets/javascripts/application.js | 1 - app/assets/stylesheets/application.scss | 10 ++++++++++ app/views/shared/_products.html.erb | 1 - 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 3800211fb3..ea3f4a9466 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -19,7 +19,6 @@ var resize_thumbs = function(){ var thumb = document.getElementsByClassName('thumbnail')[0]; var width = thumb.clientWidth; - console.log(width); $('.img-container').css({ "height": width+"px" }); }; diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 24944110d2..fc63352053 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -95,6 +95,9 @@ h5 { .thumbnail img { width: 100%; margin: auto; + border-radius: 10px 10px 10px 10px; + -moz-border-radius: 10px 10px 10px 10px; + -webkit-border-radius: 10px 10px 10px 10px; } .img-container { @@ -116,6 +119,13 @@ h5 { .thumbnail { padding: 0; + border-radius: 10px 10px 10px 10px; + -moz-border-radius: 10px 10px 10px 10px; + -webkit-border-radius: 10px 10px 10px 10px; + border: 0px solid #000000; + -webkit-box-shadow: 0px 0px 5px 1px rgba(0,0,0,0.45); + -moz-box-shadow: 0px 0px 5px 1px rgba(0,0,0,0.45); + box-shadow: 0px 0px 5px 1px rgba(0,0,0,0.45); } .caption { diff --git a/app/views/shared/_products.html.erb b/app/views/shared/_products.html.erb index df58aa258d..fd0b1560a7 100644 --- a/app/views/shared/_products.html.erb +++ b/app/views/shared/_products.html.erb @@ -18,7 +18,6 @@
    <% end %>

    -

    <%= product.stock %> Available

    <%= link_to "Edit item", edit_user_product_path(product.user.id, product.id) %>

    From 6849afd1742150eeda9b7566cbd60fa5ddef473d Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 17 Dec 2015 21:31:46 -0800 Subject: [PATCH 259/299] style login page --- app/assets/stylesheets/application.scss | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index fc63352053..9c4942db92 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -49,9 +49,7 @@ h5 { } .order-table { - // border: 2px solid blue; background-color: white; - // margin: 10px; padding-top: 5px; padding-left: 10px; border-radius: 10px 10px 10px 10px; @@ -158,6 +156,14 @@ h5 { max-width: 330px; padding: 15px; margin: 0 auto; + background-color: white; + border-radius: 10px 10px 10px 10px; + -moz-border-radius: 10px 10px 10px 10px; + -webkit-border-radius: 10px 10px 10px 10px; + border: 0px solid #000000; + -webkit-box-shadow: 0px 0px 5px 1px rgba(0,0,0,0.45); + -moz-box-shadow: 0px 0px 5px 1px rgba(0,0,0,0.45); + box-shadow: 0px 0px 5px 1px rgba(0,0,0,0.45); } .btn-block { From 5e74629f2931db774e57dc468721f040b5bf1532 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 17 Dec 2015 21:40:33 -0800 Subject: [PATCH 260/299] style new user form --- app/assets/stylesheets/application.scss | 18 +++++-- app/views/sessions/new.html.erb | 2 +- app/views/users/_form.html.erb | 72 ++++++++++++------------- app/views/users/new.html.erb | 11 +++- 4 files changed, 57 insertions(+), 46 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 9c4942db92..d84ce1ff30 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -151,11 +151,11 @@ h5 { font-size: 28px; } -// Login Page -.form-signin { - max-width: 330px; - padding: 15px; - margin: 0 auto; +.add-padding { + padding: 10px; +} + +.box-with-shadow { background-color: white; border-radius: 10px 10px 10px 10px; -moz-border-radius: 10px 10px 10px 10px; @@ -166,6 +166,14 @@ h5 { box-shadow: 0px 0px 5px 1px rgba(0,0,0,0.45); } +// Login Page +.form-signin { + max-width: 330px; + padding: 15px; + margin: 0 auto; + +} + .btn-block { display: block; width: 100%; diff --git a/app/views/sessions/new.html.erb b/app/views/sessions/new.html.erb index 6c86ea6fb1..7252c8262d 100644 --- a/app/views/sessions/new.html.erb +++ b/app/views/sessions/new.html.erb @@ -1,4 +1,4 @@ -<%= form_for(:session_data, url: login_path, :html => {:class => "form-signin"}) do |f| %> +<%= form_for(:session_data, url: login_path, :html => {:class => "form-signin box-with-shadow"}) do |f| %> <% if !flash.now[:danger].nil? %>

    <%= flash.now[:danger] %>

    <% end %> diff --git a/app/views/users/_form.html.erb b/app/views/users/_form.html.erb index 3b81581576..ca6d25ee4e 100644 --- a/app/views/users/_form.html.erb +++ b/app/views/users/_form.html.erb @@ -1,41 +1,37 @@ -
    -
    - <%= form_for(@user, class: "form-group") do |f| %> - <% if @user.errors.any? %> -
    -

    <%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:

    +<%= form_for(@user, class: "form-group") do |f| %> + <% if @user.errors.any? %> +
    +

    <%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:

    -
      - <% @user.errors.full_messages.each do |message| %> -
    • <%= message %>
    • - <% end %> -
    -
    +
      + <% @user.errors.full_messages.each do |message| %> +
    • <%= message %>
    • <% end %> -
      - <%= f.label :name %>
      - <%= f.text_field :name, class: 'form-control' %> -
      -
      - <%= f.label :username %>
      - <%= f.text_field :username, class: 'form-control', :required => true %> -
      -
      - <%= f.label :email %>
      - <%= f.email_field :email, class: 'form-control', :required => true %> -
      -
      - <%= f.label :password %>
      - <%= f.password_field :password, class: 'form-control', :required => true %> -
      -
      - <%= f.label :password_confirmation %>
      - <%= f.password_field :password_confirmation, class: 'form-control', :required => true %> -
      -
      -
      - <%= f.submit value: "#{submit_text}", class: "btn btn-primary" %> -
      - <% end %> +
    +
    + <% end %> +
    + <%= f.label :name %>
    + <%= f.text_field :name, class: 'form-control' %>
    -
    +
    + <%= f.label :username %>
    + <%= f.text_field :username, class: 'form-control', :required => true %> +
    +
    + <%= f.label :email %>
    + <%= f.email_field :email, class: 'form-control', :required => true %> +
    +
    + <%= f.label :password %>
    + <%= f.password_field :password, class: 'form-control', :required => true %> +
    +
    + <%= f.label :password_confirmation %>
    + <%= f.password_field :password_confirmation, class: 'form-control', :required => true %> +
    +
    +
    + <%= f.submit value: "#{submit_text}", class: "btn btn-primary" %> +
    +<% end %> diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb index ba431a12b1..82c384e2a1 100644 --- a/app/views/users/new.html.erb +++ b/app/views/users/new.html.erb @@ -1,2 +1,9 @@ -

    New User

    -<%= render partial: 'form', locals: {submit_text: "Create My Account"} %> +
    +
    +
    +

    New User

    +
    + <%= render partial: 'form', locals: {submit_text: "Create My Account"} %> +
    +
    +
    From 6d5fc5592f627eb637352278155ce1aa183e54c4 Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Thu, 17 Dec 2015 21:52:34 -0800 Subject: [PATCH 261/299] hover effect on jumbotron --- app/assets/stylesheets/application.scss | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index d84ce1ff30..873d64d7d0 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -39,6 +39,24 @@ h1 { 0px 18px 23px rgba(0,0,0,0.1); } +.jumbotron:hover { + -webkit-filter: brightness(90%); + -webkit-transition: all 0.5s ease; + -moz-transition: all 0.5s ease; + -o-transition: all 0.5s ease; + -ms-transition: all 0.5s ease; + transition: all 0.5s ease; +} + +.jumbotron { + -webkit-transition: all 0.5s ease; + -moz-transition: all 0.5s ease; + -o-transition: all 0.5s ease; + -ms-transition: all 0.5s ease; + transition: all 0.5s ease; +} + + body { font-family: $body-font; background: image-url("concrete_seamless.png"); From 9887f0856d515da2c16976d1bb389573e59594bb Mon Sep 17 00:00:00 2001 From: Jennie Buechner Date: Fri, 18 Dec 2015 08:52:41 -0800 Subject: [PATCH 262/299] create scrolling transparent navbar --- app/assets/javascripts/application.js | 16 ++++++++++++++++ app/assets/stylesheets/application.scss | 15 ++++++++++++++- app/views/layouts/application.html.erb | 6 ++++-- app/views/shared/_navbar.html.erb | 2 +- 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index ea3f4a9466..dc69c68dc8 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -25,3 +25,19 @@ var resize_thumbs = function(){ $(document).ready(resize_thumbs); $(window).resize(resize_thumbs); $(document).on('page:change', resize_thumbs); + +/** + * Listen to scroll to change header opacity class + */ +function checkScroll(){ + var startY = $('.navbar').height(); //The point where the navbar changes in px + if($(window).scrollTop() > startY){ + $('.navbar').addClass("scrolled"); + }else{ + $('.navbar').removeClass("scrolled"); + } +} + +$(window).on("scroll load resize", function(){ + checkScroll(); + }); diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 873d64d7d0..43d9156ba4 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -93,7 +93,20 @@ h5 { border: 0px solid transparent; border-radius: 0px; border-bottom: 1px solid #e7e7e7; - // border-color: rgba(248, 248, 248, 0); + -webkit-transition: all 0.6s ease-out; + -moz-transition: all 0.6s ease-out; + -o-transition: all 0.6s ease-out; + -ms-transition: all 0.6s ease-out; + transition: all 0.6s ease-out; +} + +.navbar.scrolled { + background: rgb(255, 255, 255); //IE + background: rgba(248, 248, 248, 0.95); //NON-IE +} + +.top-margin { + margin-top: 50px; } .navbar-default { diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index fb188d741d..cb6d6d7727 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -9,8 +9,10 @@
    <%= render 'shared/navbar' %> - <%= render partial: "shared/flash_messages", flash: flash %> - <%= yield %> +
    + <%= render partial: "shared/flash_messages", flash: flash %> + <%= yield %> +
    diff --git a/app/views/shared/_navbar.html.erb b/app/views/shared/_navbar.html.erb index 7bdab46e2a..e79bb9f2dd 100644 --- a/app/views/shared/_navbar.html.erb +++ b/app/views/shared/_navbar.html.erb @@ -1,4 +1,4 @@ -