diff --git a/Gemfile b/Gemfile index c1f1ee3e2..b268c825d 100644 --- a/Gemfile +++ b/Gemfile @@ -17,7 +17,7 @@ gem 'ffaker' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '~> 5.1.4' # Use sqlite3 as the database for Active Record -gem 'sqlite3' + # Use Puma as the app server gem 'puma', '~> 3.7' # Use SCSS for stylesheets @@ -37,9 +37,16 @@ gem 'jbuilder', '~> 2.5' # gem 'redis', '~> 3.0' # Use ActiveModel has_secure_password # gem 'bcrypt', '~> 3.1.7' - +gem 'bootstrap-sass', '~>3.3.7' # Use Capistrano for deployment # gem 'capistrano-rails', group: :development +gem 'jquery-rails' + +gem 'kaminari' + +group :production do + gem 'pg' +end group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console @@ -51,6 +58,8 @@ group :development, :test do gem 'factory_bot_rails' gem 'shoulda-matchers', '~> 3.1' gem 'rails-controller-testing' + gem 'sqlite3' + end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index e55e9522f..e695f18de 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -41,11 +41,16 @@ GEM addressable (2.5.2) public_suffix (>= 2.0.2, < 4.0) arel (8.0.0) + autoprefixer-rails (8.6.5) + execjs bcrypt (3.1.11) bcrypt (3.1.11-java) bcrypt (3.1.11-x64-mingw32) bcrypt (3.1.11-x86-mingw32) bindex (0.5.0) + bootstrap-sass (3.3.7) + autoprefixer-rails (>= 5.2.1) + sass (>= 3.3.4) builder (3.2.3) byebug (10.0.0) capybara (2.17.0) @@ -97,6 +102,22 @@ GEM jbuilder (2.7.0) activesupport (>= 4.2.0) multi_json (>= 1.2) + jquery-rails (4.3.3) + rails-dom-testing (>= 1, < 3) + railties (>= 4.2.0) + thor (>= 0.14, < 2.0) + kaminari (1.1.1) + activesupport (>= 4.1.0) + kaminari-actionview (= 1.1.1) + kaminari-activerecord (= 1.1.1) + kaminari-core (= 1.1.1) + kaminari-actionview (1.1.1) + actionview + kaminari-core (= 1.1.1) + kaminari-activerecord (1.1.1) + activerecord + kaminari-core (= 1.1.1) + kaminari-core (1.1.1) listen (3.1.5) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) @@ -124,6 +145,9 @@ GEM nokogiri (1.8.1-x86-mingw32) mini_portile2 (~> 2.3.0) orm_adapter (0.5.0) + pg (1.0.0) + pg (1.0.0-x64-mingw32) + pg (1.0.0-x86-mingw32) public_suffix (3.0.1) puma (3.11.2) puma (3.11.2-java) @@ -251,6 +275,7 @@ PLATFORMS x86-mswin32 DEPENDENCIES + bootstrap-sass (~> 3.3.7) byebug capybara (~> 2.13) carrierwave @@ -259,7 +284,10 @@ DEPENDENCIES factory_bot_rails ffaker jbuilder (~> 2.5) + jquery-rails + kaminari listen (>= 3.0.5, < 3.2) + pg puma (~> 3.7) rails (~> 5.1.4) rails-controller-testing diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 46b20359f..8ce53dfbc 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -13,3 +13,5 @@ //= require rails-ujs //= require turbolinks //= require_tree . +//= require jquery +//= require bootstrap-sprockets \ No newline at end of file diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.scss similarity index 92% rename from app/assets/stylesheets/application.css rename to app/assets/stylesheets/application.scss index d05ea0f51..3befa3d45 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.scss @@ -10,6 +10,6 @@ * files in this directory. Styles in this file should be added after the last require_* statement. * It is generally better to create a new file per style scope. * - *= require_tree . - *= require_self */ + @import 'bootstrap-sprockets'; + @import 'bootstrap'; diff --git a/app/assets/stylesheets/style.scss b/app/assets/stylesheets/style.scss new file mode 100644 index 000000000..25a20c212 --- /dev/null +++ b/app/assets/stylesheets/style.scss @@ -0,0 +1,55 @@ +html, body { + width: 100%; + height: 100%; +} + +body { + padding: 0px; + margin: 0px; + font-size: 14px; + line-height: 1.42857143; + color: #333; + background-color: #fff; +} + +* { + box-sizing: border-box; +} + +h1, h2, h3, h4, h5, h6, p { + margin: 0px; + padding: 0px; +} + +ul, ol { + list-style: none; + margin: 0px; + padding: 0px; +} + +a, a:hover, a:focus { + margin: 0px; + padding: 0px; + text-decoration: none; +} + +img { + width: 100%; + height: auto; + display: block; +} + +.container { + width: 85%; + max-width: 1170px; + margin: 0 auto; + position: relative; +} + +.col-left{ + float: left +} + +.col-right{ + float: right +} \ No newline at end of file diff --git a/app/controllers/admin/base_controller.rb b/app/controllers/admin/base_controller.rb index 4a89583f5..3760aed32 100644 --- a/app/controllers/admin/base_controller.rb +++ b/app/controllers/admin/base_controller.rb @@ -1,3 +1,12 @@ class Admin::BaseController < ApplicationController + before_action :authenticate_admin + private + def authenticate_admin + unless current_user.admin? + flash[:alert] = "Not allow" + redirect_to root_path + end + + end end diff --git a/app/controllers/admin/tweets_controller.rb b/app/controllers/admin/tweets_controller.rb index 24a57566c..be0a9a701 100644 --- a/app/controllers/admin/tweets_controller.rb +++ b/app/controllers/admin/tweets_controller.rb @@ -1,7 +1,20 @@ class Admin::TweetsController < Admin::BaseController def index + @tweets = Tweet.all.order(created_at: :desc) end def destroy + + @tweet = Tweet.find(params[:id]) + + @tweet.destroy + redirect_to admin_root_path + flash[:alert] = "tweet has destroyed" + + end + private + def tweet_params + params.require(:tweet).permit(:description) end + end diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 3ba9f0a36..bf6188610 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -1,4 +1,8 @@ class Admin::UsersController < Admin::BaseController + def index + @users = User.all.order(tweets_count: :desc) end + + end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 0da627f1a..0464e2c3b 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,7 +1,16 @@ class ApplicationController < ActionController::Base protect_from_forgery with: :exception + before_action :configure_permitted_parameters, if: :devise_controller? + before_action :authenticate_user! # 請參考 Devise 文件自訂表單後通過 Strong Parameters 的方法 # https://github.com/plataformatec/devise#strong-parameters # 注意有 sign_up 和 account_update 兩種參數要處理 + + protected + + def configure_permitted_parameters + devise_parameter_sanitizer.permit(:sign_up, keys: [:name]) + devise_parameter_sanitizer.permit(:account_update, keys: [:name]) + end end diff --git a/app/controllers/followships_controller.rb b/app/controllers/followships_controller.rb index 05f01b552..fdd001805 100644 --- a/app/controllers/followships_controller.rb +++ b/app/controllers/followships_controller.rb @@ -1,7 +1,25 @@ class FollowshipsController < ApplicationController + def create + @user = User.find(params[:following_id]) + if @user == current_user + flash[:alert] = "can't follow yourself" + else + @followship = current_user.followships.build(following_id: params[:following_id]) + if @followship.save + flash[:notice] = "followed sucessfully" + redirect_back(fallback_location: root_path) + else + flash[:alert] = @followship.errors.full_messages.to_sentence + redirect_back(fallback_location: root_path) + end + end end def destroy + @followship = current_user.followships.where(following_id: params[:id]).first + @followship.destroy + flash[:alert] = "Followship destroyed" + redirect_back(fallback_location: root_path) end end diff --git a/app/controllers/replies_controller.rb b/app/controllers/replies_controller.rb index a9b6a315b..ffe88e688 100644 --- a/app/controllers/replies_controller.rb +++ b/app/controllers/replies_controller.rb @@ -1,9 +1,32 @@ class RepliesController < ApplicationController def index + + @tweet = Tweet.find(params[:tweet_id]) + @replies = @tweet.replies + @reply = Reply.new + @user = @tweet.user + end def create + @tweet = Tweet.find(params[:tweet_id]) + @reply = @tweet.replies.build(reply_params) + @reply.user = current_user + + + if @reply.save + flash[:notice] = "reply successfully" + redirect_to tweet_replies_path + else + flash[:alert] = "fail to reply the tweet" + render :index + end + end + + private + def reply_params + params.require(:reply).permit(:comment, :user_id, :tweet_id) end end diff --git a/app/controllers/tweets_controller.rb b/app/controllers/tweets_controller.rb index ad14115c1..f159ce392 100644 --- a/app/controllers/tweets_controller.rb +++ b/app/controllers/tweets_controller.rb @@ -1,16 +1,41 @@ class TweetsController < ApplicationController def index - @users # 基於測試規格,必須講定變數名稱,請用此變數中存放關注人數 Top 10 的使用者資料 + @tweets = Tweet.all.order(created_at: :desc) + @tweet = Tweet.new + @users = User.all.order(followers_count: :desc).limit(10) # 基於測試規格,必須講定變數名稱,請用此變數中存放關注人數 Top 10 的使用者資料 end def create + @user = current_user + @tweet = @user.tweets.build(tweet_params) + + if @tweet.save + flash[:notice] = 'create a tweet successfully' + redirect_to tweets_path + else + flash[:alert] = 'failed to create a tweet' + render :index + end + end def like + @tweet = Tweet.find(params[:id]) + @tweet.likes.create!(user: current_user) + redirect_to tweets_path end def unlike + @tweet = Tweet.find(params[:id]) + likes = Like.where(tweet: @tweet, user: current_user) + likes.destroy_all + redirect_to tweets_path end + private + + def tweet_params + params.require(:tweet).permit(:description, :user_id) + end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 750e3c6b5..791ea2a97 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,24 +1,54 @@ class UsersController < ApplicationController def tweets + @user = User.find(params[:id]) + @tweet = Tweet.new + @tweets = @user.tweets.all end + + def edit + @user = User.find(params[:id]) + + unless @user == current_user + redirect_to tweets_user_path(@user) + end + end def update + @user = User.find(params[:id]) + @user.update(user_params) + + redirect_to tweets_user_path(@user) end def followings - @followings # 基於測試規格,必須講定變數名稱 + @user = User.find(params[:id]) + @followings = @user.followings.page(params[:page]).per(6).order('followships.created_at DESC') # 基於測試規格,必須講定變數名稱 end def followers - @followers # 基於測試規格,必須講定變數名稱 + @user = User.find(params[:id]) + @followers = @user.followers.page(params[:page]).per(6).order('followships.created_at DESC') # 基於測試規格,必須講定變數名稱 end def likes - @likes # 基於測試規格,必須講定變數名稱 + @user = User.find(params[:id]) + @likes = @user.liked_tweets.page(params[:page]).per(6).order('likes.created_at DESC') # 基於測試規格,必須講定變數名稱 + @tweets = @user.tweets + + + end + + def show + end + private + + def user_params + params.require(:user).permit(:name, :avatar, :introduction) + end end diff --git a/app/models/followship.rb b/app/models/followship.rb index 1aed01396..a7b080e92 100644 --- a/app/models/followship.rb +++ b/app/models/followship.rb @@ -1,4 +1,6 @@ class Followship < ApplicationRecord validates :following_id, uniqueness: { scope: :user_id } + belongs_to :user + belongs_to :following, class_name: "User", counter_cache: :followers_count end diff --git a/app/models/like.rb b/app/models/like.rb index d99b93a32..42d487577 100644 --- a/app/models/like.rb +++ b/app/models/like.rb @@ -1,2 +1,4 @@ class Like < ApplicationRecord + belongs_to :user + belongs_to :tweet, counter_cache: true end diff --git a/app/models/reply.rb b/app/models/reply.rb index bae6f9463..c7f16d932 100644 --- a/app/models/reply.rb +++ b/app/models/reply.rb @@ -1,2 +1,5 @@ class Reply < ApplicationRecord + validates_presence_of :comment + belongs_to :user + belongs_to :tweet, counter_cache: true end diff --git a/app/models/tweet.rb b/app/models/tweet.rb index 6715fada2..214364d44 100644 --- a/app/models/tweet.rb +++ b/app/models/tweet.rb @@ -1,4 +1,16 @@ class Tweet < ApplicationRecord + validates_presence_of :description validates_length_of :description, maximum: 140 + belongs_to :user, counter_cache: true + + has_many :replies, dependent: :destroy + + + has_many :likes, dependent: :destroy + has_many :liked_users, through: :likes, source: :user + + def is_liked?(user) + self.liked_users.include?(user) + end end diff --git a/app/models/user.rb b/app/models/user.rb index 6b05b8c21..72460a801 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -9,6 +9,27 @@ class User < ApplicationRecord # 需要 app/views/devise 裡找到樣板,加上 name 屬性 # 並參考 Devise 文件自訂表單後通過 Strong Parameters 的方法 validates_presence_of :name + validates_uniqueness_of :name # 加上驗證 name 不能重覆 (關鍵字提示: uniqueness) + has_many :tweets, dependent: :destroy + + has_many :replies, dependent: :restrict_with_error + + has_many :followships, dependent: :destroy + has_many :followings, through: :followships + + has_many :inverse_followships, class_name: "Followship",foreign_key: "following_id" + has_many :followers, through: :inverse_followships, source: :user + + has_many :likes, dependent: :destroy + has_many :liked_tweets, through: :likes, source: :tweet + + def admin? + self.role == "admin" + end + + def following?(user) + self.followings.include?(user) + end end diff --git a/app/views/admin/tweets/index.html.erb b/app/views/admin/tweets/index.html.erb new file mode 100644 index 000000000..28305d38e --- /dev/null +++ b/app/views/admin/tweets/index.html.erb @@ -0,0 +1,31 @@ + +
+ +
+

<%= link_to 'User List', admin_users_path %>

+
+ <% @tweets.each do |tweet| %> + +
+
+
+ <%= image_tag tweet.user.avatar, width: "80px"%> +
+
+ @<%= link_to tweet.user.name, tweets_user_path(tweet.user) %> + + , <%= tweet.created_at.strftime("%Y-%m-%d, %H:%M") %> +
+

<%= simple_format(tweet.description)%>

+ <% tweet.replies.each do |reply| %> + <%= reply.comment %> + <% end %> +

<%= link_to 'Reply', tweet_replies_path(tweet.id)%>

+

<%= link_to 'Delete', admin_tweet_path(tweet), method: :delete, data:{confirm: "Are you sure?"} %>

+
+
+
+ <% end %> +
+
+
diff --git a/app/views/admin/users/index.html.erb b/app/views/admin/users/index.html.erb new file mode 100644 index 000000000..ab37fb524 --- /dev/null +++ b/app/views/admin/users/index.html.erb @@ -0,0 +1,24 @@ +
+
+ <% @users.each do |user| %> +
+
    +
  • +
    + <%= image_tag user.avatar,width: "180px", class: "thumbnail" %> +
    +
    +

    <%= link_to user.name, tweets_user_path(user)%>

    + +
    +

    <%= link_to 'Tweet', tweets_user_path(user) %> <%= user.tweets.count %>

    +

    <%= link_to 'Following',followings_user_path(user) %> <%= user.followings.count %>

    +

    <%= link_to 'Follower',followers_user_path(user) %> <%= user.followers.count %>

    +

    <%= link_to 'Like',likes_user_path(user) %> <%= user.likes.count %>

    +
    +
  • +
+
+ <% end %> +
+
\ No newline at end of file diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb index 10ed32a9e..57938ac37 100644 --- a/app/views/devise/registrations/edit.html.erb +++ b/app/views/devise/registrations/edit.html.erb @@ -3,6 +3,11 @@ <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %> <%= devise_error_messages! %> +
+ <%= f.label :name %>
+ <%= f.text_field :name, autofocus: true %> +
+
<%= f.label :email %>
<%= f.email_field :email, autofocus: true, autocomplete: "email" %> diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb index 602803cff..74dd4b95f 100644 --- a/app/views/devise/registrations/new.html.erb +++ b/app/views/devise/registrations/new.html.erb @@ -2,7 +2,11 @@ <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <%= devise_error_messages! %> - + +
+ <%= f.label :name %>
+ <%= f.text_field :name, autofocus: true %> +
<%= f.label :email %>
<%= f.email_field :email, autofocus: true, autocomplete: "email" %> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 952cb7a1b..d30fe304a 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -9,18 +9,45 @@ - <% if current_user %> - <% if current_user&.admin? %> -
  • <%= link_to 'Admin Panel', admin_restaurants_path %>
  • - <% end %> -
  • -
  • <%= link_to('登出', destroy_user_session_path, method: :delete) %>
  • -
  • <%= link_to('修改個人資料', edit_user_path(current_user)) %>
  • -
  • <%= link_to('修改密碼', edit_user_registration_path) %>
  • - <% else %> -
  • <%= link_to('註冊', new_user_registration_path) %>
  • -
  • <%= link_to('登入', new_user_session_path) %>
  • - <% end %> + +

    <%= notice %>

    <%= alert %>

    <%= yield %> diff --git a/app/views/replies/index.html.erb b/app/views/replies/index.html.erb new file mode 100644 index 000000000..fbaa11ccf --- /dev/null +++ b/app/views/replies/index.html.erb @@ -0,0 +1,61 @@ +
    +
    +
    + <%= image_tag @user.avatar, width: "200px"%> +

    @<%= link_to @user.name, tweets_user_path(@tweet) %>

    +

    <%= @user.introduction %>

    + +
    + <%= render partial: "shared/count", locals:{user: @user} %> + <%= link_to "Edit Profile", edit_user_path(current_user), class: "btn btn-primary" %> +
    +
    +

    Tweets

    +
    +
    + @<%= link_to @tweet.user.name, tweets_user_path(@tweet.user) %>, <%= @tweet.created_at.strftime("%Y-%m-%d, %H:%M") %> +
    +

    <%= simple_format(@tweet.description)%>

    + <%= link_to tweet_replies_path(@tweet) do %> + Reply (<%= @tweet.replies.count %>) + <% end %> + + <%= render partial: "shared/like", locals:{tweet: @tweet} %> +
    +
    +

    Replies

    + + <% @replies.each do |reply| %> +
    +
    +
    + <%= image_tag reply.user.avatar, width: "80px"%> +
    +
    +

    @<%= link_to reply.user.name, tweets_user_path(reply.user) %>, <%= reply.created_at.strftime("%Y-%m-%d, %H:%M") %>

    +

    <%= reply.comment %>

    +
    + +
    + +
    +
    + <% end %> +
    + <%= form_for [@tweet,@reply] do |f| %> +
    + <%= f.text_area :comment, rows: "6", class: "form-control"%> +
    +
    + <%= f.submit "Reply", class: "btn btn-primary pull-right" %> +
    + <% end %> +
    + + +
    +
    +
    + + + diff --git a/app/views/shared/_count.html.erb b/app/views/shared/_count.html.erb new file mode 100644 index 000000000..f0008cbe9 --- /dev/null +++ b/app/views/shared/_count.html.erb @@ -0,0 +1,4 @@ +

    <%= link_to 'Tweets',tweets_user_path(user) %> <%= @user.tweets.count %>

    +

    <%= link_to 'Following',followings_user_path(user) %> <%= @user.followings.count %>

    +

    <%= link_to 'Follower', followers_user_path(user) %> <%= @user.followers.count %>

    +

    <%= link_to 'Like', likes_user_path(user) %> <%= @user.likes.count %>

    \ No newline at end of file diff --git a/app/views/shared/_follow.html.erb b/app/views/shared/_follow.html.erb new file mode 100644 index 000000000..8f6d4b9ad --- /dev/null +++ b/app/views/shared/_follow.html.erb @@ -0,0 +1,7 @@ +<% if user != current_user %> + <% if current_user.following?(user) %> + <%= link_to "Unfollow", followship_path(user), method: :delete, class: "btn btn-primary" %> + <% else %> + <%= link_to "Follow", followships_path(following_id: user), method: :post, class: "btn btn-primary" %> + <% end %> +<% end %> \ No newline at end of file diff --git a/app/views/shared/_like.html.erb b/app/views/shared/_like.html.erb new file mode 100644 index 000000000..da8c1bb05 --- /dev/null +++ b/app/views/shared/_like.html.erb @@ -0,0 +1,10 @@ + +<% if tweet.is_liked?(current_user) %> + <%= link_to unlike_tweet_path(tweet),method: :post do %> + Unlike(<%= tweet.likes.count %>) + <% end %> +<% else %> + <%= link_to like_tweet_path(tweet), method: :post do %> + Like (<%= tweet.likes.count %>) + <% end %> +<% end %> diff --git a/app/views/tweets/index.html.erb b/app/views/tweets/index.html.erb new file mode 100644 index 000000000..426b344b6 --- /dev/null +++ b/app/views/tweets/index.html.erb @@ -0,0 +1,65 @@ +
    +
    +
    +
    + <%= form_for [@user, @tweet] do |f| %> +
    + <%= f.text_area :description , rows:"6", placeholder: "What's on your mind?",class: "form-control"%> +
    +
    +
    + <%= f.submit 'Tweet', class: "btn btn-primary pull-right"%> +
    + +
    +
    +
    +
    + <% @tweets.each do |tweet| %> + +
    +
    +
    + <%= image_tag tweet.user.avatar, width: "80px"%> +
    +
    + @<%= link_to tweet.user.name, tweets_user_path(tweet.user) %> + + , <%= tweet.created_at.strftime("%Y-%m-%d, %H:%M") %> +
    +

    <%= simple_format(tweet.description)%>

    + <%= link_to tweet_replies_path(tweet) do%> + Reply (<%= tweet.replies.count %>) + <% end %> + + <%= render partial: "shared/like", locals:{tweet: tweet} %> +
    +
    +
    + <% end %> +
    + <% end %> + +
    + +
    +
    +

    Popular

    + <% @users.each do |user| %> +
    +
    + + <%= image_tag user.avatar, width: "80px"%> +

    @<%= link_to user.name, tweets_user_path(user) %>

    +

    <%= user.introduction %>

    +
    + <%= render partial: "shared/follow",locals: {user: user} %> + +
    +
    + <% end %> + + +
    +
    +
    \ No newline at end of file diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb new file mode 100644 index 000000000..44ee42450 --- /dev/null +++ b/app/views/users/edit.html.erb @@ -0,0 +1,35 @@ +
    +
    +
    + <%= form_for @user do |f| %> +
    + + +
    + <%= image_tag @user.avatar , width: "180px"if @user.avatar? %> + <%= f.file_field :avatar %> + <%= f.label :avatar, "Browse files", class: 'btn btn-primary' %> +
    + +
    +
    + + +
    + <%= f.text_field :name, placeholder: "Name", class: "form-control" %> +
    +
    + <%= f.text_area :introduction, placeholder: "Type anything about you here...", rows: "10", class: "form-control" %> +
    +
    + <%= f.submit 'Update', class: "btn btn-primary pull-right" %> +
    + +
    + <% end %> + + + +
    +
    +
    \ No newline at end of file diff --git a/app/views/users/followers.html.erb b/app/views/users/followers.html.erb new file mode 100644 index 000000000..40e68134c --- /dev/null +++ b/app/views/users/followers.html.erb @@ -0,0 +1,51 @@ +
    +
    +
    + <%= image_tag @user.avatar, width: "80px"%> +

    @<%= link_to @user.name, tweets_user_path(@user) %>

    +

    <%= @user.introduction %>

    + +
    + <%= render partial: "shared/count", locals:{user: current_user} %> + <% if @user.email == current_user.email %> + <%= link_to "Edit Profile", edit_user_path(@user), class: "btn btn-primary" %> + <% end %> + <%= render partial: "shared/follow", locals:{user: @user} %> + + + +
    + +
    +

    Follower

    + <% @followers.each do |user| %> +
    + +
    + +
      +
    • +
      + <%= image_tag user.avatar, width: "120px"%> +
      +
      +

      @<%= link_to user.name, tweets_user_path %>

      + <%= truncate(user.introduction, length: 80) %> + + +
      + <%= render partial: "shared/follow", locals:{user: user} %> +
      +
    • +
    + + + <% end %> +
    +
    + <%= paginate @followers %> +
    + + +
    +
    \ No newline at end of file diff --git a/app/views/users/followings.html.erb b/app/views/users/followings.html.erb new file mode 100644 index 000000000..a77592eb9 --- /dev/null +++ b/app/views/users/followings.html.erb @@ -0,0 +1,55 @@ +
    +
    +
    + <%= image_tag @user.avatar, width: "80px"%> +

    @<%= link_to @user.name, tweets_user_path(@user) %>

    +

    <%= @user.introduction %>

    + +
    + <%= render partial: "shared/count", locals:{user: current_user} %> + <% if @user.email == current_user.email %> + <%= link_to "Edit Profile", edit_user_path(@user), class: "btn btn-primary" %> + <% end %> + <%= render partial: "shared/follow", locals:{user: @user} %> + + + +
    + +
    +

    Following

    + <% @followings.each do |user| %> +
    + +
    + +
      +
    • +
      + <%= image_tag user.avatar, width: "120px"%> +
      +
      +

      @<%= link_to user.name, tweets_user_path %>

      + <%= truncate(user.introduction, length: 80) %> + + +
      +
      +
      + <%= render partial: "shared/follow", locals:{user: user} %> +
      +
    • +
    + + + <% end %> +
    +
    + <%= paginate @followings %> +
    + + +
    +
    + + diff --git a/app/views/users/likes.html.erb b/app/views/users/likes.html.erb new file mode 100644 index 000000000..e56f08f6f --- /dev/null +++ b/app/views/users/likes.html.erb @@ -0,0 +1,43 @@ +
    +
    +
    + <%= image_tag @user.avatar, width: "80px"%> +

    @<%= link_to @user.name, tweets_user_path(@user) %>

    +

    <%= @user.introduction %>

    + +
    + <%= render partial: "shared/count", locals:{user: current_user} %> + <% if @user.email == current_user.email %> + <%= link_to "Edit Profile", edit_user_path(@user), class: "btn btn-primary" %> + <% end %> + <%= render partial: "shared/follow", locals:{user: @user} %> + + + +
    + +
    + <% @likes.each do |tweet| %> +
    +
    +
    + <%= image_tag tweet.user.avatar, width: "120px" %> +
    +
    +

    @<%= link_to tweet.user.name, tweets_user_path(tweet.user) %>, <%= tweet.created_at.strftime("%Y-%m_%d, %H:%M") %>

    +

    <%= tweet.user.introduction %>

    +
    + +
    +
    + + <% end %> +
    + +
    + <%= paginate @likes %> +
    + + +
    +
    \ No newline at end of file diff --git a/app/views/users/tweets.html.erb b/app/views/users/tweets.html.erb new file mode 100644 index 000000000..3c1f4d263 --- /dev/null +++ b/app/views/users/tweets.html.erb @@ -0,0 +1,37 @@ +
    +
    +
    + <%= image_tag @user.avatar, width: "80px"%> +

    @<%= link_to @user.name, tweets_user_path(@user) %> +

    <%= @user.introduction %>

    + +
    + <%= render partial: "shared/count", locals: {user: @user} %> + <% if @user.email == current_user.email %> + <%= link_to "Edit Profile", edit_user_path(@user), class: "btn btn-primary" %> + <% end %> + <%= render partial: "shared/follow", locals: {user: @user} %> +
    +
    + <% @user.tweets.each do |tweet| %> +
    +
    +
    + <%= image_tag tweet.user.avatar,width: "80px" %> +
    +
    +

    @<%= link_to tweet.user.name, tweets_user_path(tweet.user) %>, <%= tweet.created_at.strftime("%Y-%m-%d, %H:%M") %>

    +

    <%= tweet.description %>

    +
    + +
    +
    + + <% end %> +
    +
    +
    + + + + diff --git a/config/database.yml b/config/database.yml index 0d02f2498..1c8d40f2a 100644 --- a/config/database.yml +++ b/config/database.yml @@ -21,5 +21,5 @@ test: database: db/test.sqlite3 production: - <<: *default - database: db/production.sqlite3 + adapter: postgresql + encoding: Unicode diff --git a/config/routes.rb b/config/routes.rb index 90856d4fe..96164f3bd 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -3,5 +3,34 @@ devise_for :users # 請依照專案指定規格來設定路由 + root "tweets#index" + resources :tweets, only:[:index, :create] do + resources :replies, only:[:index, :create] + member do + post :like + post :unlike + end + end + resources :users, only:[:edit, :update] do + member do + get :tweets + + get :likes + + get :followings + + get :followers + + end + end + + + resources :followships, only:[:create, :destroy] + + namespace :admin do + root "tweets#index" + resources :tweets, only:[:index, :destroy] + resources :users, only:[:index] + end end diff --git a/db/migrate/20180724112943_add_tweets_count_to_users.rb b/db/migrate/20180724112943_add_tweets_count_to_users.rb new file mode 100644 index 000000000..abb23c746 --- /dev/null +++ b/db/migrate/20180724112943_add_tweets_count_to_users.rb @@ -0,0 +1,5 @@ +class AddTweetsCountToUsers < ActiveRecord::Migration[5.1] + def change + add_column :users, :tweets_count, :integer, default: 0 + end +end diff --git a/db/schema.rb b/db/schema.rb index 6a6842c86..c4b636a4f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20180201102838) do +ActiveRecord::Schema.define(version: 20180724112943) do create_table "followships", force: :cascade do |t| t.integer "user_id" @@ -66,6 +66,7 @@ t.integer "likes_count", default: 0 t.string "role", default: "normal" t.integer "followers_count", default: 0 + t.integer "tweets_count", default: 0 t.index ["email"], name: "index_users_on_email", unique: true t.index ["name"], name: "index_users_on_name", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true diff --git a/db/seeds.rb b/db/seeds.rb index 1beea2acc..6ae598c5f 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -5,3 +5,6 @@ # # movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }]) # Character.create(name: 'Luke', movie: movies.first) + +User.create(name: "Zion", email: "bone000@gmail.com", password: "zero000", role: "admin") +puts "Default admin created!" \ No newline at end of file diff --git a/lib/tasks/dev.rake b/lib/tasks/dev.rake index 9b1e87ae4..2484d3d51 100644 --- a/lib/tasks/dev.rake +++ b/lib/tasks/dev.rake @@ -20,4 +20,20 @@ namespace :dev do end end + task fake_tweet: :environment do + Tweet.destroy_all + User.all.each do |user| + 5.times do |i| + user.tweets.create!(description: FFaker::LoremCN.sentence, + user: User.all.sample) + end + end + + puts "have created fake tweets" + puts "now you have #{Tweet.count} tweets data" + + + + end + end