Merge branch 'atomaka/feature/simple-user-profile' into 'master'
Add a simple user profile Adds a profile and links to it. Also includes a refactor on the page header. See merge request !16
This commit is contained in:
commit
76610ede87
21 changed files with 128 additions and 18 deletions
|
@ -1,4 +1,9 @@
|
||||||
class UsersController < ApplicationController
|
class UsersController < ApplicationController
|
||||||
|
def show
|
||||||
|
@user = User.friendly.find(params[:id])
|
||||||
|
@comments = @user.comments
|
||||||
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@user = User.new
|
@user = User.new
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,6 +3,10 @@ module ApplicationHelper
|
||||||
bootstrap_classes[flash_type] || flash_type.to_s
|
bootstrap_classes[flash_type] || flash_type.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def page_header
|
||||||
|
content_for(:title) || ''
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def bootstrap_classes
|
def bootstrap_classes
|
||||||
|
|
|
@ -16,13 +16,12 @@ class Subcreddit < ActiveRecord::Base
|
||||||
presence: true,
|
presence: true,
|
||||||
format: /\A(?! )[a-z0-9 ]*(?<! )\z/i,
|
format: /\A(?! )[a-z0-9 ]*(?<! )\z/i,
|
||||||
uniqueness: true, #{ case_sensitive: false },
|
uniqueness: true, #{ case_sensitive: false },
|
||||||
length: { minimum: 3, maximum: 21 }
|
length: { minimum: 3, maximum: 21 },
|
||||||
|
sluguuidless: true
|
||||||
|
|
||||||
validates :closed,
|
validates :closed,
|
||||||
format: /\A[01]?\z/
|
format: /\A[01]?\z/
|
||||||
|
|
||||||
validate :slug_does_not_have_uuid
|
|
||||||
|
|
||||||
def closed?
|
def closed?
|
||||||
self.closed_at != nil
|
self.closed_at != nil
|
||||||
end
|
end
|
||||||
|
@ -36,10 +35,4 @@ class Subcreddit < ActiveRecord::Base
|
||||||
self.closed_at = nil
|
self.closed_at = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def slug_does_not_have_uuid
|
|
||||||
if self.slug.match /([a-z0-9]+\-){4}[a-z0-9]+\z/
|
|
||||||
errors.add(:name, 'must be unique')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,10 +1,17 @@
|
||||||
class User < ActiveRecord::Base
|
class User < ActiveRecord::Base
|
||||||
|
extend FriendlyId
|
||||||
|
|
||||||
has_secure_password
|
has_secure_password
|
||||||
|
|
||||||
|
has_many :comments
|
||||||
|
has_many :posts
|
||||||
|
|
||||||
|
friendly_id :username, use: :slugged
|
||||||
|
|
||||||
before_save :downcase_email
|
before_save :downcase_email
|
||||||
|
|
||||||
validates :email, presence: true, uniqueness: true
|
validates :email, presence: true, uniqueness: true
|
||||||
validates :username, presence: true, uniqueness: true
|
validates :username, presence: true, uniqueness: true, sluguuidless: true
|
||||||
validates :password, length: { minimum: 8 }
|
validates :password, length: { minimum: 8 }
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
7
app/validators/sluguuidless_validator.rb
Normal file
7
app/validators/sluguuidless_validator.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
class SluguuidlessValidator < ActiveModel::EachValidator
|
||||||
|
def validate_each(record, attribute, value)
|
||||||
|
if record.slug.match /([a-z0-9]+\-){4}[a-z0-9]+\z/
|
||||||
|
record.errors[attribute] << 'must be unique'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,8 +10,7 @@
|
||||||
= link_to 'Creddit', root_path, class: 'navbar-brand'
|
= link_to 'Creddit', root_path, class: 'navbar-brand'
|
||||||
.collapse.navbar-collapse
|
.collapse.navbar-collapse
|
||||||
ul.nav.navbar-nav
|
ul.nav.navbar-nav
|
||||||
- if @subcreddit && @subcreddit.name
|
li= page_header
|
||||||
li= link_to @subcreddit.name, @subcreddit
|
|
||||||
ul.nav.navbar-nav.navbar-right
|
ul.nav.navbar-nav.navbar-right
|
||||||
- if logged_in?
|
- if logged_in?
|
||||||
li= link_to 'Sign Out', signout_path
|
li= link_to 'Sign Out', signout_path
|
||||||
|
|
|
@ -18,4 +18,4 @@
|
||||||
.title Moderators
|
.title Moderators
|
||||||
.box
|
.box
|
||||||
ul
|
ul
|
||||||
li= @subcreddit.owner_username
|
li= link_to @subcreddit.owner_username, @subcreddit.owner
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
.comment
|
.comment
|
||||||
p.details= "#{comment.user_username} X points #{distance_of_time_in_words comment.created_at, Time.now} ago"
|
p.details
|
||||||
|
== link_to comment.user_username, comment.user
|
||||||
|
= " X points #{distance_of_time_in_words comment.created_at, Time.now} ago"
|
||||||
p.content= comment.content
|
p.content= comment.content
|
||||||
ul.links.list-inline
|
ul.links.list-inline
|
||||||
li= link_to 'permalink', subcreddit_post_comment_path(subcreddit, post, comment)
|
li= link_to 'permalink', subcreddit_post_comment_path(subcreddit, post, comment)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
- content_for(:title, link_to(@subcreddit.name, @subcreddit))
|
||||||
== render 'posts/post', post: @post
|
== render 'posts/post', post: @post
|
||||||
.alert.alert-info.in-page
|
.alert.alert-info.in-page
|
||||||
p you are viewing a single comment's thread.
|
p you are viewing a single comment's thread.
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
.posts.contents
|
.posts.contents
|
||||||
.post.show
|
.post.show
|
||||||
p.title= link_to post.title, [post.subcreddit, post]
|
p.title= link_to post.title, [post.subcreddit, post]
|
||||||
p.details= "submitted #{distance_of_time_in_words post.created_at, Time.now} ago by #{post.user_username}"
|
p.details
|
||||||
|
= "submitted #{distance_of_time_in_words post.created_at, Time.now} ago by "
|
||||||
|
== link_to post.user_username, post.user
|
||||||
p.content= post.content
|
p.content= post.content
|
||||||
ul.links.list-inline
|
ul.links.list-inline
|
||||||
li= link_to "#{post.comments_count} comments", subcreddit_post_path(post.subcreddit, post)
|
li= link_to "#{post.comments_count} comments", subcreddit_post_path(post.subcreddit, post)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
- content_for(:title, link_to(@subcreddit.name, @subcreddit))
|
||||||
== render 'post', post: @post
|
== render 'post', post: @post
|
||||||
- if @post.comments?
|
- if @post.comments?
|
||||||
.title= "all #{@post.comments_count} comments"
|
.title= "all #{@post.comments_count} comments"
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
- content_for(:title) { link_to @subcreddit.name, @subcreddit }
|
||||||
- if @subcreddit.closed?
|
- if @subcreddit.closed?
|
||||||
= "Board has been closed"
|
= "Board has been closed"
|
||||||
- else
|
- else
|
||||||
|
@ -7,7 +8,9 @@
|
||||||
li
|
li
|
||||||
.post
|
.post
|
||||||
p.title= link_to post.title, subcreddit_post_path(@subcreddit, post)
|
p.title= link_to post.title, subcreddit_post_path(@subcreddit, post)
|
||||||
p.details= "submitted #{distance_of_time_in_words post.created_at, Time.now} ago by #{post.user_username}"
|
p.details
|
||||||
|
= "submitted #{distance_of_time_in_words post.created_at, Time.now} ago by "
|
||||||
|
== link_to post.user_username, post.user
|
||||||
ul.links.list-inline
|
ul.links.list-inline
|
||||||
li= link_to "#{post.comments_count} comments", subcreddit_post_path(@subcreddit, post)
|
li= link_to "#{post.comments_count} comments", subcreddit_post_path(@subcreddit, post)
|
||||||
li= link_to 'share', ''
|
li= link_to 'share', ''
|
||||||
|
|
5
app/views/users/show.html.slim
Normal file
5
app/views/users/show.html.slim
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
- content_for(:title, link_to(@user.username, @user))
|
||||||
|
|
||||||
|
.comments.contents
|
||||||
|
- @comments.each do |comment|
|
||||||
|
== render 'comments/comment', subcreddit: comment.post.subcreddit, post: comment.post, comment: comment
|
|
@ -22,5 +22,8 @@ module Creddit
|
||||||
|
|
||||||
# Do not swallow errors in after_commit/after_rollback callbacks.
|
# Do not swallow errors in after_commit/after_rollback callbacks.
|
||||||
config.active_record.raise_in_transactional_callbacks = true
|
config.active_record.raise_in_transactional_callbacks = true
|
||||||
|
|
||||||
|
# So our console continues to work
|
||||||
|
config.autoload_paths += %W["#{config.root}/app/validators/"]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,7 +10,7 @@ Rails.application.routes.draw do
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :user_sessions, only: [:new, :create, :destroy]
|
resources :user_sessions, only: [:new, :create, :destroy]
|
||||||
resources :users, only: [:new, :create]
|
resources :users, path: 'u', only: [:show, :new, :create]
|
||||||
|
|
||||||
root to: 'subcreddits#index'
|
root to: 'subcreddits#index'
|
||||||
end
|
end
|
||||||
|
|
6
db/migrate/20150806191452_add_friendly_id_to_user.rb
Normal file
6
db/migrate/20150806191452_add_friendly_id_to_user.rb
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
class AddFriendlyIdToUser < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :users, :slug, :string
|
||||||
|
add_index :users, :slug, unique: true
|
||||||
|
end
|
||||||
|
end
|
|
@ -11,7 +11,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20150804145405) do
|
ActiveRecord::Schema.define(version: 20150806191452) do
|
||||||
|
|
||||||
create_table "comments", force: :cascade do |t|
|
create_table "comments", force: :cascade do |t|
|
||||||
t.integer "user_id"
|
t.integer "user_id"
|
||||||
|
@ -84,6 +84,9 @@ ActiveRecord::Schema.define(version: 20150804145405) do
|
||||||
t.string "password_digest"
|
t.string "password_digest"
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
|
t.string "slug"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
add_index "users", ["slug"], name: "index_users_on_slug", unique: true
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,25 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
describe UsersController, type: :controller do
|
describe UsersController, type: :controller do
|
||||||
|
describe '#show' do
|
||||||
|
let(:user) { create(:user) }
|
||||||
|
before(:each) { get :show, id: user }
|
||||||
|
|
||||||
|
it 'should render :show' do
|
||||||
|
expect(response).to render_template(:show)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should assign user comments to @comments' do
|
||||||
|
comments = 5.times.collect { create(:comment, user: user) }
|
||||||
|
|
||||||
|
expect(assigns(:comments)).to eq(comments)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should assign requested User to @user' do
|
||||||
|
expect(assigns(:user)).to eq(user)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#new' do
|
describe '#new' do
|
||||||
it 'should render :new' do
|
it 'should render :new' do
|
||||||
get :new
|
get :new
|
||||||
|
|
23
spec/features/users/profile_spec.rb
Normal file
23
spec/features/users/profile_spec.rb
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe 'Profile', type: :feature do
|
||||||
|
let!(:user) { create(:user) }
|
||||||
|
|
||||||
|
it 'should display a user profile' do
|
||||||
|
visit user_path(user)
|
||||||
|
|
||||||
|
expect(page).to have_content(user.username)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the user has commented' do
|
||||||
|
let!(:comments) { 5.times.collect { create(:comment, user: user) } }
|
||||||
|
|
||||||
|
it 'should display user comments' do
|
||||||
|
visit user_path(user)
|
||||||
|
|
||||||
|
comments.each do |comment|
|
||||||
|
expect(page).to have_content(comment.content)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -26,4 +26,20 @@ describe ApplicationHelper do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#page_header' do
|
||||||
|
context 'when title is provided' do
|
||||||
|
it 'should return the set title' do
|
||||||
|
allow(helper).to receive(:content_for).with(:title).and_return('Test')
|
||||||
|
|
||||||
|
expect(helper.page_header).to eq 'Test'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when title is not provided' do
|
||||||
|
it 'should return blank' do
|
||||||
|
expect(helper.page_header).to be_blank
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
|
require 'securerandom'
|
||||||
|
|
||||||
describe User, type: :model do
|
describe User, type: :model do
|
||||||
let(:user) { build(:user) }
|
let(:user) { build(:user) }
|
||||||
|
|
||||||
it { should have_secure_password }
|
it { should have_secure_password }
|
||||||
|
|
||||||
|
it { should have_many :comments }
|
||||||
|
it { should have_many :posts }
|
||||||
|
|
||||||
context 'with valid data' do
|
context 'with valid data' do
|
||||||
it 'should be valid' do
|
it 'should be valid' do
|
||||||
expect(user).to be_valid
|
expect(user).to be_valid
|
||||||
|
@ -44,5 +49,11 @@ describe User, type: :model do
|
||||||
user.password = 'a' * 4
|
user.password = 'a' * 4
|
||||||
expect(user).to be_invalid
|
expect(user).to be_invalid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'should not allow a slug with a UUID' do
|
||||||
|
user.slug = "test-#{SecureRandom.uuid}"
|
||||||
|
|
||||||
|
expect(user).to be_invalid
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue