diff --git a/Gemfile b/Gemfile index b460be7..94ca855 100644 --- a/Gemfile +++ b/Gemfile @@ -34,7 +34,7 @@ gem "jbuilder" # gem "kredis" # Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword] -# gem "bcrypt", "~> 3.1.7" +gem "bcrypt", "~> 3.1.7" # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] @@ -42,8 +42,13 @@ gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] # Reduces boot times through caching; required in config/boot.rb gem "bootsnap", require: false +gem 'pry-rails' +gem 'cancancan' +gem 'bootstrap', '~> 5.1.3' +gem 'jquery-rails' + # Use Sass to process CSS -# gem "sassc-rails" +gem "sassc-rails" # Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] # gem "image_processing", "~> 1.2" @@ -51,6 +56,7 @@ gem "bootsnap", require: false group :development, :test do # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem gem "debug", platforms: %i[ mri mingw x64_mingw ] + gem 'faker' end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index b6c2b90..a0e6807 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -66,10 +66,19 @@ GEM i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) + autoprefixer-rails (10.4.2.0) + execjs (~> 2) + bcrypt (3.1.17) bindex (0.8.1) bootsnap (1.11.1) msgpack (~> 1.2) + bootstrap (5.1.3) + autoprefixer-rails (>= 9.1.0) + popper_js (>= 2.9.3, < 3) + sassc-rails (>= 2.0.0) builder (3.2.4) + cancancan (3.3.0) + coderay (1.1.3) concurrent-ruby (1.1.10) crass (1.0.6) debug (1.4.0) @@ -77,6 +86,10 @@ GEM reline (>= 0.2.7) digest (3.1.0) erubi (1.10.0) + execjs (2.8.1) + faker (2.20.0) + i18n (>= 1.8.11, < 2) + ffi (1.15.5) globalid (1.0.0) activesupport (>= 5.0) i18n (1.10.0) @@ -91,6 +104,10 @@ GEM jbuilder (2.11.5) actionview (>= 5.0.0) activesupport (>= 5.0.0) + jquery-rails (4.4.0) + rails-dom-testing (>= 1, < 3) + railties (>= 4.2.0) + thor (>= 0.14, < 2.0) loofah (2.15.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) @@ -120,6 +137,12 @@ GEM nokogiri (1.13.3-x86_64-linux) racc (~> 1.4) pg (1.3.4) + popper_js (2.9.3) + pry (0.14.1) + coderay (~> 1.1) + method_source (~> 1.0) + pry-rails (0.3.9) + pry (>= 0.10.4) puma (5.6.2) nio4r (~> 2.0) racc (1.6.0) @@ -155,6 +178,14 @@ GEM rake (13.0.6) reline (0.3.1) io-console (~> 0.5) + sassc (2.4.0) + ffi (~> 1.9) + sassc-rails (2.1.2) + railties (>= 4.0.0) + sassc (>= 2.0) + sprockets (> 3.0) + sprockets-rails + tilt sprockets (4.0.3) concurrent-ruby (~> 1.0) rack (> 1, < 3) @@ -166,6 +197,7 @@ GEM railties (>= 6.0.0) strscan (3.0.1) thor (1.2.1) + tilt (2.0.10) timeout (0.2.0) turbo-rails (1.0.1) actionpack (>= 6.0.0) @@ -186,13 +218,20 @@ PLATFORMS x86_64-linux DEPENDENCIES + bcrypt (~> 3.1.7) bootsnap + bootstrap (~> 5.1.3) + cancancan debug + faker importmap-rails jbuilder + jquery-rails pg (~> 1.1) + pry-rails puma (~> 5.0) rails (~> 7.0.2, >= 7.0.2.3) + sassc-rails sprockets-rails stimulus-rails turbo-rails diff --git a/README.md b/README.md deleted file mode 100644 index 7db80e4..0000000 --- a/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# README - -This README would normally document whatever steps are necessary to get the -application up and running. - -Things you may want to cover: - -* Ruby version - -* System dependencies - -* Configuration - -* Database creation - -* Database initialization - -* How to run the test suite - -* Services (job queues, cache servers, search engines, etc.) - -* Deployment instructions - -* ... diff --git a/app/assets/images/idea.png b/app/assets/images/idea.png new file mode 100644 index 0000000..1a1147a Binary files /dev/null and b/app/assets/images/idea.png differ diff --git a/app/assets/images/.keep b/app/assets/stylesheets/ideas.scss similarity index 100% rename from app/assets/images/.keep rename to app/assets/stylesheets/ideas.scss diff --git a/app/assets/stylesheets/likes.scss b/app/assets/stylesheets/likes.scss new file mode 100644 index 0000000..e69de29 diff --git a/app/assets/stylesheets/reviews.scss b/app/assets/stylesheets/reviews.scss new file mode 100644 index 0000000..e69de29 diff --git a/app/assets/stylesheets/sessions.scss b/app/assets/stylesheets/sessions.scss new file mode 100644 index 0000000..e69de29 diff --git a/app/assets/stylesheets/users.scss b/app/assets/stylesheets/users.scss new file mode 100644 index 0000000..e69de29 diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 09705d1..1450813 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,2 +1,20 @@ class ApplicationController < ActionController::Base -end + + private + + def current_user + current_user ||= User.find_by_id session[:user_id] # ||= will only assign @current_user if it is nil. Otherwise continue using it's + end + helper_method :current_user + + def user_signed_in? + current_user.present? + end + helper_method :user_signed_in? + + def authenticate_user! + redirect_to new_session_path, {alert: "You need to be signed in first!", status: 303} unless user_signed_in? + end + helper_method :authenticate_user! + +end \ No newline at end of file diff --git a/app/controllers/ideas_controller.rb b/app/controllers/ideas_controller.rb new file mode 100644 index 0000000..5970f76 --- /dev/null +++ b/app/controllers/ideas_controller.rb @@ -0,0 +1,61 @@ +class IdeasController < ApplicationController + before_action :authenticate_user!, except: [:index, :show] + before_action :get_idea!, only: [:show, :edit, :update, :destroy] + before_action :authorize!, only: [:edit, :update, :destroy] + + def new + @idea = Idea.new + end + + def create + @idea = Idea.new idea_params + @idea.user = current_user + if @idea.save + redirect_to ideas_path(@idea), { status: 303, notice: 'Idea created' } + else + flash.alert = @idea.errors.full_messages.join(', ') + render :new, status: 303 + end + end + + def index + @ideas = Idea.all.order('updated_at DESC') + end + + def show + @review = Review.new + @reviews = @idea.reviews.order(created_at: :desc) + @like = @idea.likes.find_by(user: current_user) + end + + def edit + + end + + def update + id = params[:id] + @idea = Idea.find(id) + if @idea.update(params.require(:idea).permit(:title, :description)) + redirect_to idea_path(@idea), status: 303 + else + render :edit, status: 303 + end + end + + def destroy + id = params[:id] + @idea = Idea.find(id) + @idea.destroy + redirect_to ideas_path, status: 303 + end + + private + + def get_idea! + @idea = Idea.find(params[:id]) + end + + def authorize! + redirect_to root_path, status: 303, alert: 'Not Authorized' unless can?(:crud, @idea) + end + end \ No newline at end of file diff --git a/app/controllers/likes_controller.rb b/app/controllers/likes_controller.rb new file mode 100644 index 0000000..a942ee7 --- /dev/null +++ b/app/controllers/likes_controller.rb @@ -0,0 +1,29 @@ +class LikesController < ApplicationController + before_action :authenticate_user!, only: [:create, :destroy] + + def create + idea = Idea.find params[:idea_id] + like = Like.new( user: current_user, idea: idea ) + + if can?(:like, idea) + if like.save + redirect_to idea_path(idea), { notice: "Idea Liked", status: 303 } + else + redirect_to root_path, { alert: like.errors.full_messages.join(", "), status: 303 } + end + else + redirect_to root_path, { alert: "You can't like your own idea....", status: 303 } + end + end + + def destroy + like = Like.find params[:id] + + if can?(:destroy, like) + like.destroy + redirect_to root_path, { notice: "Idea unliked", status: 303 } + else + redirect_to root_path, {alert: "You can't unlike because not authorized!", status: 303 } + end + end +end \ No newline at end of file diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb new file mode 100644 index 0000000..ec28f72 --- /dev/null +++ b/app/controllers/reviews_controller.rb @@ -0,0 +1,31 @@ +class ReviewsController < ApplicationController + + def create + @idea = Idea.find(params[:idea_id]) + @review = Review.new review_params + @review.idea = @idea + @review.user = current_user + if @review.save + redirect_to idea_path(@idea) + else + @reviews = @idea.reviews.order(created_at: :desc) + render 'ideas/show', status: 303 + end + end + + def destroy + @review = Review.find params[:id] + if can?(:crud, @review) + @review.destroy + redirect_to idea_path(@review.idea), status: 303 + else + head :unauthorized + end + end + + private + + def review_params + params.require(:review).permit(:body) + end +end \ No newline at end of file diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb new file mode 100644 index 0000000..afe2549 --- /dev/null +++ b/app/controllers/sessions_controller.rb @@ -0,0 +1,22 @@ +class SessionsController < ApplicationController + def new + end + + def create + user = User.find_by_email params[:email] + + if user&.authenticate params[:password] + session[:user_id] = user.id + flash[:success] = "User Logged In" + redirect_to ideas_path, status: 303 + else + flash[:warning] = "Couldn't Log In, Please Try Again" + render :new, status: 303 + end + end + + def destroy + session[:user_id] = nil + redirect_to ideas_path, status: 303 + end +end \ No newline at end of file diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 0000000..73f4347 --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,16 @@ +class UsersController < ApplicationController + def new + @user = User.new + end + + def create + @user = User.new params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation) + if @user.save + flash.delete(:warning) + redirect_to ideas_path, status: 303 + else + flash[:warning] = "Unable to Create User" + render :new, status: 303 + end + end +end \ No newline at end of file diff --git a/app/helpers/ideas_helper.rb b/app/helpers/ideas_helper.rb new file mode 100644 index 0000000..0a60b4e --- /dev/null +++ b/app/helpers/ideas_helper.rb @@ -0,0 +1,2 @@ +module IdeasHelper +end diff --git a/app/helpers/likes_helper.rb b/app/helpers/likes_helper.rb new file mode 100644 index 0000000..a78a759 --- /dev/null +++ b/app/helpers/likes_helper.rb @@ -0,0 +1,2 @@ +module LikesHelper +end diff --git a/app/helpers/reviews_helper.rb b/app/helpers/reviews_helper.rb new file mode 100644 index 0000000..682b7b1 --- /dev/null +++ b/app/helpers/reviews_helper.rb @@ -0,0 +1,2 @@ +module ReviewsHelper +end diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb new file mode 100644 index 0000000..309f8b2 --- /dev/null +++ b/app/helpers/sessions_helper.rb @@ -0,0 +1,2 @@ +module SessionsHelper +end diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb new file mode 100644 index 0000000..2310a24 --- /dev/null +++ b/app/helpers/users_helper.rb @@ -0,0 +1,2 @@ +module UsersHelper +end diff --git a/app/models/ability.rb b/app/models/ability.rb new file mode 100644 index 0000000..3174ebc --- /dev/null +++ b/app/models/ability.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +class Ability + include CanCan::Ability + + def initialize(user) + + user ||= User.new + + alias_action :create, :read, :update, :destroy, to: :crud + + can :crud, Idea do |idea| + idea.user == user + end + + can :crud, Review do |review| + review.user == user + end + + can :like, Idea do |idea| + user.present? && idea.user != user + end + + can :destroy, Like do |like| + like.user == user + end + end +end \ No newline at end of file diff --git a/app/models/idea.rb b/app/models/idea.rb new file mode 100644 index 0000000..24d8349 --- /dev/null +++ b/app/models/idea.rb @@ -0,0 +1,12 @@ +class Idea < ApplicationRecord + has_many :reviews, dependent: :destroy + + has_many :likes, dependent: :destroy + has_many :likers, through: :likes, source: :user + belongs_to :user + + validates :title, presence: true + validates :description, presence: true + + +end \ No newline at end of file diff --git a/app/models/like.rb b/app/models/like.rb new file mode 100644 index 0000000..3c411aa --- /dev/null +++ b/app/models/like.rb @@ -0,0 +1,4 @@ +class Like < ApplicationRecord + belongs_to :user + belongs_to :idea +end \ No newline at end of file diff --git a/app/models/review.rb b/app/models/review.rb new file mode 100644 index 0000000..271ab68 --- /dev/null +++ b/app/models/review.rb @@ -0,0 +1,7 @@ +class Review < ApplicationRecord + belongs_to :idea + belongs_to :user + + validates :body, presence: true + validates :rating, {numericality: { greater_than_or_equal_to: 1, less_than_or_equal_to: 5 }} +end \ No newline at end of file diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..373763b --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,10 @@ +class User < ApplicationRecord + has_secure_password + has_many :ideas + has_many :reviews + + has_many :likes, dependent: :destroy + has_many :liked_ideas, through: :likes, source: :idea + + validates :email, presence: true, uniqueness: true, format: /\A([\w+\-].?)+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i +end \ No newline at end of file diff --git a/app/views/ideas/_form.html.erb b/app/views/ideas/_form.html.erb new file mode 100644 index 0000000..a747978 --- /dev/null +++ b/app/views/ideas/_form.html.erb @@ -0,0 +1,20 @@ +<% if @idea.errors.any? %> + +<% end%> + + +<%= form_for @idea do |f|%> +
+ <%= f.label :title %> + <%= f.text_field :title,class:'form-control'%> +
+
+ <%= f.label :description %> + <%= f.text_area :description,class:'form-control'%> +
+<%= f.submit :submit, class:"btn btn-primary" %> +<% end%> \ No newline at end of file diff --git a/app/views/ideas/edit.html.erb b/app/views/ideas/edit.html.erb new file mode 100644 index 0000000..4a207d9 --- /dev/null +++ b/app/views/ideas/edit.html.erb @@ -0,0 +1,2 @@ +

Create Your Idea

+<%= render "form"%> \ No newline at end of file diff --git a/app/views/ideas/index.html.erb b/app/views/ideas/index.html.erb new file mode 100644 index 0000000..c8a173b --- /dev/null +++ b/app/views/ideas/index.html.erb @@ -0,0 +1,28 @@ +<% @ideas.each do |idea| %> +
+

<%= link_to idea.title, idea_path(idea) %>

+

<%= idea.description %>

+
+ By <%= idea.user&.first_name %> + <% @like = idea.likes.find_by(user: current_user)%> + <% if @like.present? && can?(:destroy, @like) %> + <%= link_to( + "Unlike", + like_path(@like), + class:"btn btn-danger ", + method: :delete + ) %> + <% else can?(:like, idea) %> + <%= link_to( + "Like", + idea_likes_path(idea), + class:"btn btn-success ", + method: :post + ) %> + <% end %>| + + (<%= pluralize(idea.likes.count, "like") %>) + +
+
+<% end %> \ No newline at end of file diff --git a/app/views/ideas/new.html.erb b/app/views/ideas/new.html.erb new file mode 100644 index 0000000..4a207d9 --- /dev/null +++ b/app/views/ideas/new.html.erb @@ -0,0 +1,2 @@ +

Create Your Idea

+<%= render "form"%> \ No newline at end of file diff --git a/app/views/ideas/show.html.erb b/app/views/ideas/show.html.erb new file mode 100644 index 0000000..7058eb4 --- /dev/null +++ b/app/views/ideas/show.html.erb @@ -0,0 +1,64 @@ +

<%= @idea.title %>

+

<%= @idea.description %>

+ +<% if can?(:crud, @idea)%> +<%= link_to "Edit", edit_idea_path(@idea), class:"btn btn-warning " %> +<%= link_to "Delete", idea_path(@idea), class:"btn btn-danger ", method: :delete, data: {confirm: "Are you sure?"} %> +<% end %> +
+<%= form_with(model: [@idea, @review], local: true) do |f| %> +<% if @review.errors.any? %> + +<% end %> + +
+ + <%= f.text_area( + :body, + cols: 50, + rows: 5, + placeholder: "What are your review?", + class: "form-control" + ) %> +
+<%= f.submit "Review", class:"btn btn-primary" %> +<% end %> + +
+ + \ No newline at end of file diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 2a554b5..f77e0a9 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -1,6 +1,10 @@ +
+ <%= image_tag("idea.png", width:"100",class:"image ml-4")%> +
+ IdeaFactory <%= csrf_meta_tags %> @@ -10,7 +14,38 @@ <%= javascript_importmap_tags %> - + + <% flash.each do |type, message|%> +
+ <%= message%> +
+ <% end%> +
+
Idea Factory
+ +
+ + +
+ <%= yield %> - + \ No newline at end of file diff --git a/app/views/sessions/new.html.erb b/app/views/sessions/new.html.erb new file mode 100644 index 0000000..798d35e --- /dev/null +++ b/app/views/sessions/new.html.erb @@ -0,0 +1,15 @@ +

+ Sign In +

+ +<%= form_with url: session_path, local: true do |f|%> +
+ <%= f.label :email %> + <%= f.email_field :email,class:'form-control'%> +
+
+ <%= f.label :password %> + <%= f.password_field :password,class:'form-control'%> +
+<%= f.submit "Sign In", class:"btn btn-primary" %> +<% end%> \ No newline at end of file diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb new file mode 100644 index 0000000..52450bf --- /dev/null +++ b/app/views/users/new.html.erb @@ -0,0 +1,24 @@ +

Sing Up

+<%= form_with model: @user, local: true do |f|%> +
+ <%= f.label :first_name %> + <%= f.text_field :first_name,class:'form-control'%> +
+
+ <%= f.label :last_name %> + <%= f.text_field :last_name,class:'form-control'%> +
+
+ <%= f.label :email %> + <%= f.email_field :email,class:'form-control'%> +
+
+ <%= f.label :password %> + <%= f.password_field :password,class:'form-control'%> +
+
+ <%= f.label :password_confirmation %> + <%= f.password_field :password_confirmation,class:'form-control'%> +
+<%= f.submit :submit, class:"btn btn-primary" %> +<% end%> \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 262ffd5..774adae 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,11 @@ Rails.application.routes.draw do - # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html + + root 'ideas#index' + resources :ideas, except: [:index] do + resources :likes, shallow: true, only: [:create, :destroy] + resources :reviews, only: [:create, :destroy] + end - # Defines the root path route ("/") - # root "articles#index" -end + resources :users, only: [:new, :create, :edit, :update] + resource :session, only: [:new, :create, :destroy] +end \ No newline at end of file diff --git a/db/migrate/20220323185500_create_users.rb b/db/migrate/20220323185500_create_users.rb new file mode 100644 index 0000000..6352519 --- /dev/null +++ b/db/migrate/20220323185500_create_users.rb @@ -0,0 +1,12 @@ +class CreateUsers < ActiveRecord::Migration[6.0] + def change + create_table :users do |t| + t.string :first_name + t.string :last_name + t.string :email, index: {unique: true} + t.string :password_digest + + t.timestamps + end + end +end \ No newline at end of file diff --git a/db/migrate/20220323185506_create_ideas.rb b/db/migrate/20220323185506_create_ideas.rb new file mode 100644 index 0000000..83f64b2 --- /dev/null +++ b/db/migrate/20220323185506_create_ideas.rb @@ -0,0 +1,10 @@ +class CreateIdeas < ActiveRecord::Migration[6.0] + def change + create_table :ideas do |t| + t.string :title + t.text :description + + t.timestamps + end + end +end \ No newline at end of file diff --git a/db/migrate/20220323213652_create_likes.rb b/db/migrate/20220323213652_create_likes.rb new file mode 100644 index 0000000..a0d94c3 --- /dev/null +++ b/db/migrate/20220323213652_create_likes.rb @@ -0,0 +1,10 @@ +class CreateLikes < ActiveRecord::Migration[6.0] + def change + create_table :likes do |t| + t.references :user, foreign_key: true + t.references :idea, foreign_key: true + + t.timestamps + end + end +end \ No newline at end of file diff --git a/db/migrate/20220323214639_create_reviews.rb b/db/migrate/20220323214639_create_reviews.rb new file mode 100644 index 0000000..5ff4d93 --- /dev/null +++ b/db/migrate/20220323214639_create_reviews.rb @@ -0,0 +1,11 @@ +class CreateReviews < ActiveRecord::Migration[6.0] + def change + create_table :reviews do |t| + t.text :body + t.references :idea, foreign_key: true + t.references :user, foreign_key: true + + t.timestamps + end + end +end \ No newline at end of file diff --git a/db/migrate/20220324040612_add_user_to_ideas.rb b/db/migrate/20220324040612_add_user_to_ideas.rb new file mode 100644 index 0000000..ae6a146 --- /dev/null +++ b/db/migrate/20220324040612_add_user_to_ideas.rb @@ -0,0 +1,6 @@ +class AddUserToIdeas < ActiveRecord::Migration[7.0] + def change + + add_reference :ideas, :user, null: false, foreign_key: true + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..6fbac18 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,60 @@ +# 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. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_03_24_040612) do + # These are extensions that must be enabled in order to support this database + enable_extension "plpgsql" + + create_table "ideas", force: :cascade do |t| + t.string "title" + t.text "description" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.bigint "user_id", null: false + t.index ["user_id"], name: "index_ideas_on_user_id" + end + + create_table "likes", force: :cascade do |t| + t.integer "user_id" + t.integer "idea_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["idea_id"], name: "index_likes_on_idea_id" + t.index ["user_id"], name: "index_likes_on_user_id" + end + + create_table "reviews", force: :cascade do |t| + t.text "body" + t.integer "idea_id" + t.integer "user_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["idea_id"], name: "index_reviews_on_idea_id" + t.index ["user_id"], name: "index_reviews_on_user_id" + end + + create_table "users", force: :cascade do |t| + t.string "first_name" + t.string "last_name" + t.string "email" + t.string "password_digest" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["email"], name: "index_users_on_email", unique: true + end + + add_foreign_key "ideas", "users" + add_foreign_key "likes", "ideas" + add_foreign_key "likes", "users" + add_foreign_key "reviews", "ideas" + add_foreign_key "reviews", "users" +end