diff --git a/Gemfile b/Gemfile
index 839131d..9a277d5 100644
--- a/Gemfile
+++ b/Gemfile
@@ -24,8 +24,7 @@ gem 'jbuilder', '~> 2.0'
# bundle exec rake doc:rails generates the API under doc/api.
gem 'sdoc', '~> 0.4.0', group: :doc
-# Use ActiveModel has_secure_password
- gem 'bcrypt', '~> 3.1.7'
+gem 'bcrypt', '~> 3.1.7'
gem 'kaminari'
@@ -38,6 +37,16 @@ gem 'hirb'
gem 'faker'
gem 'cancancan'
+
+gem 'simple_form'
+
+gem 'carrierwave'
+gem 'mini_magick'
+
+gem 'delayed_job_active_record'
+gem 'delayed_job_web'
+
+gem 'animate-rails'
# Use Unicorn as the app server
# gem 'unicorn'
@@ -46,8 +55,10 @@ gem 'cancancan'
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
+ gem 'pry'
+ gem 'pry-rails'
gem 'byebug'
-
+ gem "letter_opener"
# Access an IRB console on exception pages or by using <%= console %> in views
gem 'web-console', '~> 2.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 70060c3..d822356 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -36,6 +36,9 @@ GEM
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
+ addressable (2.3.8)
+ animate-rails (1.0.8)
+ rails
arel (6.0.0)
autoprefixer-rails (5.2.1)
execjs
@@ -51,6 +54,12 @@ GEM
byebug (5.0.0)
columnize (= 0.9.0)
cancancan (1.10.1)
+ carrierwave (0.10.0)
+ activemodel (>= 3.2.0)
+ activesupport (>= 3.2.0)
+ json (>= 1.7)
+ mime-types (>= 1.16)
+ coderay (1.1.0)
coffee-rails (4.1.0)
coffee-script (>= 2.2.0)
railties (>= 4.0.0, < 5.0)
@@ -60,6 +69,15 @@ GEM
coffee-script-source (1.9.1.1)
columnize (0.9.0)
debug_inspector (0.0.2)
+ delayed_job (4.0.6)
+ activesupport (>= 3.0, < 5.0)
+ delayed_job_active_record (4.0.3)
+ activerecord (>= 3.0, < 5.0)
+ delayed_job (>= 3.0, < 4.1)
+ delayed_job_web (1.2.10)
+ activerecord (> 3.0.0)
+ delayed_job (> 2.0.3)
+ sinatra (>= 1.4.4)
erubis (2.7.0)
execjs (2.5.2)
faker (1.4.3)
@@ -82,18 +100,32 @@ GEM
kaminari (0.16.3)
actionpack (>= 3.0.0)
activesupport (>= 3.0.0)
+ launchy (2.4.3)
+ addressable (~> 2.3)
+ letter_opener (1.4.1)
+ launchy (~> 2.2)
loofah (2.0.2)
nokogiri (>= 1.5.9)
mail (2.6.3)
mime-types (>= 1.16, < 3)
+ method_source (0.8.2)
mime-types (2.6.1)
+ mini_magick (4.2.7)
mini_portile (0.6.2)
minitest (5.7.0)
multi_json (1.11.0)
nokogiri (1.6.6.2)
mini_portile (~> 0.6.0)
pg (0.18.2)
+ pry (0.10.1)
+ coderay (~> 1.1.0)
+ method_source (~> 0.8.1)
+ slop (~> 3.4)
+ pry-rails (0.3.4)
+ pry (>= 0.9.10)
rack (1.6.1)
+ rack-protection (1.5.3)
+ rack
rack-test (0.6.3)
rack (>= 1.0)
rails (4.2.1)
@@ -132,6 +164,14 @@ GEM
sdoc (0.4.1)
json (~> 1.7, >= 1.7.7)
rdoc (~> 4.0)
+ simple_form (3.1.0)
+ actionpack (~> 4.0)
+ activemodel (~> 4.0)
+ sinatra (1.4.6)
+ rack (~> 1.4)
+ rack-protection (~> 1.4)
+ tilt (>= 1.3, < 3)
+ slop (3.6.0)
spoon (0.0.4)
ffi
spring (1.3.6)
@@ -161,22 +201,31 @@ PLATFORMS
ruby
DEPENDENCIES
+ animate-rails
awesome_print
bcrypt (~> 3.1.7)
bootstrap-sass (~> 3.3.5)
byebug
cancancan
+ carrierwave
coffee-rails (~> 4.1.0)
+ delayed_job_active_record
+ delayed_job_web
faker
hirb
interactive_editor
jbuilder (~> 2.0)
jquery-rails
kaminari
+ letter_opener
+ mini_magick
pg
+ pry
+ pry-rails
rails (= 4.2.1)
sass-rails (~> 5.0)
sdoc (~> 0.4.0)
+ simple_form
spring
turbolinks
uglifier (>= 1.3.0)
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..37676a1
--- /dev/null
+++ b/README.md
@@ -0,0 +1,32 @@
+#Blog Features:
+
+##Homepage
+
+#### Site Navigation Bar:
+ - Visible on each page
+ - Drop-down for Post Categories
+ - User Log In / Sign Up / Log Out
+ - Click on site header leads to homepage
+
+#### Image carousel
+ - Useful for highlight news/updates/features
+
+#### Recent blog posts featured
+ - Link in title and full body shown
+
+##Creating Post
+ - Posts can have categories and tags in addition to the body and title
+ - Can add user collaborators for the post for management ability
+
+##Viewing Post
+ - Includes Liking, Favouriting, UpVoting
+ - Users can click 'Join' / 'Leave'
+ - File Attachment previews
+ - Comment box for other viewers
+ - Comments print avatar, body, and deletion link if applicable
+
+##Feautures Being Added in the Future:
+ - Working AJAX on the posts show page
+ - Nested drop down for All Posts > Post Index / Post Category in the future
+ - Implement clicking on image to link to parts of site
+ - Add image preview to Recent Posts featured
diff --git a/README.rdoc b/README.rdoc
deleted file mode 100644
index dd4e97e..0000000
--- a/README.rdoc
+++ /dev/null
@@ -1,28 +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
-
-* ...
-
-
-Please feel free to use a different markup language if you do not plan to run
-rake doc:app.
diff --git a/app/assets/images/blue.jpg b/app/assets/images/blue.jpg
new file mode 100644
index 0000000..5cc7ea4
Binary files /dev/null and b/app/assets/images/blue.jpg differ
diff --git a/app/assets/images/retina_wood.png b/app/assets/images/retina_wood.png
deleted file mode 100644
index 22f2450..0000000
Binary files a/app/assets/images/retina_wood.png and /dev/null differ
diff --git a/app/assets/images/tree.png b/app/assets/images/tree.png
new file mode 100644
index 0000000..4e627ec
Binary files /dev/null and b/app/assets/images/tree.png differ
diff --git a/app/assets/images/upfeathers.png b/app/assets/images/upfeathers.png
deleted file mode 100644
index 8046ef3..0000000
Binary files a/app/assets/images/upfeathers.png and /dev/null differ
diff --git a/app/assets/javascripts/favourites.coffee b/app/assets/javascripts/favourites.coffee
new file mode 100644
index 0000000..24f83d1
--- /dev/null
+++ b/app/assets/javascripts/favourites.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/application.scss b/app/assets/stylesheets/application.scss
index 2fde0c9..6ac0b84 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -6,6 +6,7 @@
h5 {
color: #0079a3;
font-size: 35pt;
+ letter-spacing: 15px;
margin-top: 25px;
margin-bottom:5px;
padding-top: 0px;
@@ -13,6 +14,9 @@
font-weight: lighter;
}
}
+.header-text a:hover{
+ text-decoration: none;
+}
.header-link {
text-align: center;
@@ -24,10 +28,11 @@
.user{
text-align: right;
background: rgba(0, 121, 163, 0.6);
+ background-image: url("blue.jpg");
width:100%;
margin-left: 0;
margin-right: 0;
- height: 28px;
+ height: 55px;
padding-right: 5px;
padding-top: 5px;
padding-bottom: 5px;
@@ -35,13 +40,25 @@
}
.avatar {
border-radius: 50%;
+ width: 45px;
+ height: 45px;
+}
+h1, h2, h3, h4 {
+ font-weight: lighter;
}
-
.body {
- padding-left: 10px;
- padding-right: 10px;
+ padding-left: 10px;
+ padding-right: 10px;
+ .post-options {
+ display: inline-block;
+ }
.button-options {
height: auto;
+ padding: 25px;
+ .button-select {
+ display: inline-block;
+ float: left;
+ }
.button-options button {
}
.button-long {
@@ -90,7 +107,7 @@
background-color: #ff4c4c;
}
.fave {
- background-color: #65e0fc;
+ background-color: #ffff7f;
}
}
}
@@ -107,3 +124,85 @@
padding-bottom: 15px;
border-bottom: 1px dotted #0079a3;
}
+.post-image {
+ display: block;
+ padding-top: 20px;
+ padding-bottom: 20px;
+}
+/*Simple Form Styling*/
+.form-group label {
+ display: block;
+ font-size: 16pt;
+ font-family: Arial;
+ font-weight: lighter;
+ color: #074c62;
+ text-align: left;
+ margin-right: 10px;
+}
+
+.form-group input {
+ padding: 5px;
+ margin-bottom: 10px;
+ background-color: #ececec;
+ border: 1px solid #0079a3;
+ border-radius: 10px;
+ width: 650px;
+ height: 40px;
+}
+
+.form-group textarea {
+ padding: 5px;
+ margin-bottom: 10px;
+ background-color: #ececec;
+ border: 1px solid #0079a3;
+ border-radius: 10px;
+ width: 650px;
+ height: 120px;
+}
+
+#post_category_id {
+ width: 325px;
+ height: 40px;
+ border-radius: 10px;
+ background-color: #0079a3;
+ color: #FFFFFF;
+ font-weight: lighter;
+ text-transform: uppercase;
+}
+.form-control {
+ font-size: 14pt;
+ font-weight: lighter;
+ color: #999999;
+ background-color: #0079a3;
+ border-radius: 10px;
+}
+.check-boxes label {
+ background-color: #0079a3;
+ height: 40px;
+ padding: 5px;
+ border-radius: 10px;
+ margin-right: 8px;
+ color: #FFFFFF;
+ font-weight: lighter;
+ text-transform: uppercase;
+ .collection_check_boxes {
+ margin-left: 10px;
+ margin-right: 15px;
+ height: 30px;
+ }
+}
+.submit-button {
+ width: auto;
+ height: 40px;
+ margin-top: 15px;
+ margin-left: 5px;
+ padding-top: 0px;
+ padding-left: 5px;
+ padding-bottom: 5px;
+ border-radius: 5px;
+ color: #333333;
+ font-size: 18pt;
+ font-weight: lighter;
+ text-align: center;
+ background-color: #ff7256;
+}
diff --git a/app/assets/stylesheets/favourites.scss b/app/assets/stylesheets/favourites.scss
new file mode 100644
index 0000000..66cc292
--- /dev/null
+++ b/app/assets/stylesheets/favourites.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the favourites 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/application_controller.rb b/app/controllers/application_controller.rb
index b7b85c3..f9abe9d 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -1,6 +1,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
before_action :find_category
@@ -21,5 +20,5 @@ def current_user
def find_category
@categories = Category.all
end
-
+
end
diff --git a/app/controllers/collaborations_controller.rb b/app/controllers/collaborations_controller.rb
index 51faa52..544928c 100644
--- a/app/controllers/collaborations_controller.rb
+++ b/app/controllers/collaborations_controller.rb
@@ -1,22 +1,23 @@
class CollaborationsController < ApplicationController
- before_action :authenticate_user!
- before_action :find_post
+ before_action :authenticate_user!
+ before_action :find_post
- def create
- @collaboration = Collaboration.new
- @collaboration.user = current_user
- @collaboration.post = @post
- if @collaboration.save
- redirect_to post_path(@post), notice: "Joined"
- else
- redirect_to post_path(@post), alert: "Can't Join"
- end
+ def create
+ @collaboration = Collaboration.new
+ @collaboration.user = current_user
+ @collaboration.post = @post
+ if @collaboration.save
+ redirect_to post_path(@post), notice: "Joined"
+ else
+ redirect_to post_path(@post), alert: "Can't Join"
end
+ end
- private
- def find_post
- @post = Post.find params[:post_id]
- end
+ private
+
+ def find_post
+ @post = Post.find params[:post_id]
+ end
end
diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb
index f2de207..e7a083b 100644
--- a/app/controllers/comments_controller.rb
+++ b/app/controllers/comments_controller.rb
@@ -8,19 +8,26 @@ def create
@comment = Comment.new(comment_params)
@comment.post = @post
@comment.user = current_user
-
- if @comment.save
- redirect_to post_path(@post), notice: "Comment created!"
- else
- render "/posts/show"
+ respond_to do |format|
+ if @comment.save
+ CommentsMailer.delay.notify_post_owner(@comment)
+ format.html { redirect_to post_path(@post), notice: "Comment created!" }
+ format.js
+ else
+ format.html { render "/posts/show" }
+ format.js { render :create_failure }
+ end
end
end
def destroy
- post = Post.find params[:post_id]
- comment = Comment.find params[:id]
- comment.destroy
- redirect_to post_path(post), notice: "Comment deleted."
+ @post = Post.find params[:post_id]
+ @comment = Comment.find params[:id]
+ @comment.destroy
+ respond_to do |format|
+ format.html { redirect_to post_path(@post), notice: "Comment deleted." }
+ format.js { render :destroy }
+ end
end
end
diff --git a/app/controllers/favourites_controller.rb b/app/controllers/favourites_controller.rb
new file mode 100644
index 0000000..3434943
--- /dev/null
+++ b/app/controllers/favourites_controller.rb
@@ -0,0 +1,23 @@
+class FavouritesController < ApplicationController
+
+ before_action :authenticate_user!
+
+ def create
+ post = Post.find params[:post_id]
+ favourite = current_user.favourites.new
+ favourite.post = post
+ if favourite.save
+ redirect_to post, notice: "Question favourited"
+ else
+ redirect_to post, alert: "Can't favourite"
+ end
+ end
+
+ def destroy
+ post = Post.find params[:post_id]
+ favourite = current_user.favourites.find params[:id]
+ favourite.destroy
+ redirect_to post, notice: "Un-Favourited"
+ end
+
+end
diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb
index 414eaf3..a2a09e1 100644
--- a/app/controllers/posts_controller.rb
+++ b/app/controllers/posts_controller.rb
@@ -1,9 +1,8 @@
class PostsController < ApplicationController
before_action :find_post, only: [:edit, :update, :destroy, :show]
-
before_action :authenticate_user!, except: [:index, :show]
- before_action :authorize, only: [:edit, :update, :destroy]
+ before_action :authorize, only: [:edit]
def index
@posts = Post.page(params[:page]).per(8).order("id ASC")
@@ -14,7 +13,6 @@ def new
end
def create
- post_params = params.require(:post).permit([:title, :body, :category_id, {tag_ids: []}])
@post = Post.new(post_params)
@post.user = current_user
@@ -29,6 +27,7 @@ def show
@comment = Comment.new
@like = @post.like_for(current_user)
@vote = @post.vote_for(current_user)
+ @favourite = @post.favourite_for(current_user)
@collaboration = @post.collaborating_users
end
@@ -36,7 +35,6 @@ def edit
end
def update
- post_params = params.require(:post).permit([:title, :body, :category_id, {tag_ids: []}])
if @post.update(post_params)
redirect_to post_path(@post), notice: "Post has been updated"
else
@@ -45,18 +43,26 @@ def update
end
def destroy
+ authorize_delete
@post.destroy
redirect_to posts_path, notice: "Post Deleted"
end
private
+ def post_params
+ post_params = params.require(:post).permit([:title, :body, :category_id, {tag_ids: []}, :image])
+ end
+
def find_post
@post = Post.find params[:id]
end
def authorize
- redirect_to root_path, alert: "Access denied." unless can? :manage, @post
+ redirect_to root_path, alert: "Access denied." unless can? :edit, @post
end
+ def authorize_delete
+ redirect_to post_path(@post), alert: "Access denied" unless can? :destroy, @post
+ end
end
diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb
deleted file mode 100644
index 0ea233d..0000000
--- a/app/controllers/tags_controller.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-class TagsController < ApplicationController
-end
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index a325c5a..c1c469e 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -1,42 +1,46 @@
class UsersController < ApplicationController
- before_action :user_params, only: [:create, :edit]
-
- def new
- @user = User.new
- end
-
- def create
- @user = User.new user_params
- if @user.save
- session[:user_id] = @user.id
- redirect_to root_path
- else
- render :new
- end
- end
-
-def edit
- @user = current_user
-end
+ before_action :authenticate_user!, only: [:edit, :update]
+ before_action :user_params, only: [:create, :update]
-def update
- @user = current_user
- if !@user.authenticate(params[:user][:current_password])
- flash[:alert] = "You've entered the wrong password"
- render :edit
- elsif @user.update(user_params)
- redirect_to edit_users_path, notice: "Information updated"
- else
- render :edit
+ def new
+ @user = User.new
+ end
+
+ def create
+ @user = User.new user_params
+ if @user.save
+ session[:user_id] = @user.id
+ redirect_to root_path, notice: "Logged In!"
+ else
+ render :new
+ end
+ end
+
+ def edit
+ @user = current_user
+ end
+
+ def update
+ @user = current_user
+ if !@user.authenticate(params[:user][:current_password])
+ flash[:alert] = "You've entered the wrong password"
+ render :edit
+ elsif @user.update(user_params)
+ redirect_to user_path(@user), notice: "Information updated"
+ else
+ render :edit
+ end
+ end
+
+ def show
+ @user = User.find params[:id]
end
-end
-
-private
-def user_params
- params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation)
-end
+ private
+ def user_params
+ params.require(:user).permit(:first_name, :last_name, :email, :avatar, :password, :password_confirmation)
+ end
end
diff --git a/app/controllers/votes_controller.rb b/app/controllers/votes_controller.rb
index aaf6665..b2d4840 100644
--- a/app/controllers/votes_controller.rb
+++ b/app/controllers/votes_controller.rb
@@ -1,35 +1,42 @@
class VotesController < ApplicationController
-
before_action :authenticate_user!
def create
- post = Post.find params[:post_id]
-
- vote = current_user.votes.new(vote_params)
- vote.post = post
- if vote.save
- redirect_to post, notice: "Voted!"
- else
- redirect_to post, alert: "Couldn't vote"
+ @post = Post.find params[:post_id]
+ @vote = current_user.votes.new(vote_params)
+ @vote.post = @post
+ respond_to do |format|
+ if @vote.save
+ format.html { redirect_to @post, notice: "Voted!" }
+ format.js { render }
+ else
+ format.html { redirect_to @post, alert: "Couldnt Vote!" }
+ format.js { render }
+ end
end
end
- def destroy
- post = Post.find params[:post_id]
-
- vote = current_user.votes.find params[:id]
- vote.destroy
- redirect_to post, notice: "Vote Removed"
- end
-
def update
- post = Post.find params[:post_id]
+ @post = Post.find params[:post_id]
+ @vote = current_user.votes.find params[:id]
+ respond_to do |format|
+ if @vote.update(vote_params)
+ format.html { redirect_to @post, notice: "Vote updated!" }
+ format.js { render }
+ else
+ format.html { redirect_to @post, alert: "Vote couldn't update" }
+ format.js { render }
+ end
+ end
+ end
- vote = current_user.votes.find params[:id]
- if vote.update(vote_params)
- redirect_to post, notice: "Vote Changed!"
- else
- redirect_to post, alert: "Vote Un-Changed"
+ def destroy
+ @post = Post.find params[:post_id]
+ @vote = current_user.votes.find params[:id]
+ @vote.destroy
+ respond_to do |format|
+ format.html { redirect_to @post, notice: "Vote removed" }
+ format.js { render }
end
end
diff --git a/app/helpers/favourites_helper.rb b/app/helpers/favourites_helper.rb
new file mode 100644
index 0000000..907962e
--- /dev/null
+++ b/app/helpers/favourites_helper.rb
@@ -0,0 +1,2 @@
+module FavouritesHelper
+end
diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb
new file mode 100644
index 0000000..d25d889
--- /dev/null
+++ b/app/mailers/application_mailer.rb
@@ -0,0 +1,4 @@
+class ApplicationMailer < ActionMailer::Base
+ default from: "from@example.com"
+ layout 'mailer'
+end
diff --git a/app/mailers/comments_mailer.rb b/app/mailers/comments_mailer.rb
new file mode 100644
index 0000000..755b51e
--- /dev/null
+++ b/app/mailers/comments_mailer.rb
@@ -0,0 +1,8 @@
+class CommentsMailer < ApplicationMailer
+
+ def notify_post_owner(comment)
+ @comment = comment
+ @post = comment.post
+ mail(to: @post.user.email, subject: "A post has been commented on!")
+ end
+end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index ff4087a..1e94485 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -13,7 +13,7 @@ def initialize(user)
end
can :manage, Comment do |comment|
- comment.user == user
+ comment.user == user || comment.post.user == user
end
end
end
diff --git a/app/models/favourite.rb b/app/models/favourite.rb
new file mode 100644
index 0000000..40ae00c
--- /dev/null
+++ b/app/models/favourite.rb
@@ -0,0 +1,6 @@
+class Favourite < ActiveRecord::Base
+ belongs_to :user
+ belongs_to :post
+
+ validates :post_id, uniqueness: {scope: :user_id}
+end
diff --git a/app/models/post.rb b/app/models/post.rb
index d36d610..922fb11 100644
--- a/app/models/post.rb
+++ b/app/models/post.rb
@@ -1,5 +1,7 @@
class Post < ActiveRecord::Base
+ mount_uploader :image, ImageUploader
+
belongs_to :category
belongs_to :user
@@ -12,6 +14,9 @@ class Post < ActiveRecord::Base
has_many :taggings, dependent: :destroy
has_many :tags, through: :taggings
+ has_many :favourites, dependent: :destroy
+ has_many :favouriting_users, through: :favourites, source: :user
+
has_many :collaborations, dependent: :destroy
has_many :collaborating_users, through: :collaborations, source: :user
@@ -21,6 +26,7 @@ class Post < ActiveRecord::Base
scope :recent_three, lambda { order("updated_at DESC").limit(3) }
+
def liked_by?(user)
likes.where(user: user).present?
end
@@ -29,6 +35,14 @@ def like_for(user)
likes.find_by_user_id(user)
end
+ def favourited_by?(user)
+ favourites.where(user: user).present?
+ end
+
+ def favourite_for(user)
+ favourites.find_by_user_id(user)
+ end
+
def vote_for(user)
votes.find_by_user_id(user)
end
diff --git a/app/models/user.rb b/app/models/user.rb
index d92217f..ebbf895 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -1,5 +1,7 @@
class User < ActiveRecord::Base
+ mount_uploader :avatar, ImageUploader
+
has_secure_password
has_many :posts, dependent: :destroy
@@ -9,7 +11,13 @@ class User < ActiveRecord::Base
has_many :votes, dependent: :destroy
has_many :voted_posts, through: :votes, source: :post
has_many :collaborations, dependent: :destroy
- has_many :collaborated_posts, through: :collaborations, source: :posts
+ has_many :collaborated_posts, through: :collaborations, source: :post
+
+ has_many :taggings, dependent: :destroy
+ has_many :tagged_posts, through: :taggings, source: :post
+
+ has_many :favourites, dependent: :destroy
+ has_many :favourited_posts, through: :favourites, source: :post
validates :first_name, presence: true
validates :last_name, presence: true
@@ -20,4 +28,12 @@ def full_name
"#{first_name} #{last_name}".strip.squeeze(" ")
end
+ def recent_five_made
+ posts.order("updated_at DESC").limit(5)
+ end
+
+ def recent_five_joins
+ collaborated_posts.order("created_at DESC").limit(5)
+ end
+
end
diff --git a/app/uploaders/image_uploader.rb b/app/uploaders/image_uploader.rb
new file mode 100644
index 0000000..1898658
--- /dev/null
+++ b/app/uploaders/image_uploader.rb
@@ -0,0 +1,26 @@
+# encoding: utf-8
+
+class ImageUploader < CarrierWave::Uploader::Base
+
+ # Include RMagick or MiniMagick support:
+ # include CarrierWave::RMagick
+ include CarrierWave::MiniMagick
+
+ # Choose what kind of storage to use for this uploader:
+ storage :file
+ # storage :fog
+
+ # Override the directory where uploaded files will be stored.
+ # This is a sensible default for uploaders that are meant to be mounted:
+ def store_dir
+ "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
+ end
+
+ version :square_thumb do
+ process :resize_to_fill => [45,45]
+ end
+
+ version :resized_image do
+ process :resize_to_fill => [300,300]
+ end
+end
diff --git a/app/views/comments/_comment.html.erb b/app/views/comments/_comment.html.erb
new file mode 100644
index 0000000..17c2e2d
--- /dev/null
+++ b/app/views/comments/_comment.html.erb
@@ -0,0 +1,29 @@
+<% @post.comments.each do |comment| %>
+
+<% end %>
diff --git a/app/views/comments/_form.html.erb b/app/views/comments/_form.html.erb
new file mode 100644
index 0000000..f663b0d
--- /dev/null
+++ b/app/views/comments/_form.html.erb
@@ -0,0 +1,13 @@
+<% if @comment.errors.any? %>
+
+ <% @comment.errors.full_messages.each do |msg| %>
+ - <%= msg %>
+ <% end %>
+
+ <% end %>
+
+<%= simple_form_for [@post, @comment], :remote => true do |f| %>
+ <%= f.text_area :body, :size => "50x8" %>
+
+ <%= f.submit 'Comment!', :class => "submit-button" %>
+<% end %>
diff --git a/app/views/comments/create.js.erb b/app/views/comments/create.js.erb
new file mode 100644
index 0000000..6330834
--- /dev/null
+++ b/app/views/comments/create.js.erb
@@ -0,0 +1,4 @@
+$("#comments").prepend("<%= j render 'comment', comment: @comment %>");
+
+<% @comment = Comment.new %>
+$("#new_comment").replaceWith("<%= j render 'form' %>");
diff --git a/app/views/comments/create_failure.js.erb b/app/views/comments/create_failure.js.erb
new file mode 100644
index 0000000..a00b123
--- /dev/null
+++ b/app/views/comments/create_failure.js.erb
@@ -0,0 +1 @@
+$("#new_comment").replaceWith("<%= j render 'form' %>");
diff --git a/app/views/comments/destroy.js.erb b/app/views/comments/destroy.js.erb
new file mode 100644
index 0000000..c859aca
--- /dev/null
+++ b/app/views/comments/destroy.js.erb
@@ -0,0 +1 @@
+$("#<% dom_id(@comment) %>").fadeOut();
diff --git a/app/views/comments_mailer/notify_post_owner.html.erb b/app/views/comments_mailer/notify_post_owner.html.erb
new file mode 100644
index 0000000..b3b243d
--- /dev/null
+++ b/app/views/comments_mailer/notify_post_owner.html.erb
@@ -0,0 +1,10 @@
+
+
+ Hey there, <%= @post.user.full_name %>,
+ Your post, titled: <%= @post.title %>
+ Has been commented on. It reads:
+ <%= @comment.body %>
+
+
Have a great one and see you on the blog soon!
+
+
diff --git a/app/views/homes/about.html.erb b/app/views/homes/about.html.erb
index b6fa616..0f65265 100644
--- a/app/views/homes/about.html.erb
+++ b/app/views/homes/about.html.erb
@@ -1,4 +1,6 @@
-Hi, I'm Tien.
-This is my about page
+
+
Hi, I'm Tien.
+ This is my about page
-<%= image_tag "http://i.imgur.com/9f4lbXW.jpg" %>
+ <%= image_tag "http://i.imgur.com/9f4lbXW.jpg" %>
+
diff --git a/app/views/homes/home.html.erb b/app/views/homes/home.html.erb
index a6e8135..fdfe694 100644
--- a/app/views/homes/home.html.erb
+++ b/app/views/homes/home.html.erb
@@ -1,4 +1,4 @@
-
+
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 70c46c0..f2dd6d1 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -12,7 +12,7 @@
diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb
new file mode 100644
index 0000000..991cf0f
--- /dev/null
+++ b/app/views/layouts/mailer.html.erb
@@ -0,0 +1,5 @@
+
+
+ <%= yield %>
+
+
diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb
new file mode 100644
index 0000000..37f0bdd
--- /dev/null
+++ b/app/views/layouts/mailer.text.erb
@@ -0,0 +1 @@
+<%= yield %>
diff --git a/app/views/posts/_buttons.html.erb b/app/views/posts/_buttons.html.erb
new file mode 100644
index 0000000..ad2a633
--- /dev/null
+++ b/app/views/posts/_buttons.html.erb
@@ -0,0 +1,55 @@
+ <% if @post.liked_by?(current_user) %>
+
+ <%= button_to "☹", post_like_path(@post, @like), method: :delete, :class => 'button likes' %>
+
+ <% else %>
+
+ <%= button_to "♥︎", post_likes_path(@post), method: :post, :class => 'button likes' %>
+
+ <% end %>
+
+ <% if @post.favourited_by?(current_user)%>
+
+ <%= button_to "★", post_favourite_path(@post,@favourite), method: :delete, :class =>'button fave' %>
+
+ <% else %>
+
+ <%= button_to "☆", post_favourites_path(@post), method: :post, :class =>'button fave' %>
+
+ <% end %>
+
+ <% if @vote.nil? %>
+
+ <%= button_to "⬆︎", post_votes_path(@post, {vote: {is_up: true}}), method: :post, :class => 'button vote' %>
+
+
+ <%= button_to "⬇︎", post_votes_path(@post, {vote: {is_up: false}}), method: :post, :class => 'button vote' %>
+
+
+ <% elsif @vote.is_up? %>
+
+ <%= button_to "⬆︎", post_vote_path(@post, @vote), method: :delete, :class => 'button vote-up', :id => 'up' %>
+
+
+ <%= button_to "⬇︎", post_vote_path(@post, @vote, {vote: {is_up: false}}), method: :patch, :class => 'button vote' %>
+
+
+ <% else %>
+
+ <%= button_to "⬆︎", post_vote_path(@post, @vote, {vote: {is_up: true}}), method: :patch, :class => 'button vote' %>
+
+
+ <%= button_to "⬇︎", post_vote_path(@post, @vote), method: :delete, :class => 'button vote-down', :id => 'down' %>
+
+ <% end %>
+
+ <% if can? :edit, @post %>
+
+ <%= button_to "Leave", post_collaboration_path(@post, @collaboration), method: :delete, :class => 'button-long join' %>
+
+
+ <% else %>
+
+ <%= button_to "Join", post_collaborations_path(@post), method: :post, :class => 'button-long leave' %>
+
+ <% end %>
diff --git a/app/views/posts/_collaborators.html.erb b/app/views/posts/_collaborators.html.erb
new file mode 100644
index 0000000..8c4ad64
--- /dev/null
+++ b/app/views/posts/_collaborators.html.erb
@@ -0,0 +1,6 @@
+Collaborator(s):
+
+ <% @post.collaborating_users.each do |user| %>
+ - <%= link_to user.full_name, user_path(user) %>
+ <% end %>
+
diff --git a/app/views/posts/_form.html.erb b/app/views/posts/_form.html.erb
index 0550f29..de29332 100644
--- a/app/views/posts/_form.html.erb
+++ b/app/views/posts/_form.html.erb
@@ -1,20 +1,35 @@
-
-<%= form_for @post do |f| %>
+<%= simple_form_for @post do |f| %>
+
+ <%= f.input :title %>
+
-
- | <%= f.label :category %>
- | <%= f.collection_select :category_id, Category.all, :id, :title %>
- |
-
- | <%= f.label :title %>
- | <%= f.text_field :title %>
- |
-
- | <%= f.label :body %>
- | <%= f.text_area :body, :size => '50x10' %>
- |
-
+
+ <%= f.input :body %>
+
-
- <%= f.submit 'Submit!', :class => 'submit-button' %>
+
+ <%= f.input :image %>
+
+
+
+ <%= f.label :category %>
+ <%= f.collection_select :category_id, Category.all, :id, :title, html: {class: "form-control"} %>
+
+
+
+ <%#= f.label :tag_ids %>
+ <%#= f.collection_check_boxes :tag_ids, Tag.all, :id, :name %>
+
+
+
+ <%= f.label "Collaborators" %>
+
+
+ <% users = @post.persisted? ? User.where(["id != ?",@post.user.id]) : User.where(["id != ?", current_user.id]) %>
+ <%= f.collection_check_boxes :collaborating_user_ids, users, :id,:full_name %>
+
+
+
+ <%= f.submit "Submit!", :class => "submit-button" %>
+
<% end %>
diff --git a/app/views/posts/_info.html.erb b/app/views/posts/_info.html.erb
new file mode 100644
index 0000000..0b5c4bc
--- /dev/null
+++ b/app/views/posts/_info.html.erb
@@ -0,0 +1,7 @@
+<% if @post.likes.length == 1 %>
+ <%= @post.likes.length %> Like,
+<% else %>
+ <%= @post.likes.length %> Likes,
+<% end %>
+
+Vote Popularity: <%= @post.vote_result %>
diff --git a/app/views/posts/_options.html.erb b/app/views/posts/_options.html.erb
new file mode 100644
index 0000000..e69a16d
--- /dev/null
+++ b/app/views/posts/_options.html.erb
@@ -0,0 +1,10 @@
+
+ <% if can?(:edit, @post) %>
+
[Post Options]
+ <%= link_to "Edit", edit_post_path(@post) %> ::
+ <% end %>
+
+ <% if can?(:destroy, @post) %>
+ <%= link_to "Delete", post_path(@post), method: :delete, data: {confirm: "Are you sure you wanto delete this?"} %>
+ <% end %>
+
diff --git a/app/views/posts/edit.html.erb b/app/views/posts/edit.html.erb
index 7bf1894..bff28d4 100644
--- a/app/views/posts/edit.html.erb
+++ b/app/views/posts/edit.html.erb
@@ -1,4 +1,5 @@
-Edit Post:
-
-
-<%= render "form" %>
+
+
Edit Post:
+
+ <%= render "form" %>
+
diff --git a/app/views/posts/new.html.erb b/app/views/posts/new.html.erb
index f176ce2..553deaa 100644
--- a/app/views/posts/new.html.erb
+++ b/app/views/posts/new.html.erb
@@ -1,5 +1,5 @@
-<%# Ability to view a page with a form to create a new post %>
-<%# Ability to click "submit" on the form and create the post %>
-New Post:
-
-<%= render "form" %>
+
+
New Post:
+
+ <%= render "form" %>
+
diff --git a/app/views/posts/show.html.erb b/app/views/posts/show.html.erb
index aa657fc..58a93ae 100644
--- a/app/views/posts/show.html.erb
+++ b/app/views/posts/show.html.erb
@@ -1,136 +1,54 @@
-
<%= @post.title %>
-
Created on: <%= formatted_date(@post.created_at) %>
- <% if @post.user %>
- by <%= @post.user.full_name %>
- <% end %>
-
<%= @post.body %>
-
-
- <% if can?(:edit, @post) %>
-
- [Post Options]
- <%= link_to "Edit", edit_post_path(@post) %> ::
- <% end %>
- <% if can?(:destroy, @post) %>
- <%= link_to "Delete", post_path(@post), method: :delete, data: {confirm: "Are you sure you wanto delete this?"} %>
- <% end %>
+
<%= @post.title %>
+
+ Created on: <%= formatted_date(@post.created_at) %> by <%= @post.user.full_name %>
-
-
- Collaborator(s):
-
- <% @post.collaborating_users.each do |user| %>
- - <%= user.full_name %>
+
+ Tags:
+ <% @post.tag_ids.each do |p| %>
+ <%= Tag.find(p).name %>,
<% end %>
-
+
+
-
+
<%= @post.body %>
- <% if @post.likes.length == 1 %>
- <%= @post.likes.length %> Like,
- <% else %>
- <%= @post.likes.length %> Likes,
- <% end %>
+ <%= render "options" %>
- Vote Popularity: <%= @post.vote_result %>
+
+ <%= render "collaborators" %>
-
-
+
diff --git a/app/views/users/_form.html.erb b/app/views/users/_form.html.erb
new file mode 100644
index 0000000..bd3bd75
--- /dev/null
+++ b/app/views/users/_form.html.erb
@@ -0,0 +1,48 @@
+<% if @user.errors.any? %>
+
+ <% @user.errors.full_messages.each do |msg| %>
+ - <%= msg %>
+
+ <% end %>
+<% end %>
+
+<%= simple_form_for @user, url: user_path, html: {class: "form-horizontal"} do |f| %>
+
+ <%= f.input :first_name, input_html: {placeholder: "e.g. Carlos"} %>
+
+
+
+ <%= f.input :last_name %>
+
+
+
+ <%= f.input :email %>
+
+
+
+ <%= f.input :avatar %>
+
+
+
+
+
+
+
+ <%= f.input :password_confirmation %>
+
+
+
+ <%= f.submit class: "submit-button" %>
+
+
+<% end %>
diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb
new file mode 100644
index 0000000..fe50172
--- /dev/null
+++ b/app/views/users/edit.html.erb
@@ -0,0 +1,4 @@
+
+
Edit Information
+ <%= render "form" %>
+
diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb
index d686285..97f67ce 100644
--- a/app/views/users/new.html.erb
+++ b/app/views/users/new.html.erb
@@ -1,40 +1,5 @@
-
Register
+
+
Register
-<% if @user.errors.any? %>
-
- <% @user.errors.full_messages.each do |msg| %>
- - <%= msg %>
-
- <% end %>
-<% end %>
-
-
-<%= form_for @user do |f| %>
-
-| <%= f.label :first_name %>
- | <%= f.text_field :first_name %>
- |
-
-
-| <%= f.label :last_name%>
- | <%= f.text_field :last_name %>
- |
-
-
-| <%= f.label :email %>
- | <%= f.text_field :email %>
- |
-
-
-| <%= f.label :password %>
- | <%= f.password_field :password %>
- |
-
-
-| <%= f.label :password_confirmation, "Re-type PW" %>
- | <%= f.password_field :password_confirmation %>
- |
-
-<%= f.submit %>
-
-<% end %>
+ <%= render "form" %>
+
diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb
new file mode 100644
index 0000000..1da7a19
--- /dev/null
+++ b/app/views/users/show.html.erb
@@ -0,0 +1,16 @@
+
+
<%= @user.full_name %>
+
+
Recent 5 Posts Created:
+
+ <% @user.recent_five_made.each do |post| %>
+ - <%= link_to post.title, post_path(post) %>
+ <% end %>
+
+
+
Recent 5 Posts Joined
+
+ <% @user.recent_five_joins.each do |post| %>
+ - <%= link_to post.title, post_path(post) %>
+ <% end %>
+
diff --git a/bin/delayed_job b/bin/delayed_job
new file mode 100755
index 0000000..edf1959
--- /dev/null
+++ b/bin/delayed_job
@@ -0,0 +1,5 @@
+#!/usr/bin/env ruby
+
+require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
+require 'delayed/command'
+Delayed::Command.new(ARGV).daemonize
diff --git a/config/application.rb b/config/application.rb
index 5d45ded..f19e5cd 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -17,6 +17,8 @@
module RailsBlog
class Application < Rails::Application
+ config.active_job.queue_adapter = :delayed_job
+
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
diff --git a/config/initializers/setup_mailer.rb b/config/initializers/setup_mailer.rb
new file mode 100644
index 0000000..d7eb465
--- /dev/null
+++ b/config/initializers/setup_mailer.rb
@@ -0,0 +1,8 @@
+ActionMailer::Base.smtp_settings = {
+ address: "smtp.gmail.com",
+ port: "587",
+ enable_starttls_auto: true,
+ authentication: :plain,
+ user_name: ENV["email_user_name"],
+ password: ENV["email_password"]
+}
diff --git a/config/initializers/simple_form.rb b/config/initializers/simple_form.rb
new file mode 100644
index 0000000..d5492e5
--- /dev/null
+++ b/config/initializers/simple_form.rb
@@ -0,0 +1,166 @@
+# Use this setup block to configure all options available in SimpleForm.
+SimpleForm.setup do |config|
+ # Wrappers are used by the form builder to generate a
+ # complete input. You can remove any component from the
+ # wrapper, change the order or even add your own to the
+ # stack. The options given below are used to wrap the
+ # whole input.
+ config.wrappers :default, class: :input,
+ hint_class: :field_with_hint, error_class: :field_with_errors do |b|
+ ## Extensions enabled by default
+ # Any of these extensions can be disabled for a
+ # given input by passing: `f.input EXTENSION_NAME => false`.
+ # You can make any of these extensions optional by
+ # renaming `b.use` to `b.optional`.
+
+ # Determines whether to use HTML5 (:email, :url, ...)
+ # and required attributes
+ b.use :html5
+
+ # Calculates placeholders automatically from I18n
+ # You can also pass a string as f.input placeholder: "Placeholder"
+ b.use :placeholder
+
+ ## Optional extensions
+ # They are disabled unless you pass `f.input EXTENSION_NAME => true`
+ # to the input. If so, they will retrieve the values from the model
+ # if any exists. If you want to enable any of those
+ # extensions by default, you can change `b.optional` to `b.use`.
+
+ # Calculates maxlength from length validations for string inputs
+ b.optional :maxlength
+
+ # Calculates pattern from format validations for string inputs
+ b.optional :pattern
+
+ # Calculates min and max from length validations for numeric inputs
+ b.optional :min_max
+
+ # Calculates readonly automatically from readonly attributes
+ b.optional :readonly
+
+ ## Inputs
+ b.use :label_input
+ b.use :hint, wrap_with: { tag: :span, class: :hint }
+ b.use :error, wrap_with: { tag: :span, class: :error }
+
+ ## full_messages_for
+ # If you want to display the full error message for the attribute, you can
+ # use the component :full_error, like:
+ #
+ # b.use :full_error, wrap_with: { tag: :span, class: :error }
+ end
+
+ # The default wrapper to be used by the FormBuilder.
+ config.default_wrapper = :default
+
+ # Define the way to render check boxes / radio buttons with labels.
+ # Defaults to :nested for bootstrap config.
+ # inline: input + label
+ # nested: label > input
+ config.boolean_style = :nested
+
+ # Default class for buttons
+ config.button_class = 'btn'
+
+ # Method used to tidy up errors. Specify any Rails Array method.
+ # :first lists the first message for each field.
+ # Use :to_sentence to list all errors for each field.
+ # config.error_method = :first
+
+ # Default tag used for error notification helper.
+ config.error_notification_tag = :div
+
+ # CSS class to add for error notification helper.
+ config.error_notification_class = 'error_notification'
+
+ # ID to add for error notification helper.
+ # config.error_notification_id = nil
+
+ # Series of attempts to detect a default label method for collection.
+ # config.collection_label_methods = [ :to_label, :name, :title, :to_s ]
+
+ # Series of attempts to detect a default value method for collection.
+ # config.collection_value_methods = [ :id, :to_s ]
+
+ # You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none.
+ # config.collection_wrapper_tag = nil
+
+ # You can define the class to use on all collection wrappers. Defaulting to none.
+ # config.collection_wrapper_class = nil
+
+ # You can wrap each item in a collection of radio/check boxes with a tag,
+ # defaulting to :span. Please note that when using :boolean_style = :nested,
+ # SimpleForm will force this option to be a label.
+ # config.item_wrapper_tag = :span
+
+ # You can define a class to use in all item wrappers. Defaulting to none.
+ # config.item_wrapper_class = nil
+
+ # How the label text should be generated altogether with the required text.
+ # config.label_text = lambda { |label, required, explicit_label| "#{required} #{label}" }
+
+ # You can define the class to use on all labels. Default is nil.
+ # config.label_class = nil
+
+ # You can define the default class to be used on forms. Can be overriden
+ # with `html: { :class }`. Defaulting to none.
+ # config.default_form_class = nil
+
+ # You can define which elements should obtain additional classes
+ # config.generate_additional_classes_for = [:wrapper, :label, :input]
+
+ # Whether attributes are required by default (or not). Default is true.
+ # config.required_by_default = true
+
+ # Tell browsers whether to use the native HTML5 validations (novalidate form option).
+ # These validations are enabled in SimpleForm's internal config but disabled by default
+ # in this configuration, which is recommended due to some quirks from different browsers.
+ # To stop SimpleForm from generating the novalidate option, enabling the HTML5 validations,
+ # change this configuration to true.
+ config.browser_validations = false
+
+ # Collection of methods to detect if a file type was given.
+ # config.file_methods = [ :mounted_as, :file?, :public_filename ]
+
+ # Custom mappings for input types. This should be a hash containing a regexp
+ # to match as key, and the input type that will be used when the field name
+ # matches the regexp as value.
+ # config.input_mappings = { /count/ => :integer }
+
+ # Custom wrappers for input types. This should be a hash containing an input
+ # type as key and the wrapper that will be used for all inputs with specified type.
+ # config.wrapper_mappings = { string: :prepend }
+
+ # Namespaces where SimpleForm should look for custom input classes that
+ # override default inputs.
+ # config.custom_inputs_namespaces << "CustomInputs"
+
+ # Default priority for time_zone inputs.
+ # config.time_zone_priority = nil
+
+ # Default priority for country inputs.
+ # config.country_priority = nil
+
+ # When false, do not use translations for labels.
+ # config.translate_labels = true
+
+ # Automatically discover new inputs in Rails' autoload path.
+ # config.inputs_discovery = true
+
+ # Cache SimpleForm inputs discovery
+ # config.cache_discovery = !Rails.env.development?
+
+ # Default class for inputs
+ # config.input_class = nil
+
+ # Define the default class of the input wrapper of the boolean input.
+ config.boolean_label_class = 'checkbox'
+
+ # Defines if the default input wrapper class should be included in radio
+ # collection wrappers.
+ # config.include_default_input_wrapper_class = true
+
+ # Defines which i18n scope will be used in Simple Form.
+ # config.i18n_scope = 'simple_form'
+end
diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml
new file mode 100644
index 0000000..2374383
--- /dev/null
+++ b/config/locales/simple_form.en.yml
@@ -0,0 +1,31 @@
+en:
+ simple_form:
+ "yes": 'Yes'
+ "no": 'No'
+ required:
+ text: 'required'
+ mark: '*'
+ # You can uncomment the line below if you need to overwrite the whole required html.
+ # When using html, text and mark won't be used.
+ # html: '
*'
+ error_notification:
+ default_message: "Please review the problems below:"
+ # Examples
+ # labels:
+ # defaults:
+ # password: 'Password'
+ # user:
+ # new:
+ # email: 'E-mail to sign in.'
+ # edit:
+ # email: 'E-mail.'
+ # hints:
+ # defaults:
+ # username: 'User name to sign in.'
+ # password: 'No special characters, please.'
+ # include_blanks:
+ # defaults:
+ # age: 'Rather not say'
+ # prompts:
+ # defaults:
+ # age: 'Select your age'
diff --git a/config/routes.rb b/config/routes.rb
index 4902941..94cc82f 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,11 +1,6 @@
Rails.application.routes.draw do
- resources :users, except: [:edit, :update] do
- get :edit, on: :collection
-
- patch :update, on: :collection
-
- end
+ resources :users
resources :categories
@@ -13,6 +8,7 @@
resources :comments
resources :likes, only: [:create, :destroy]
resources :votes, only: [:create, :destroy, :update]
+ resources :favourites, only: [:create, :destroy]
resources :collaborations
end
@@ -24,4 +20,7 @@
get "/about" => "homes#about"
+ match "/delayed_job" => DelayedJobWeb, :anchor => false, via: [:get, :post]
+
+
end
diff --git a/db/migrate/20150630021324_add_avatar_to_users.rb b/db/migrate/20150630021324_add_avatar_to_users.rb
new file mode 100644
index 0000000..7b4de37
--- /dev/null
+++ b/db/migrate/20150630021324_add_avatar_to_users.rb
@@ -0,0 +1,5 @@
+class AddAvatarToUsers < ActiveRecord::Migration
+ def change
+ add_column :users, :avatar, :string
+ end
+end
diff --git a/db/migrate/20150701011946_create_favourites.rb b/db/migrate/20150701011946_create_favourites.rb
new file mode 100644
index 0000000..bf98360
--- /dev/null
+++ b/db/migrate/20150701011946_create_favourites.rb
@@ -0,0 +1,10 @@
+class CreateFavourites < ActiveRecord::Migration
+ def change
+ create_table :favourites do |t|
+ t.references :user, index: true, foreign_key: true
+ t.references :post, index: true, foreign_key: true
+
+ t.timestamps null: false
+ end
+ end
+end
diff --git a/db/migrate/20150701022427_create_delayed_jobs.rb b/db/migrate/20150701022427_create_delayed_jobs.rb
new file mode 100644
index 0000000..27fdcf6
--- /dev/null
+++ b/db/migrate/20150701022427_create_delayed_jobs.rb
@@ -0,0 +1,22 @@
+class CreateDelayedJobs < ActiveRecord::Migration
+ def self.up
+ create_table :delayed_jobs, force: true do |table|
+ table.integer :priority, default: 0, null: false # Allows some jobs to jump to the front of the queue
+ table.integer :attempts, default: 0, null: false # Provides for retries, but still fail eventually.
+ table.text :handler, null: false # YAML-encoded string of the object that will do work
+ table.text :last_error # reason for last failure (See Note below)
+ table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future.
+ table.datetime :locked_at # Set when a client is working on this object
+ table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
+ table.string :locked_by # Who is working on this object (if locked)
+ table.string :queue # The name of the queue this job is in
+ table.timestamps null: true
+ end
+
+ add_index :delayed_jobs, [:priority, :run_at], name: "delayed_jobs_priority"
+ end
+
+ def self.down
+ drop_table :delayed_jobs
+ end
+end
diff --git a/db/migrate/20150703005252_add_image_to_post.rb b/db/migrate/20150703005252_add_image_to_post.rb
new file mode 100644
index 0000000..4e159e6
--- /dev/null
+++ b/db/migrate/20150703005252_add_image_to_post.rb
@@ -0,0 +1,5 @@
+class AddImageToPost < ActiveRecord::Migration
+ def change
+ add_column :posts, :image, :string
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 8d40ae6..3485fe2 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: 20150625023057) do
+ActiveRecord::Schema.define(version: 20150703005252) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -52,6 +52,32 @@
t.datetime "updated_at", null: false
end
+ create_table "delayed_jobs", force: :cascade do |t|
+ t.integer "priority", default: 0, null: false
+ t.integer "attempts", default: 0, null: false
+ t.text "handler", null: false
+ t.text "last_error"
+ t.datetime "run_at"
+ t.datetime "locked_at"
+ t.datetime "failed_at"
+ t.string "locked_by"
+ t.string "queue"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ add_index "delayed_jobs", ["priority", "run_at"], name: "delayed_jobs_priority", using: :btree
+
+ create_table "favourites", force: :cascade do |t|
+ t.integer "user_id"
+ t.integer "post_id"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
+ add_index "favourites", ["post_id"], name: "index_favourites_on_post_id", using: :btree
+ add_index "favourites", ["user_id"], name: "index_favourites_on_user_id", using: :btree
+
create_table "likes", force: :cascade do |t|
t.integer "user_id"
t.integer "post_id"
@@ -69,6 +95,7 @@
t.datetime "updated_at", null: false
t.integer "user_id"
t.integer "category_id"
+ t.string "image"
end
add_index "posts", ["body"], name: "index_posts_on_body", using: :btree
@@ -99,6 +126,7 @@
t.string "password_digest"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
+ t.string "avatar"
end
add_index "users", ["email"], name: "index_users_on_email", using: :btree
@@ -117,6 +145,8 @@
add_foreign_key "collaborations", "posts"
add_foreign_key "collaborations", "users"
add_foreign_key "comments", "users"
+ add_foreign_key "favourites", "posts"
+ add_foreign_key "favourites", "users"
add_foreign_key "likes", "posts"
add_foreign_key "likes", "users"
add_foreign_key "posts", "categories"
diff --git a/db/seeds.rb b/db/seeds.rb
index 4edb1e8..fa0df7b 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -1,7 +1,15 @@
-# This file should contain all the record creation needed to seed the database with its default values.
-# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
-#
-# Examples:
-#
-# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
-# Mayor.create(name: 'Emanuel', city: cities.first)
+100.times do {
+ Post.create(
+ title: Faker::Company.catch_phrase,
+ body: Faker::Lorem.sentence(12)
+ user_id: rand(4)+1
+ category_id: rand(5)+1
+ )
+}
+
+["New Idea", "Recent Events", "Product Review", "Travel", "Random"].each do |name|
+ Category.create(title: name)
+
+["Silly","Too Serious","Shower Thought","Uplifting","Surreal","Inspiring"].each do |name|
+ Tag.create(name: name)
+end
diff --git a/lib/templates/erb/scaffold/_form.html.erb b/lib/templates/erb/scaffold/_form.html.erb
new file mode 100644
index 0000000..201a069
--- /dev/null
+++ b/lib/templates/erb/scaffold/_form.html.erb
@@ -0,0 +1,13 @@
+<%%= simple_form_for(@<%= singular_table_name %>) do |f| %>
+ <%%= f.error_notification %>
+
+
+ <%- attributes.each do |attribute| -%>
+ <%%= f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %> %>
+ <%- end -%>
+
+
+
+ <%%= f.button :submit %>
+
+<%% end %>
diff --git a/public/uploads/post/image/18/red-house-in-the-mountains-nature-hd-wallpaper-1920x1080-22430.jpg b/public/uploads/post/image/18/red-house-in-the-mountains-nature-hd-wallpaper-1920x1080-22430.jpg
new file mode 100644
index 0000000..b08eb6b
Binary files /dev/null and b/public/uploads/post/image/18/red-house-in-the-mountains-nature-hd-wallpaper-1920x1080-22430.jpg differ
diff --git a/public/uploads/post/image/18/resized_image_red-house-in-the-mountains-nature-hd-wallpaper-1920x1080-22430.jpg b/public/uploads/post/image/18/resized_image_red-house-in-the-mountains-nature-hd-wallpaper-1920x1080-22430.jpg
new file mode 100644
index 0000000..8c18711
Binary files /dev/null and b/public/uploads/post/image/18/resized_image_red-house-in-the-mountains-nature-hd-wallpaper-1920x1080-22430.jpg differ
diff --git a/public/uploads/post/image/18/square_thumb_red-house-in-the-mountains-nature-hd-wallpaper-1920x1080-22430.jpg b/public/uploads/post/image/18/square_thumb_red-house-in-the-mountains-nature-hd-wallpaper-1920x1080-22430.jpg
new file mode 100644
index 0000000..752b00b
Binary files /dev/null and b/public/uploads/post/image/18/square_thumb_red-house-in-the-mountains-nature-hd-wallpaper-1920x1080-22430.jpg differ
diff --git a/public/uploads/tmp/1435631091-44997-0966/square_thumb_tree.png b/public/uploads/tmp/1435631091-44997-0966/square_thumb_tree.png
new file mode 100644
index 0000000..4e627ec
Binary files /dev/null and b/public/uploads/tmp/1435631091-44997-0966/square_thumb_tree.png differ
diff --git a/public/uploads/tmp/1435631091-44997-0966/tree.png b/public/uploads/tmp/1435631091-44997-0966/tree.png
new file mode 100644
index 0000000..4e627ec
Binary files /dev/null and b/public/uploads/tmp/1435631091-44997-0966/tree.png differ
diff --git a/public/uploads/user/avatar/3/rick.jpg b/public/uploads/user/avatar/3/rick.jpg
new file mode 100644
index 0000000..6851957
Binary files /dev/null and b/public/uploads/user/avatar/3/rick.jpg differ
diff --git a/public/uploads/user/avatar/3/square_thumb_rick.jpg b/public/uploads/user/avatar/3/square_thumb_rick.jpg
new file mode 100644
index 0000000..f9a437c
Binary files /dev/null and b/public/uploads/user/avatar/3/square_thumb_rick.jpg differ
diff --git a/public/uploads/user/avatar/4/square_thumb_tree.png b/public/uploads/user/avatar/4/square_thumb_tree.png
new file mode 100644
index 0000000..bb0b8e7
Binary files /dev/null and b/public/uploads/user/avatar/4/square_thumb_tree.png differ
diff --git a/public/uploads/user/avatar/4/tree.png b/public/uploads/user/avatar/4/tree.png
new file mode 100644
index 0000000..4e627ec
Binary files /dev/null and b/public/uploads/user/avatar/4/tree.png differ
<%= comment.body %>
+ Posted on: <%= formatted_date(comment.created_at) %> + + + <% if can?(:delete, comment) %> +