From dc1957cc156bec98739ffaf389cf6d5c298c1fcf Mon Sep 17 00:00:00 2001 From: allenpan Date: Wed, 29 Aug 2018 15:38:34 +0800 Subject: [PATCH 01/26] add routes tweets#index and index view for tweets --- app/views/tweets/index.html.erb | 1 + config/routes.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 app/views/tweets/index.html.erb diff --git a/app/views/tweets/index.html.erb b/app/views/tweets/index.html.erb new file mode 100644 index 000000000..83133bd68 --- /dev/null +++ b/app/views/tweets/index.html.erb @@ -0,0 +1 @@ +

Tweet前台

\ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 90856d4fe..1ddef8463 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -3,5 +3,5 @@ devise_for :users # 請依照專案指定規格來設定路由 - + root "tweets#index" end From 342cfb41de41f4edf578f65d3fbc334f6d55be19 Mon Sep 17 00:00:00 2001 From: allenpan Date: Wed, 29 Aug 2018 22:23:12 +0800 Subject: [PATCH 02/26] 1.add user registration name field, 2.authenticate user, only login user can access the page --- app/controllers/application_controller.rb | 11 ++++++++++- app/controllers/tweets_controller.rb | 2 +- app/models/user.rb | 4 +++- app/views/admin/tweets/index.html.erb | 1 + app/views/devise/registrations/edit.html.erb | 8 +++++++- app/views/devise/registrations/new.html.erb | 9 ++++++++- app/views/layouts/application.html.erb | 4 ++-- config/routes.rb | 6 ++++++ spec/controllers/admin/tweets_controller_spec.rb | 5 +++++ spec/helpers/admin/tweets_helper_spec.rb | 15 +++++++++++++++ 10 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 app/views/admin/tweets/index.html.erb create mode 100644 spec/controllers/admin/tweets_controller_spec.rb create mode 100644 spec/helpers/admin/tweets_helper_spec.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 0da627f1a..3ef939bcb 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 + # Devise 客製化屬性的使用說明: https://github.com/plataformatec/devise#strong-parameters + 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/tweets_controller.rb b/app/controllers/tweets_controller.rb index ad14115c1..6417b748e 100644 --- a/app/controllers/tweets_controller.rb +++ b/app/controllers/tweets_controller.rb @@ -1,5 +1,5 @@ class TweetsController < ApplicationController - + def index @users # 基於測試規格,必須講定變數名稱,請用此變數中存放關注人數 Top 10 的使用者資料 end diff --git a/app/models/user.rb b/app/models/user.rb index 6b05b8c21..be13069f4 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -10,5 +10,7 @@ class User < ApplicationRecord # 並參考 Devise 文件自訂表單後通過 Strong Parameters 的方法 validates_presence_of :name # 加上驗證 name 不能重覆 (關鍵字提示: uniqueness) - + def admin? + self.role == "admin" + 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..9edffed8b --- /dev/null +++ b/app/views/admin/tweets/index.html.erb @@ -0,0 +1 @@ +

tweets後台

\ 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..529ec5393 100644 --- a/app/views/devise/registrations/edit.html.erb +++ b/app/views/devise/registrations/edit.html.erb @@ -3,9 +3,15 @@ <%= 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" %> + <%= f.email_field :email, autocomplete: "email" %>
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %> diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb index 602803cff..e1874d569 100644 --- a/app/views/devise/registrations/new.html.erb +++ b/app/views/devise/registrations/new.html.erb @@ -3,9 +3,16 @@ <%= 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" %> + <%= f.email_field :email, autocomplete: "email" %>
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 952cb7a1b..437728e95 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -11,11 +11,11 @@ <% if current_user %> <% if current_user&.admin? %> -
  • <%= link_to 'Admin Panel', admin_restaurants_path %>
  • +
  • <%= link_to 'Admin Panel', admin_root_path %>
  • <% end %>
  • <%= link_to('登出', destroy_user_session_path, method: :delete) %>
  • -
  • <%= link_to('修改個人資料', edit_user_path(current_user)) %>
  • + <%# <%= link_to('修改個人資料', edit_user_path(current_user)) %>
  • <%= link_to('修改密碼', edit_user_registration_path) %>
  • <% else %>
  • <%= link_to('註冊', new_user_registration_path) %>
  • diff --git a/config/routes.rb b/config/routes.rb index 1ddef8463..26c130b42 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -4,4 +4,10 @@ # 請依照專案指定規格來設定路由 root "tweets#index" + + namespace :admin do + resources :tweets, only: [:index, :destroy] + resources :users, only: [:index] + root "tweets#index" + end end diff --git a/spec/controllers/admin/tweets_controller_spec.rb b/spec/controllers/admin/tweets_controller_spec.rb new file mode 100644 index 000000000..56d5404b7 --- /dev/null +++ b/spec/controllers/admin/tweets_controller_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Admin::TweetsController, type: :controller do + +end diff --git a/spec/helpers/admin/tweets_helper_spec.rb b/spec/helpers/admin/tweets_helper_spec.rb new file mode 100644 index 000000000..0c792ac78 --- /dev/null +++ b/spec/helpers/admin/tweets_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the Admin::TweetsHelper. For example: +# +# describe Admin::TweetsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe Admin::TweetsHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end From 863a75ac192163e687b19441084ba1284f0591af Mon Sep 17 00:00:00 2001 From: allenpan Date: Wed, 29 Aug 2018 22:35:43 +0800 Subject: [PATCH 03/26] set up admin authentication --- app/controllers/admin/base_controller.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/controllers/admin/base_controller.rb b/app/controllers/admin/base_controller.rb index 4a89583f5..f80163781 100644 --- a/app/controllers/admin/base_controller.rb +++ b/app/controllers/admin/base_controller.rb @@ -1,3 +1,15 @@ class Admin::BaseController < ApplicationController + before_action :authenticate_user! + before_action :authenticate_admin + + private + + def authenticate_admin + unless current_user.admin? + flash[:alert] = "Not allow!" + redirect_to root_path + end + end + end From 4a8c1ca3137ba0680b919d8a2287bce9ab9fe0bd Mon Sep 17 00:00:00 2001 From: allenpan Date: Wed, 29 Aug 2018 23:54:05 +0800 Subject: [PATCH 04/26] link user and tweet model --- app/models/tweet.rb | 2 +- app/models/user.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/tweet.rb b/app/models/tweet.rb index 6715fada2..7895d54d6 100644 --- a/app/models/tweet.rb +++ b/app/models/tweet.rb @@ -1,4 +1,4 @@ class Tweet < ApplicationRecord validates_length_of :description, maximum: 140 - + belongs_to :user end diff --git a/app/models/user.rb b/app/models/user.rb index be13069f4..37d86b89b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -3,7 +3,7 @@ class User < ApplicationRecord # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable - + has_many :tweets, dependent: :destroy mount_uploader :avatar, AvatarUploader # 需要 app/views/devise 裡找到樣板,加上 name 屬性 From acdd0f4cbfc7b4e5b8fe1e95a2553a2d5989d692 Mon Sep 17 00:00:00 2001 From: allenpan Date: Thu, 30 Aug 2018 01:05:30 +0800 Subject: [PATCH 05/26] add rake tweet --- lib/tasks/dev.rake | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/tasks/dev.rake b/lib/tasks/dev.rake index 9b1e87ae4..bf870a070 100644 --- a/lib/tasks/dev.rake +++ b/lib/tasks/dev.rake @@ -20,4 +20,14 @@ namespace :dev do end end + task fake_tweet: :environment do + 50.times do |i| + Tweet.create!( + description: FFaker::Tweet::body, + user: User.all.sample + ) + end + end + end + \ No newline at end of file From 3e972c3c325e668f187ebdb4b3c4fb6ccd94e4a3 Mon Sep 17 00:00:00 2001 From: allenpan Date: Thu, 30 Aug 2018 13:27:53 +0800 Subject: [PATCH 06/26] 1.add bootstrap gem, and related setting, 2.implement Create action in Tweet Controller --- Gemfile | 2 ++ Gemfile.lock | 11 ++++++++++ app/assets/javascripts/application.js | 2 ++ .../{application.css => application.scss} | 4 ++-- app/controllers/tweets_controller.rb | 22 +++++++++++++++++-- app/views/tweets/index.html.erb | 15 ++++++++++++- config/routes.rb | 1 + 7 files changed, 52 insertions(+), 5 deletions(-) rename app/assets/stylesheets/{application.css => application.scss} (92%) diff --git a/Gemfile b/Gemfile index c1f1ee3e2..df19038c9 100644 --- a/Gemfile +++ b/Gemfile @@ -20,6 +20,7 @@ gem 'rails', '~> 5.1.4' gem 'sqlite3' # Use Puma as the app server gem 'puma', '~> 3.7' +gem 'bootstrap-sass', '~> 3.3.7' # Use SCSS for stylesheets gem 'sass-rails', '~> 5.0' # Use Uglifier as compressor for JavaScript assets @@ -40,6 +41,7 @@ gem 'jbuilder', '~> 2.5' # Use Capistrano for deployment # gem 'capistrano-rails', group: :development +gem 'jquery-rails' group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console diff --git a/Gemfile.lock b/Gemfile.lock index 3b212e9b7..c32097096 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 (9.1.3) + execjs bcrypt (3.1.12) bcrypt (3.1.12-java) bcrypt (3.1.12-x64-mingw32) bcrypt (3.1.12-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.2) capybara (2.18.0) @@ -97,6 +102,10 @@ 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) listen (3.1.5) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) @@ -251,6 +260,7 @@ PLATFORMS x86-mswin32 DEPENDENCIES + bootstrap-sass (~> 3.3.7) byebug capybara (~> 2.13) carrierwave @@ -259,6 +269,7 @@ DEPENDENCIES factory_bot_rails ffaker jbuilder (~> 2.5) + jquery-rails listen (>= 3.0.5, < 3.2) puma (~> 3.7) rails (~> 5.1.4) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 46b20359f..38d5802a2 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 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..ff522f71d 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"; \ No newline at end of file diff --git a/app/controllers/tweets_controller.rb b/app/controllers/tweets_controller.rb index 6417b748e..0df09947c 100644 --- a/app/controllers/tweets_controller.rb +++ b/app/controllers/tweets_controller.rb @@ -1,10 +1,21 @@ class TweetsController < ApplicationController - + def index - @users # 基於測試規格,必須講定變數名稱,請用此變數中存放關注人數 Top 10 的使用者資料 + + @tweet = Tweet.new + end def create + @tweet = Tweet.new(tweet_params) + @tweet.user = current_user + if @tweet.save + flash[:notice] = "You Tweet was successfully created" + redirect_to root_path + else + flash.now[:alert] = "Your Tweet was failed to create" + render :index + end end def like @@ -13,4 +24,11 @@ def like def unlike end + + private + + def tweet_params + params.require(:tweet).permit(:description) + end + end diff --git a/app/views/tweets/index.html.erb b/app/views/tweets/index.html.erb index 83133bd68..2a0b62d65 100644 --- a/app/views/tweets/index.html.erb +++ b/app/views/tweets/index.html.erb @@ -1 +1,14 @@ -

    Tweet前台

    \ No newline at end of file +

    Tweet前台

    + +
    +
    + <%= form_for [@tweet] do |f| %> +
    + <%= f.text_area :description, placeholder: "What's on your mind?", class: "form-control" %> +
    +
    + <%= f.submit 'Tweet', class: "btn btn-primary" %> +
    + <% end %> +
    +
    \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 26c130b42..b3f98a731 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -3,6 +3,7 @@ devise_for :users # 請依照專案指定規格來設定路由 + resources :tweets root "tweets#index" namespace :admin do From dfbfe5e43ff17673c192ba1d5783664ac3f90d71 Mon Sep 17 00:00:00 2001 From: allenpan Date: Thu, 30 Aug 2018 16:58:16 +0800 Subject: [PATCH 07/26] add style.scss, display tweet item in index.html --- app/assets/stylesheets/application.scss | 3 +- app/assets/stylesheets/style.scss | 25 ++++++++++++++++ app/controllers/tweets_controller.rb | 4 +-- app/views/tweets/index.html.erb | 39 ++++++++++++++++++------- 4 files changed, 58 insertions(+), 13 deletions(-) create mode 100644 app/assets/stylesheets/style.scss diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index ff522f71d..68e7bddea 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -12,4 +12,5 @@ * */ @import "bootstrap-sprockets"; -@import "bootstrap"; \ No newline at end of file +@import "bootstrap"; +@import 'style' \ No newline at end of file diff --git a/app/assets/stylesheets/style.scss b/app/assets/stylesheets/style.scss new file mode 100644 index 000000000..c9fd638ea --- /dev/null +++ b/app/assets/stylesheets/style.scss @@ -0,0 +1,25 @@ + +.form-style{ +border:2px grey solid; +border-radius: 10px; +margin: 10px; +} + +.button-tweet{ + border-radius: 5px; + padding: 5px 15px; + margin-right: 0px; + margin-bottom: 10px; +} + +.tweet-item{ + margin: 10px; + border: 1px solid #ddd; + padding: 10px 10px; +} + + +.tweet-avatar{ + margin: 0px 10px 10px 10px; + width: 60px; +} diff --git a/app/controllers/tweets_controller.rb b/app/controllers/tweets_controller.rb index 0df09947c..d86929bab 100644 --- a/app/controllers/tweets_controller.rb +++ b/app/controllers/tweets_controller.rb @@ -1,9 +1,9 @@ class TweetsController < ApplicationController def index - + @tweets = Tweet.all @tweet = Tweet.new - + @users = User.order(followers_count: :desc).limit(10)# 基於測試規格,必須講定變數名稱,請用此變數中存放關注人數 Top 10 的使用者資料 end def create diff --git a/app/views/tweets/index.html.erb b/app/views/tweets/index.html.erb index 2a0b62d65..a480f8d40 100644 --- a/app/views/tweets/index.html.erb +++ b/app/views/tweets/index.html.erb @@ -1,14 +1,33 @@ -

    Tweet前台

    -
    - <%= form_for [@tweet] do |f| %> -
    - <%= f.text_area :description, placeholder: "What's on your mind?", class: "form-control" %> -
    -
    - <%= f.submit 'Tweet', class: "btn btn-primary" %> +
    +
    + <%= form_for [@tweet] do |f| %> +
    + <%= f.text_area :description, placeholder: "What's on your mind?", class: "form-control form-style", style: 'height: 150px' %> + + <%= f.submit 'Tweet', class: "navbar-right btn btn-primary button-tweet" %> +
    + <% end %>
    - <% end %> + + <% @tweets.each do |tweet| %> +
    +
    +
    + <%= image_tag tweet.user.avatar , class: "tweet-avatar"%> +
    +
    +

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

    +

    <%= tweet.description %>

    +
    +
    +
    + <% end %> +
    +
    +
    -
    \ No newline at end of file +
    + From 6f64d515afa98a6eb7dfd5387a95d3f7ea9b5c3d Mon Sep 17 00:00:00 2001 From: allenpan Date: Thu, 30 Aug 2018 17:27:46 +0800 Subject: [PATCH 08/26] implement display popular user in index.html --- app/views/tweets/index.html.erb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/views/tweets/index.html.erb b/app/views/tweets/index.html.erb index a480f8d40..8d95cfafd 100644 --- a/app/views/tweets/index.html.erb +++ b/app/views/tweets/index.html.erb @@ -27,6 +27,19 @@ <% end %>
    +

    Popular

    + <% @users.each do |user| %> +
    +
    + <%= image_tag user.avatar , class: "tweet-avatar"%> +
    +
    +

    @<%= user.name %> +

    +

    <%= user.introduction %>

    +
    +
    + <% end %>
    From d509d3eac79eff89c4465a2e4984d684ed99d78a Mon Sep 17 00:00:00 2001 From: allenpan Date: Thu, 30 Aug 2018 23:14:39 +0800 Subject: [PATCH 09/26] add nav bar icon and content --- app/assets/stylesheets/style.scss | 13 ++++- app/views/layouts/application.html.erb | 69 +++++++++++++++++++++----- config/routes.rb | 10 ++++ 3 files changed, 77 insertions(+), 15 deletions(-) diff --git a/app/assets/stylesheets/style.scss b/app/assets/stylesheets/style.scss index c9fd638ea..9d3b2f11a 100644 --- a/app/assets/stylesheets/style.scss +++ b/app/assets/stylesheets/style.scss @@ -20,6 +20,15 @@ margin: 10px; .tweet-avatar{ - margin: 0px 10px 10px 10px; - width: 60px; + margin: 0px 0px 0px 0px; + width: 50px; +} + +.nav-avatar{ + padding: 0px 0px; + margin: 0px 0px; +} + +.navbar-nav > li > a { + padding: 0px 0px; } diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 437728e95..a781ba2f8 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -9,20 +9,63 @@ - <% if current_user %> - <% if current_user&.admin? %> -
  • <%= link_to 'Admin Panel', admin_root_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) %>
  • + + + + <% if flash[:notice] %> +
    +
    + +
    +
    + <% end %> + + <% if flash[:alert] %> +
    +
    + +
    +
    <% end %> -

    <%= notice %>

    -

    <%= alert %>

    + <%= yield %> diff --git a/config/routes.rb b/config/routes.rb index b3f98a731..6f96418f5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -3,6 +3,16 @@ devise_for :users # 請依照專案指定規格來設定路由 + resources :users, only: [:edit, :update] do + member do + get :tweets + get :followings + get :followers + get :likes + post :like + end + end + resources :tweets root "tweets#index" From 6175ecb67c93ef92b4be9bcf812cb272f02cc273 Mon Sep 17 00:00:00 2001 From: allenpan Date: Fri, 31 Aug 2018 01:31:58 +0800 Subject: [PATCH 10/26] add follow/unfollow function & user's tweets index page --- app/assets/stylesheets/style.scss | 5 ++++ app/controllers/followships_controller.rb | 13 +++++++++ app/controllers/users_controller.rb | 2 ++ app/models/followship.rb | 2 ++ app/models/user.rb | 12 ++++++++- app/views/shared/_user_info.html.erb | 33 +++++++++++++++++++++++ app/views/tweets/index.html.erb | 2 +- app/views/users/tweets.html.erb | 22 +++++++++++++++ config/routes.rb | 2 ++ 9 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 app/views/shared/_user_info.html.erb create mode 100644 app/views/users/tweets.html.erb diff --git a/app/assets/stylesheets/style.scss b/app/assets/stylesheets/style.scss index 9d3b2f11a..a559db709 100644 --- a/app/assets/stylesheets/style.scss +++ b/app/assets/stylesheets/style.scss @@ -32,3 +32,8 @@ margin: 10px; .navbar-nav > li > a { padding: 0px 0px; } + +.user-avatar{ + margin: 0px 0px 0px 0px; + width: 200px +} diff --git a/app/controllers/followships_controller.rb b/app/controllers/followships_controller.rb index 05f01b552..5a1713cea 100644 --- a/app/controllers/followships_controller.rb +++ b/app/controllers/followships_controller.rb @@ -1,7 +1,20 @@ class FollowshipsController < ApplicationController def create + @followship = current_user.followships.build(following_id: params[:following_id]) + + if @followship.save + flash[:notice] = "Successfilly followed" + redirect_back(fallback_location: tweets_user_path(params[:following_id])) + else + flash[:alert] = @followship.errors.full_messages.to_sentence + redirect_back(fallback_location: tweets_user_path(params[:following_id])) + end end def destroy + @followship = current_user.followships.where(following_id: params[:id]).first + @followship.destroy + flash[:alert] = "Followship destroyed" + redirect_back(fallback_location: tweets_user_path(params[:id])) end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 750e3c6b5..ae7eda5f6 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,6 +1,8 @@ class UsersController < ApplicationController def tweets + @user = User.find(params[:id]) + @tweets = @user.tweets end def edit diff --git a/app/models/followship.rb b/app/models/followship.rb index 1aed01396..d21c6439f 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/user.rb b/app/models/user.rb index 37d86b89b..edabcd8b5 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -3,7 +3,13 @@ class User < ApplicationRecord # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable - has_many :tweets, dependent: :destroy + has_many :tweets, dependent: :destroy + 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 + mount_uploader :avatar, AvatarUploader # 需要 app/views/devise 裡找到樣板,加上 name 屬性 @@ -13,4 +19,8 @@ class User < ApplicationRecord def admin? self.role == "admin" end + + def following?(user) + self.followings.include?(user) + end end diff --git a/app/views/shared/_user_info.html.erb b/app/views/shared/_user_info.html.erb new file mode 100644 index 000000000..2b54201ae --- /dev/null +++ b/app/views/shared/_user_info.html.erb @@ -0,0 +1,33 @@ +
    + <%= image_tag user.avatar, class: "img-responsive img-rounded user-avatar" if user.avatar? %> +

    <%= user.name %>

    +

    <%= user.introduction %>

    + <%= link_to tweets_user_path(user) do %> +

    Tweets <%= user.tweets.count %>

    + <% end %> + + <%= link_to followings_user_path(user) do %> +

    Following <%= user.followships.count %>

    + <% end %> + + <%= link_to followers_user_path(user) do %> +

    Follower <%= user.followers_count %>

    + <% end %> + + <%= link_to likes_user_path(user) do %> +

    like <%= user.likes_count %>

    + <% end %> + + <% if user == current_user %> + <%= link_to 'Edit Profile', edit_user_path(user), class: "btn btn-primary"%> + <% else %> + <% if current_user.following?(user) %> + <%= link_to 'Unfollow', followship_path(user), method: :delete, class: "btn btn-info" %> + <% else %> + <%= link_to 'Follow', followships_path(following_id: user), method: :post, class: "btn btn-primary"%> + <% end %> + <% end %> +
    + + + diff --git a/app/views/tweets/index.html.erb b/app/views/tweets/index.html.erb index 8d95cfafd..729a8baee 100644 --- a/app/views/tweets/index.html.erb +++ b/app/views/tweets/index.html.erb @@ -34,7 +34,7 @@ <%= image_tag user.avatar , class: "tweet-avatar"%>
    -

    @<%= user.name %> +

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

    <%= user.introduction %>

    diff --git a/app/views/users/tweets.html.erb b/app/views/users/tweets.html.erb new file mode 100644 index 000000000..4cbf329dd --- /dev/null +++ b/app/views/users/tweets.html.erb @@ -0,0 +1,22 @@ +
    +
    + <%= render partial: "shared/user_info", locals: {user: @user} %> +
    + <% @tweets.each do |tweet| %> +
    +
    +
    + <%= image_tag tweet.user.avatar , class: "tweet-avatar"%> +
    +
    +

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

    +

    <%= tweet.description %>

    +
    +
    +
    + <% end %> +
    +
    + +
    \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 6f96418f5..bfb39dcc0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -13,6 +13,8 @@ end end + resources :followships, only: [:create, :destroy] + resources :tweets root "tweets#index" From 4a3f53cb2a958a6fe3fd543974a88ec543efaa51 Mon Sep 17 00:00:00 2001 From: allenpan Date: Fri, 31 Aug 2018 09:49:23 +0800 Subject: [PATCH 11/26] add followings page --- app/controllers/users_controller.rb | 4 +++- app/views/shared/_user_wall.html.erb | 24 ++++++++++++++++++++++++ app/views/tweets/index.html.erb | 2 +- app/views/users/followings.html.erb | 9 +++++++++ 4 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 app/views/shared/_user_wall.html.erb create mode 100644 app/views/users/followings.html.erb diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index ae7eda5f6..529b00da6 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -12,7 +12,9 @@ def update end def followings - @followings # 基於測試規格,必須講定變數名稱 + @user = User.find(params[:id]) + @followings = @user.followings + # 基於測試規格,必須講定變數名稱 end def followers diff --git a/app/views/shared/_user_wall.html.erb b/app/views/shared/_user_wall.html.erb new file mode 100644 index 000000000..17a0dfc2e --- /dev/null +++ b/app/views/shared/_user_wall.html.erb @@ -0,0 +1,24 @@ + +<% followings.each do |following| %> +
    +
    +
    + <%= image_tag following.avatar , class: "tweet-avatar"%> +
    +
    +

    <%= following.name %> +

    +

    <%= truncate(following.introduction, length: 140) %>

    + <% if user.following?(following) %> + <%= link_to 'Unfollow', followship_path(following), method: :delete, class: "btn btn-info" %> + <% end %> +
    +
    +
    +<% end %> + + + + + + diff --git a/app/views/tweets/index.html.erb b/app/views/tweets/index.html.erb index 729a8baee..9941100d4 100644 --- a/app/views/tweets/index.html.erb +++ b/app/views/tweets/index.html.erb @@ -18,7 +18,7 @@ <%= image_tag tweet.user.avatar , class: "tweet-avatar"%>
    -

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

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

    <%= tweet.description %>

    diff --git a/app/views/users/followings.html.erb b/app/views/users/followings.html.erb new file mode 100644 index 000000000..447494f68 --- /dev/null +++ b/app/views/users/followings.html.erb @@ -0,0 +1,9 @@ +
    +
    + <%= render partial: "shared/user_info", locals: {user: @user} %> +
    +

    Following

    + <%= render partial: "shared/user_wall", locals: {followings: @followings, user: @user} %> +
    +
    +
    \ No newline at end of file From 7d227b4caa0e9cd44a8009293e6ad618cf9ae3e2 Mon Sep 17 00:00:00 2001 From: allenpan Date: Fri, 31 Aug 2018 11:04:31 +0800 Subject: [PATCH 12/26] fix following isse --- app/views/shared/_user_wall.html.erb | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/app/views/shared/_user_wall.html.erb b/app/views/shared/_user_wall.html.erb index 17a0dfc2e..c5eb07656 100644 --- a/app/views/shared/_user_wall.html.erb +++ b/app/views/shared/_user_wall.html.erb @@ -6,12 +6,24 @@ <%= image_tag following.avatar , class: "tweet-avatar"%>
    -

    <%= following.name %> +

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

    <%= truncate(following.introduction, length: 140) %>

    - <% if user.following?(following) %> - <%= link_to 'Unfollow', followship_path(following), method: :delete, class: "btn btn-info" %> + + <% if user != current_user %> + <% if current_user.following?(following) %> + <%= link_to 'Unfollow', followship_path(following), method: :delete, class: "btn btn-info" %> + <% else %> + <%= link_to 'Follow', followships_path(following_id: following), method: :post, class: "btn btn-primary"%> + <% end %> + <% else %> + <% if user.following?(following) %> + <%= link_to 'Unfollow', followship_path(following), method: :delete, class: "btn btn-info" %> + <% else %> + <%= link_to 'Follow', followships_path(following_id: user), method: :post, class: "btn btn-primary"%> + <% end %> <% end %> +
    From 54be9d7e4a8a192dc3c4cdd495884a06a489a9a9 Mon Sep 17 00:00:00 2001 From: allenpan Date: Fri, 31 Aug 2018 11:05:44 +0800 Subject: [PATCH 13/26] modify tweets username format --- app/views/users/tweets.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/users/tweets.html.erb b/app/views/users/tweets.html.erb index 4cbf329dd..edd5e134a 100644 --- a/app/views/users/tweets.html.erb +++ b/app/views/users/tweets.html.erb @@ -9,7 +9,7 @@ <%= image_tag tweet.user.avatar , class: "tweet-avatar"%>
    -

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

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

    <%= tweet.description %>

    From 5871a82ba848802b0675341102dedc2b7600a330 Mon Sep 17 00:00:00 2001 From: allenpan Date: Fri, 31 Aug 2018 11:10:10 +0800 Subject: [PATCH 14/26] modify followings naming --- .../shared/_user_following_wall.html.erb | 36 +++++++++++++++++++ app/views/users/followings.html.erb | 2 +- 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 app/views/shared/_user_following_wall.html.erb diff --git a/app/views/shared/_user_following_wall.html.erb b/app/views/shared/_user_following_wall.html.erb new file mode 100644 index 000000000..c5eb07656 --- /dev/null +++ b/app/views/shared/_user_following_wall.html.erb @@ -0,0 +1,36 @@ + +<% followings.each do |following| %> +
    +
    +
    + <%= image_tag following.avatar , class: "tweet-avatar"%> +
    +
    +

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

    +

    <%= truncate(following.introduction, length: 140) %>

    + + <% if user != current_user %> + <% if current_user.following?(following) %> + <%= link_to 'Unfollow', followship_path(following), method: :delete, class: "btn btn-info" %> + <% else %> + <%= link_to 'Follow', followships_path(following_id: following), method: :post, class: "btn btn-primary"%> + <% end %> + <% else %> + <% if user.following?(following) %> + <%= link_to 'Unfollow', followship_path(following), method: :delete, class: "btn btn-info" %> + <% else %> + <%= link_to 'Follow', followships_path(following_id: user), method: :post, class: "btn btn-primary"%> + <% end %> + <% end %> + +
    +
    +
    +<% end %> + + + + + + diff --git a/app/views/users/followings.html.erb b/app/views/users/followings.html.erb index 447494f68..5963d2cc1 100644 --- a/app/views/users/followings.html.erb +++ b/app/views/users/followings.html.erb @@ -3,7 +3,7 @@ <%= render partial: "shared/user_info", locals: {user: @user} %>

    Following

    - <%= render partial: "shared/user_wall", locals: {followings: @followings, user: @user} %> + <%= render partial: "shared/user_following_wall", locals: {followings: @followings, user: @user} %>
    \ No newline at end of file From c893fc3959218e6bbb90540f8356189d4d6a4b03 Mon Sep 17 00:00:00 2001 From: allenpan Date: Fri, 31 Aug 2018 11:29:43 +0800 Subject: [PATCH 15/26] add followers function --- app/controllers/users_controller.rb | 3 +- .../shared/_user_following_wall.html.erb | 2 +- app/views/shared/_user_wall.html.erb | 36 ------------------- app/views/users/followers.html.erb | 9 +++++ 4 files changed, 12 insertions(+), 38 deletions(-) delete mode 100644 app/views/shared/_user_wall.html.erb create mode 100644 app/views/users/followers.html.erb diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 529b00da6..8e765180c 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -18,7 +18,8 @@ def followings end def followers - @followers # 基於測試規格,必須講定變數名稱 + @user = User.find(params[:id]) + @followers = @user.followers# 基於測試規格,必須講定變數名稱 end def likes diff --git a/app/views/shared/_user_following_wall.html.erb b/app/views/shared/_user_following_wall.html.erb index c5eb07656..476cf443a 100644 --- a/app/views/shared/_user_following_wall.html.erb +++ b/app/views/shared/_user_following_wall.html.erb @@ -20,7 +20,7 @@ <% if user.following?(following) %> <%= link_to 'Unfollow', followship_path(following), method: :delete, class: "btn btn-info" %> <% else %> - <%= link_to 'Follow', followships_path(following_id: user), method: :post, class: "btn btn-primary"%> + <%= link_to 'Follow', followships_path(following_id: following), method: :post, class: "btn btn-primary"%> <% end %> <% end %> diff --git a/app/views/shared/_user_wall.html.erb b/app/views/shared/_user_wall.html.erb deleted file mode 100644 index c5eb07656..000000000 --- a/app/views/shared/_user_wall.html.erb +++ /dev/null @@ -1,36 +0,0 @@ - -<% followings.each do |following| %> -
    -
    -
    - <%= image_tag following.avatar , class: "tweet-avatar"%> -
    -
    -

    <%= link_to following.name, tweets_user_path(following) %> -

    -

    <%= truncate(following.introduction, length: 140) %>

    - - <% if user != current_user %> - <% if current_user.following?(following) %> - <%= link_to 'Unfollow', followship_path(following), method: :delete, class: "btn btn-info" %> - <% else %> - <%= link_to 'Follow', followships_path(following_id: following), method: :post, class: "btn btn-primary"%> - <% end %> - <% else %> - <% if user.following?(following) %> - <%= link_to 'Unfollow', followship_path(following), method: :delete, class: "btn btn-info" %> - <% else %> - <%= link_to 'Follow', followships_path(following_id: user), method: :post, class: "btn btn-primary"%> - <% end %> - <% end %> - -
    -
    -
    -<% end %> - - - - - - diff --git a/app/views/users/followers.html.erb b/app/views/users/followers.html.erb new file mode 100644 index 000000000..68ab88acb --- /dev/null +++ b/app/views/users/followers.html.erb @@ -0,0 +1,9 @@ +
    +
    + <%= render partial: "shared/user_info", locals: {user: @user} %> +
    +

    Follower

    + <%= render partial: "shared/user_following_wall", locals: {followings: @followers, user: @user} %> +
    +
    +
    \ No newline at end of file From ae652df9903215267cd12491cf029d26d4cf9b49 Mon Sep 17 00:00:00 2001 From: allenpan Date: Fri, 31 Aug 2018 11:36:53 +0800 Subject: [PATCH 16/26] add follow/unfollow button on tweets index page --- app/views/tweets/index.html.erb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/views/tweets/index.html.erb b/app/views/tweets/index.html.erb index 9941100d4..2c640e8ab 100644 --- a/app/views/tweets/index.html.erb +++ b/app/views/tweets/index.html.erb @@ -37,6 +37,13 @@

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

    <%= user.introduction %>

    + <% if current_user != user %> + <% if current_user.following?(user) %> + <%= link_to 'Unfollow', followship_path(user), method: :delete, class: "btn btn-info" %> + <% else %> + <%= link_to 'Follow', followships_path(following_id: user), method: :post, class: "btn btn-primary"%> + <% end %> + <% end %> <% end %> From 890147dcafee82b33c52be03c79054d79800070c Mon Sep 17 00:00:00 2001 From: allenpan Date: Fri, 31 Aug 2018 15:40:25 +0800 Subject: [PATCH 17/26] define relation between tweet, user, and comment --- app/models/reply.rb | 2 ++ app/models/tweet.rb | 1 + app/models/user.rb | 4 +++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/models/reply.rb b/app/models/reply.rb index bae6f9463..223589f44 100644 --- a/app/models/reply.rb +++ b/app/models/reply.rb @@ -1,2 +1,4 @@ class Reply < ApplicationRecord + belongs_to :user + belongs_to :tweet end diff --git a/app/models/tweet.rb b/app/models/tweet.rb index 7895d54d6..256b56c47 100644 --- a/app/models/tweet.rb +++ b/app/models/tweet.rb @@ -1,4 +1,5 @@ class Tweet < ApplicationRecord validates_length_of :description, maximum: 140 belongs_to :user + has_many :replies end diff --git a/app/models/user.rb b/app/models/user.rb index edabcd8b5..83ee742f1 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -9,7 +9,9 @@ class User < ApplicationRecord has_many :inverse_followships, class_name: "Followship", foreign_key: "following_id" has_many :followers, through: :inverse_followships, source: :user - + + has_many :replies + mount_uploader :avatar, AvatarUploader # 需要 app/views/devise 裡找到樣板,加上 name 屬性 From bd58a6d81ba9738e24136b4ad79737472ff94d89 Mon Sep 17 00:00:00 2001 From: allenpan Date: Fri, 31 Aug 2018 19:31:26 +0800 Subject: [PATCH 18/26] add reply feature --- app/assets/stylesheets/style.scss | 11 +++++++ app/controllers/replies_controller.rb | 14 +++++++++ app/models/reply.rb | 2 +- app/models/tweet.rb | 3 +- app/models/user.rb | 3 +- app/views/replies/index.html.erb | 45 +++++++++++++++++++++++++++ app/views/shared/_reply_link.html.erb | 5 +++ app/views/tweets/index.html.erb | 1 + app/views/users/tweets.html.erb | 1 + config/routes.rb | 6 +++- 10 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 app/views/replies/index.html.erb create mode 100644 app/views/shared/_reply_link.html.erb diff --git a/app/assets/stylesheets/style.scss b/app/assets/stylesheets/style.scss index a559db709..1cc92d7b7 100644 --- a/app/assets/stylesheets/style.scss +++ b/app/assets/stylesheets/style.scss @@ -37,3 +37,14 @@ margin: 10px; margin: 0px 0px 0px 0px; width: 200px } + +.user-item { + border: 1px solid #ddd; + border-radius: 4px; + padding: 4px; + margin-bottom: 20px; +} + +.reply-area { + padding: 15px 15px; +} diff --git a/app/controllers/replies_controller.rb b/app/controllers/replies_controller.rb index a9b6a315b..67063f6cf 100644 --- a/app/controllers/replies_controller.rb +++ b/app/controllers/replies_controller.rb @@ -1,9 +1,23 @@ class RepliesController < ApplicationController def index + @tweet = Tweet.find(params[:tweet_id]) + @replies = @tweet.replies + @reply = Reply.new end def create + @tweet = Tweet.find(params[:tweet_id]) + @reply = @tweet.replies.build(replied_params) + @reply.user = current_user + @reply.save! + redirect_to tweet_replies_path(@tweet) + end + + private + + def replied_params + params.require(:reply).permit(:comment) end end diff --git a/app/models/reply.rb b/app/models/reply.rb index 223589f44..dd3679577 100644 --- a/app/models/reply.rb +++ b/app/models/reply.rb @@ -1,4 +1,4 @@ class Reply < ApplicationRecord belongs_to :user - belongs_to :tweet + belongs_to :tweet, counter_cache: true end diff --git a/app/models/tweet.rb b/app/models/tweet.rb index 256b56c47..27dc2a808 100644 --- a/app/models/tweet.rb +++ b/app/models/tweet.rb @@ -1,5 +1,6 @@ class Tweet < ApplicationRecord validates_length_of :description, maximum: 140 belongs_to :user - has_many :replies + has_many :replies, dependent: :destroy + has_many :replied_users, through: :replies, source: :user end diff --git a/app/models/user.rb b/app/models/user.rb index 83ee742f1..3d0e6214c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -10,7 +10,8 @@ class User < ApplicationRecord has_many :inverse_followships, class_name: "Followship", foreign_key: "following_id" has_many :followers, through: :inverse_followships, source: :user - has_many :replies + has_many :replies, dependent: :destroy + has_many :replied_tweets, through: :replies, source: :tweet mount_uploader :avatar, AvatarUploader diff --git a/app/views/replies/index.html.erb b/app/views/replies/index.html.erb new file mode 100644 index 000000000..def14e5b2 --- /dev/null +++ b/app/views/replies/index.html.erb @@ -0,0 +1,45 @@ +
    +
    + <%= render partial: "shared/user_info", locals: {user: @tweet.user} %> +
    +

    Tweets

    +
    +
    +
    + <%= image_tag @tweet.user.avatar , class: "tweet-avatar"%> +
    +
    +

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

    +

    <%= @tweet.description %>

    + <%= render partial: "shared/reply_link", locals: {tweet: @tweet} %> +
    +
    +
    +

    Replies

    + <% @replies.each do |reply| %> +
    +
    +
    + <%= image_tag reply.user.avatar , class: "tweet-avatar"%> +
    +
    +

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

    +

    <%= reply.comment %>

    +
    +
    +
    + <% end %> + + <%= form_for [@tweet, @reply] do |f| %> +
    + <%= f.text_area :comment, placeholder: "Any comment about this tweet?", class: "form-control", style: 'height: 90px' %> +
    +
    + <%= f.submit "Reply", class: "btn btn-primary"%> + <% end %> + +
    +
    +
    \ No newline at end of file diff --git a/app/views/shared/_reply_link.html.erb b/app/views/shared/_reply_link.html.erb new file mode 100644 index 000000000..bd9b70fef --- /dev/null +++ b/app/views/shared/_reply_link.html.erb @@ -0,0 +1,5 @@ +<%= link_to tweet_replies_path(tweet) do %> + + Reply(<%=tweet.replies_count%>) + +<% end %> \ No newline at end of file diff --git a/app/views/tweets/index.html.erb b/app/views/tweets/index.html.erb index 2c640e8ab..6056c10e9 100644 --- a/app/views/tweets/index.html.erb +++ b/app/views/tweets/index.html.erb @@ -21,6 +21,7 @@

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

    <%= tweet.description %>

    + <%= render partial: "shared/reply_link", locals: {tweet: tweet} %> diff --git a/app/views/users/tweets.html.erb b/app/views/users/tweets.html.erb index edd5e134a..487466dd0 100644 --- a/app/views/users/tweets.html.erb +++ b/app/views/users/tweets.html.erb @@ -12,6 +12,7 @@

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

    <%= tweet.description %>

    + <%= render partial: "shared/reply_link", locals: {tweet: tweet} %> diff --git a/config/routes.rb b/config/routes.rb index bfb39dcc0..5c76fc255 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -15,7 +15,9 @@ resources :followships, only: [:create, :destroy] - resources :tweets + resources :tweets do + resources :replies, only: [:index, :create] + end root "tweets#index" namespace :admin do @@ -23,4 +25,6 @@ resources :users, only: [:index] root "tweets#index" end + + end From 91728bb697a8e475c0c064deaf5fadba7f1ced26 Mon Sep 17 00:00:00 2001 From: allenpan Date: Fri, 31 Aug 2018 21:17:45 +0800 Subject: [PATCH 19/26] add like function and edit user profile --- app/controllers/tweets_controller.rb | 9 ++++++- app/controllers/users_controller.rb | 21 ++++++++++++---- app/models/like.rb | 2 ++ app/models/tweet.rb | 7 ++++++ app/models/user.rb | 6 +++++ app/views/replies/index.html.erb | 1 + app/views/shared/_like_link.html.erb | 9 +++++++ app/views/tweets/index.html.erb | 1 + app/views/users/edit.html.erb | 37 ++++++++++++++++++++++++++++ app/views/users/likes.html.erb | 27 ++++++++++++++++++++ app/views/users/tweets.html.erb | 1 + config/routes.rb | 10 +++++--- 12 files changed, 122 insertions(+), 9 deletions(-) create mode 100644 app/views/shared/_like_link.html.erb create mode 100644 app/views/users/edit.html.erb create mode 100644 app/views/users/likes.html.erb diff --git a/app/controllers/tweets_controller.rb b/app/controllers/tweets_controller.rb index d86929bab..d2c408dea 100644 --- a/app/controllers/tweets_controller.rb +++ b/app/controllers/tweets_controller.rb @@ -1,7 +1,7 @@ class TweetsController < ApplicationController def index - @tweets = Tweet.all + @tweets = Tweet.all.order(created_at: :desc) @tweet = Tweet.new @users = User.order(followers_count: :desc).limit(10)# 基於測試規格,必須講定變數名稱,請用此變數中存放關注人數 Top 10 的使用者資料 end @@ -19,9 +19,16 @@ def create end def like + @tweet = Tweet.find(params[:id]) + @tweet.likes.create!(user: current_user) + redirect_back(fallback_location: root_path) end def unlike + @tweet = Tweet.find(params[:id]) + like_items = Like.where(tweet: @tweet, user: current_user) + like_items.destroy_all + redirect_back(fallback_location: root_path) end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 8e765180c..ddea264ca 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -2,28 +2,39 @@ class UsersController < ApplicationController def tweets @user = User.find(params[:id]) - @tweets = @user.tweets + @tweets = @user.tweets.order(created_at: :desc) end def edit + @user = User.find(params[:id]) + if @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 @user = User.find(params[:id]) - @followings = @user.followings - # 基於測試規格,必須講定變數名稱 + @followings = @user.followings.order(created_at: :desc) # 基於測試規格,必須講定變數名稱 end def followers @user = User.find(params[:id]) - @followers = @user.followers# 基於測試規格,必須講定變數名稱 + @followers = @user.followers.order(created_at: :desc)# 基於測試規格,必須講定變數名稱 end def likes - @likes # 基於測試規格,必須講定變數名稱 + @user = User.find(params[:id]) + @likes = @user.liked_tweets.order(created_at: :desc)# 基於測試規格,必須講定變數名稱 + end + + def user_params + params.require(:user).permit(:name, :introduction, :avatar) end end diff --git a/app/models/like.rb b/app/models/like.rb index d99b93a32..0d1910145 100644 --- a/app/models/like.rb +++ b/app/models/like.rb @@ -1,2 +1,4 @@ class Like < ApplicationRecord + belongs_to :user, counter_cache: true + belongs_to :tweet, counter_cache: true end diff --git a/app/models/tweet.rb b/app/models/tweet.rb index 27dc2a808..92690834d 100644 --- a/app/models/tweet.rb +++ b/app/models/tweet.rb @@ -3,4 +3,11 @@ class Tweet < ApplicationRecord belongs_to :user has_many :replies, dependent: :destroy has_many :replied_users, through: :replies, source: :user + + has_many :likes, dependent: :destroy + has_many :liked_users, through: :likes, source: :user + + def is_like?(user) + self.liked_users.include?(user) + end end diff --git a/app/models/user.rb b/app/models/user.rb index 3d0e6214c..881b95f53 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -3,6 +3,9 @@ class User < ApplicationRecord # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable + + validates_presence_of :name + validates_uniqueness_of :name has_many :tweets, dependent: :destroy has_many :followships, dependent: :destroy has_many :followings, through: :followships @@ -13,6 +16,9 @@ class User < ApplicationRecord has_many :replies, dependent: :destroy has_many :replied_tweets, through: :replies, source: :tweet + has_many :likes, dependent: :destroy + has_many :liked_tweets, through: :likes, source: :tweet + mount_uploader :avatar, AvatarUploader # 需要 app/views/devise 裡找到樣板,加上 name 屬性 diff --git a/app/views/replies/index.html.erb b/app/views/replies/index.html.erb index def14e5b2..9dd777c9e 100644 --- a/app/views/replies/index.html.erb +++ b/app/views/replies/index.html.erb @@ -13,6 +13,7 @@

    <%= @tweet.description %>

    <%= render partial: "shared/reply_link", locals: {tweet: @tweet} %> + <%= render partial: "shared/like_link", locals: {tweet: @tweet} %> diff --git a/app/views/shared/_like_link.html.erb b/app/views/shared/_like_link.html.erb new file mode 100644 index 000000000..147d1c4d0 --- /dev/null +++ b/app/views/shared/_like_link.html.erb @@ -0,0 +1,9 @@ +<% if tweet.is_like?(current_user) %> + <%= link_to unlike_tweet_path(tweet),method: :post do %> + like(<%=tweet.likes_count%>) + <% end %> +<% else %> + <%= link_to like_tweet_path(tweet),method: :post do %> + like(<%=tweet.likes_count%>) + <% end %> +<% end %> \ No newline at end of file diff --git a/app/views/tweets/index.html.erb b/app/views/tweets/index.html.erb index 6056c10e9..54c65f30b 100644 --- a/app/views/tweets/index.html.erb +++ b/app/views/tweets/index.html.erb @@ -22,6 +22,7 @@

    <%= tweet.description %>

    <%= render partial: "shared/reply_link", locals: {tweet: tweet} %> + <%= render partial: "shared/like_link", locals: {tweet: tweet} %> diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb new file mode 100644 index 000000000..f49826081 --- /dev/null +++ b/app/views/users/edit.html.erb @@ -0,0 +1,37 @@ +
    +
    + <%= form_for [@user] do |user| %> +
    +

    Edit Your Profile

    +
    +
    +
    + <%= user.label :name, "Name"%> + <%= user.text_field :name, class: "form-control" %> +
    +
    +
    +
    +
    + <%= user.label :introduction, "Introduction"%> + <%= user.text_area :introduction, class: "form-control" %> +
    +
    +
    +
    +
    + <%= user.label :avatar, "Avatar" %> +
    + <%= image_tag @user.avatar, width: '350px' if @user.avatar? %> + <%= user.file_field :avatar, class: "form-control-file" %> +
    +
    +
    +
    + <%= user.submit class: "btn btn-primary" %> +
    +
    + + <%end%> +
    +
    \ No newline at end of file diff --git a/app/views/users/likes.html.erb b/app/views/users/likes.html.erb new file mode 100644 index 000000000..740fe2418 --- /dev/null +++ b/app/views/users/likes.html.erb @@ -0,0 +1,27 @@ +
    +
    + <%= render partial: "shared/user_info", locals: {user: @user} %> +
    +

    Like

    + <% @likes.each do |tweet| %> +
    +
    +
    + <%= image_tag tweet.user.avatar , class: "tweet-avatar"%> +
    +
    +

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

    +

    <%= tweet.description %>

    + <%= render partial: "shared/reply_link", locals: {tweet: tweet} %> + <%= render partial: "shared/like_link", locals: {tweet: tweet} %> +
    +
    +
    + <% end %> + + + +
    +
    +
    \ No newline at end of file diff --git a/app/views/users/tweets.html.erb b/app/views/users/tweets.html.erb index 487466dd0..4c27592c2 100644 --- a/app/views/users/tweets.html.erb +++ b/app/views/users/tweets.html.erb @@ -13,6 +13,7 @@

    <%= tweet.description %>

    <%= render partial: "shared/reply_link", locals: {tweet: tweet} %> + <%= render partial: "shared/like_link", locals: {tweet: tweet} %> diff --git a/config/routes.rb b/config/routes.rb index 5c76fc255..2fb0a3e49 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -8,15 +8,19 @@ get :tweets get :followings get :followers - get :likes - post :like + get :likes end end resources :followships, only: [:create, :destroy] - resources :tweets do + resources :tweets, only: [:index, :create] do resources :replies, only: [:index, :create] + + member do + post :like + post :unlike + end end root "tweets#index" From 773064ddb580a459be6f533bc9a84c5cff78fcdc Mon Sep 17 00:00:00 2001 From: allenpan Date: Fri, 31 Aug 2018 21:44:40 +0800 Subject: [PATCH 20/26] add admin/tweets#index --- app/controllers/admin/tweets_controller.rb | 5 +++++ app/views/admin/tweets/index.html.erb | 26 +++++++++++++++++++++- app/views/layouts/application.html.erb | 2 +- app/views/shared/_delete_link.html.erb | 5 +++++ 4 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 app/views/shared/_delete_link.html.erb diff --git a/app/controllers/admin/tweets_controller.rb b/app/controllers/admin/tweets_controller.rb index 24a57566c..8d34e21a1 100644 --- a/app/controllers/admin/tweets_controller.rb +++ b/app/controllers/admin/tweets_controller.rb @@ -1,7 +1,12 @@ 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_tweets_path + flash[:alert] = "Tweet has been deleted!" end end diff --git a/app/views/admin/tweets/index.html.erb b/app/views/admin/tweets/index.html.erb index 9edffed8b..572a05b2c 100644 --- a/app/views/admin/tweets/index.html.erb +++ b/app/views/admin/tweets/index.html.erb @@ -1 +1,25 @@ -

    tweets後台

    \ No newline at end of file +
    +
    +
    + <% @tweets.each do |tweet| %> +
    +
    +
    + <%= image_tag tweet.user.avatar , class: "tweet-avatar"%> +
    +
    +

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

    +

    <%= tweet.description %>

    + <%= render partial: "shared/reply_link", locals: {tweet: tweet} %> + <%= render partial: "shared/like_link", locals: {tweet: tweet} %> + <%= render partial: "shared/delete_link", locals: {tweet: tweet} %> +
    +
    +
    + <% end %> +
    + +
    +
    + diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index a781ba2f8..ebd34c397 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -28,7 +28,7 @@