Commit 3a70729
Changed files (20)
app
db
spec
app/controllers/application_controller.rb
@@ -8,12 +8,8 @@ class ApplicationController < ActionController::Base
protected
- def log_in(user)
- session[:user_id] = user.id
- end
-
- def current_user
- @current_user ||= User.find(session[:user_id])
+ def current_user(session_id = session[:user_id])
+ @current_user ||= UserSession.authenticate(session_id).try(:user)
end
def translate(key)
@@ -21,7 +17,7 @@ class ApplicationController < ActionController::Base
end
def authenticate!
- return if session[:user_id].present? && current_user.present?
+ return if current_user.present?
redirect_to new_session_path
rescue
redirect_to new_session_path
app/controllers/profiles_controller.rb
@@ -6,12 +6,12 @@ class ProfilesController < ApplicationController
end
def edit
- @profile = @current_user.profile
+ @profile = current_user.profile
@program = Program.stronglifts
end
def update
- profile = @current_user.profile
+ profile = current_user.profile
profile.update_attributes(profile_params)
flash[:notice] = t("profiles.edit.profile_update_success")
redirect_to profile_path(profile)
app/controllers/registrations_controller.rb
@@ -6,7 +6,9 @@ class RegistrationsController < PublicController
def create
@user = User.new(secure_params)
if @user.save
- log_in(@user)
+ session[:user_id] = User.
+ login(secure_params[:username], secure_params[:password]).
+ access(request)
UserMailer.registration_email(@user).deliver_later
flash[:notice] = translate(".success")
redirect_to dashboard_path
app/controllers/sessions_controller.rb
@@ -1,7 +1,7 @@
class SessionsController < PublicController
def create
- if user_session = UserSession.login(params[:user][:username], params[:user][:password])
- session[:user_id] = user_session.id
+ if user_session = User.login(params[:user][:username], params[:user][:password])
+ session[:user_id] = user_session.access(request)
redirect_to dashboard_path
else
flash[:warning] = t("sessions.create.invalid_login")
@@ -14,6 +14,7 @@ class SessionsController < PublicController
end
def destroy
+ UserSession.authenticate(session[:user_id]).try(:revoke!)
reset_session()
redirect_to root_path
end
app/models/gym.rb
@@ -1,13 +1,7 @@
class Gym < ActiveRecord::Base
validates_presence_of :name
has_one :location, as: :locatable
- before_save :assign_location
+ accepts_nested_attributes_for :location
scope :closest_to, ->(user) { all }
-
- private
-
- def assign_location
- #self.latitude, self.longitude = Location.from(address, city, region, country)
- end
end
app/models/location.rb
@@ -1,4 +1,6 @@
class Location < ActiveRecord::Base
+ before_save :assign_coordinates
+
def self.build_from_ip(ip)
end
@@ -6,4 +8,10 @@ class Location < ActiveRecord::Base
results = Geocoder.search("#{address}, #{city}, #{region}, #{country}")
results.any? ? results.first.coordinates : [nil, nil]
end
+
+ private
+
+ def assign_coordinates
+ self.latitude, self.longitude = Location.from(address, city, region, country)
+ end
end
app/models/user.rb
@@ -2,6 +2,7 @@ class User < ActiveRecord::Base
has_secure_password
has_many :training_sessions
has_many :exercise_sessions, through: :training_sessions
+ has_many :user_sessions, dependent: :destroy
has_one :profile
USERNAME_REGEX=/\A[-a-z0-9_.]*\z/i
@@ -28,8 +29,7 @@ class User < ActiveRecord::Base
exercise_sessions.
joins(:exercise).
where(exercises: { name: exercise.name }).
- pluck(:target_weight).
- max
+ maximum(:target_weight)
end
def history_for(exercise)
@@ -53,6 +53,18 @@ class User < ActiveRecord::Base
GoogleDrive.new(self)
end
+ class << self
+ def login(username, password)
+ user = User.find_by(
+ "email = :email OR username = :username",
+ username: username.downcase,
+ email: username.downcase
+ )
+ return false if user.blank?
+ user.user_sessions.create! if user.authenticate(password)
+ end
+ end
+
private
def create_profile
app/models/user_session.rb
@@ -14,23 +14,12 @@ class UserSession < ActiveRecord::Base
self.ip = request.ip
self.user_agent = request.user_agent
self.location = Location.build_from_ip(request.ip)
- id
+ save ? id : nil
end
class << self
def authenticate(id)
active.find_by(id: id)
end
-
- def login(username, password)
- user = User.find_by(
- "email = :email OR username = :username",
- username: username.downcase,
- email: username.downcase
- )
- if user.present?
- user.authenticate(password)
- end
- end
end
end
db/migrate/20160430155822_create_user_sessions.rb
@@ -1,7 +1,7 @@
class CreateUserSessions < ActiveRecord::Migration
def change
create_table :user_sessions, id: :uuid do |t|
- t.belongs_to :user, foreign_key: true, type: :uuid, index: true
+ t.belongs_to :user, foreign_key: true, type: :uuid, index: true, null: false
t.string :ip
t.text :user_agent
t.datetime :accessed_at
db/schema.rb
@@ -94,7 +94,7 @@ ActiveRecord::Schema.define(version: 20160430155822) do
add_index "training_sessions", ["user_id"], name: "index_training_sessions_on_user_id", using: :btree
create_table "user_sessions", id: :uuid, default: "uuid_generate_v4()", force: :cascade do |t|
- t.uuid "user_id"
+ t.uuid "user_id", null: false
t.string "ip"
t.text "user_agent"
t.datetime "accessed_at"
spec/controllers/profiles_controller_spec.rb
@@ -15,12 +15,14 @@ describe ProfilesController do
it "loads the user's profile" do
get :show, id: user.to_param
expect(assigns(:user)).to eql(user)
+ expect(assigns(:profile)).to eql(user.profile)
expect(assigns(:program)).to eql(Program.stronglifts)
end
it "loads the other user's profile" do
get :show, id: other_user.to_param
expect(assigns(:user)).to eql(other_user)
+ expect(assigns(:profile)).to eql(other_user.profile)
expect(assigns(:program)).to eql(Program.stronglifts)
end
end
@@ -30,13 +32,13 @@ describe ProfilesController do
it "loads the user's profile into an edit view" do
get :edit, id: user.to_param
- expect(assigns(:current_user)).to eql(user)
+ expect(assigns(:profile)).to eql(user.profile)
expect(assigns(:program)).to eql(Program.stronglifts)
end
it "will not load the other user's profile into an edit view" do
get :edit, id: other_user.to_param
- expect(assigns(:current_user)).to eql(user)
+ expect(assigns(:profile)).to eql(user.profile)
expect(assigns(:program)).to eql(Program.stronglifts)
end
end
spec/controllers/registrations_controller_spec.rb
@@ -38,7 +38,8 @@ describe RegistrationsController do
end
it "logs them in" do
- expect(session[:user_id]).to eql(User.first.id)
+ expect(session[:user_id]).to be_present
+ expect(session[:user_id]).to eql(UserSession.last.id)
end
it "does not display any errors" do
spec/controllers/sessions_controller_spec.rb
@@ -7,12 +7,12 @@ describe SessionsController do
context "when credentials are correct" do
it "logs you in with email" do
post :create, { user: { username: user.email, password: "password" } }
- expect(session[:user_id]).to eql(user.id)
+ expect(session[:user_id]).to eql(UserSession.last.id)
end
it "logs you in with username" do
post :create, { user: { username: user.username, password: "password" } }
- expect(session[:user_id]).to eql(user.id)
+ expect(session[:user_id]).to eql(UserSession.last.id)
end
it "redirects to the dashboard" do
@@ -37,11 +37,15 @@ describe SessionsController do
describe "#destroy" do
context "when logged in" do
let(:user) { create(:user) }
+ let(:user_session) { create(:active_session, user: user) }
it "logs you out" do
- session[:user_id] = user.id
+ session[:user_id] = user_session.id
+
delete :destroy, id: user.id
+
expect(session[:user_id]).to be_nil
+ expect(user_session.reload.revoked_at).to be_present
end
end
end
spec/features/profiles_spec.rb
@@ -3,14 +3,16 @@ require "rails_helper"
feature "Profiles", type: :feature do
include_context "stronglifts_program"
let(:user) { create(:user) }
+ let(:user_session) { create(:active_session, user: user) }
+
+ before :each do
+ page.set_rack_session(user_id: user_session.id)
+ end
context "when the user has not completed any workouts" do
subject { ProfilePage.new(user) }
- before :each do
- page.set_rack_session(user_id: user.id)
- subject.visit_page
- end
+ before { subject.visit_page }
it "displays the users username" do
expect(page).to have_content(user.username)
@@ -25,10 +27,7 @@ feature "Profiles", type: :feature do
context "editing my profile" do
subject { EditProfilePage.new(user) }
- before :each do
- page.set_rack_session(user_id: user.id)
- subject.visit_page
- end
+ before { subject.visit_page }
it "allows me to edit my profile" do
subject.change(gender: :male, social_tolerance: :low)
spec/models/gym_spec.rb
@@ -11,23 +11,20 @@ describe Gym do
end
end
- describe "#before_save" do
- let(:latitude) { rand(90.0) }
- let(:longitude) { rand(180.0) }
-
- it 'updates the latitude/logitude' do
- allow(Location).to receive(:from).and_return([latitude, longitude])
- subject.assign_attributes(
+ describe "#location" do
+ it 'updates the location' do
+ subject.location_attributes = {
address: '123 street sw',
city: 'edmonton',
region: 'alberta',
country: 'canada',
- )
+ }
subject.save!
- subject.reload
- expect(subject.latitude).to eql(latitude)
- expect(subject.longitude).to eql(longitude)
+ expect(subject.location.address).to eql('123 street sw')
+ expect(subject.location.city).to eql('edmonton')
+ expect(subject.location.region).to eql('alberta')
+ expect(subject.location.country).to eql('canada')
end
end
end
spec/models/location_spec.rb
@@ -10,4 +10,24 @@ describe Location do
expect(longitude).to be_within(0.1).of(-114.0927691)
end
end
+
+ describe "#before_save" do
+ let(:latitude) { rand(90.0) }
+ let(:longitude) { rand(180.0) }
+
+ it 'assigns a lat/long' do
+ allow(Location).to receive(:from).and_return([latitude, longitude])
+
+ location = Location.new(
+ address: '123 street sw',
+ city: 'edmonton',
+ region: 'alberta',
+ country: 'canada',
+ )
+ location.save!
+
+ expect(location.latitude).to eql(latitude)
+ expect(location.longitude).to eql(longitude)
+ end
+ end
end
spec/models/user_session_spec.rb
@@ -25,6 +25,7 @@ describe UserSession do
it { expect(subject.user_agent).to eql(request.user_agent) }
it { expect(subject.location).to_not be_nil }
it { expect(because).to eql(subject.id) }
+ it { expect(subject).to be_persisted }
end
describe ".active" do
@@ -56,26 +57,4 @@ describe UserSession do
expect(UserSession.authenticate('blah')).to be_nil
end
end
-
- describe "#login" do
- context "when credentials are correct" do
- it "returns true" do
- user = create(:user, password: "password", password_confirmation: "password")
- expect(UserSession.login(user.email.upcase, "password")).to eql(user)
- end
-
- it "is case in-sensitive for username" do
- user = create(:user, username: "upcase", password: "password", password_confirmation: "password")
- expect(UserSession.login("UPcase", "password")).to eql(user)
- end
- end
-
- context "when the email is not registered" do
- it { expect(UserSession.login("sofake@noteven.com", "password")).to be_nil }
- end
-
- context "when the username is not registered" do
- it { expect(UserSession.login("sofake", "password")).to be_nil }
- end
- end
end
spec/models/user_spec.rb
@@ -191,4 +191,30 @@ describe User do
expect(user.profile.social_tolerance).to be_nil
end
end
+
+ describe "#login" do
+ context "when credentials are correct" do
+ it "returns true" do
+ user = create(:user, password: "password", password_confirmation: "password")
+ result = User.login(user.email.upcase, "password")
+ expect(result).to be_instance_of(UserSession)
+ expect(result.user).to eql(user)
+ end
+
+ it "is case in-sensitive for username" do
+ user = create(:user, username: "upcase", password: "password", password_confirmation: "password")
+ result = User.login("UPcase", "password")
+ expect(result).to be_instance_of(UserSession)
+ expect(result.user).to eql(user)
+ end
+ end
+
+ context "when the email is not registered" do
+ it { expect(User.login("sofake@noteven.com", "password")).to be_falsey }
+ end
+
+ context "when the username is not registered" do
+ it { expect(User.login("sofake", "password")).to be_falsey }
+ end
+ end
end
spec/support/http_authentication.rb
@@ -1,5 +1,6 @@
module HttpAuthentication
def http_login(user)
- session[:user_id] = user.id
+ allow(controller).to receive(:current_user).and_return(user)
+ session[:user_id] = build(:user_session, id: SecureRandom.uuid, user: user).id
end
end
spec/spec_helper.rb
@@ -11,4 +11,7 @@ RSpec.configure do |config|
config.run_all_when_everything_filtered = true
config.order = :random
Kernel.srand config.seed
+ config.backtrace_exclusion_patterns = [
+ /usr\/local/
+ ]
end