diff --git a/.gitignore b/.gitignore index 9cbc5dbfc..1fcd1eec7 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,6 @@ yarn-debug.log* .yarn-integrity /config/credentials/production.key + +.DS_Store +vendor/bundle/ diff --git a/.node-version b/.node-version new file mode 100644 index 000000000..431076a94 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +16.16.0 diff --git a/Gemfile b/Gemfile index 059b8fabb..44d77bc7b 100644 --- a/Gemfile +++ b/Gemfile @@ -46,6 +46,9 @@ group :development, :test do gem 'byebug', platforms: %i[mri mingw x64_mingw] gem 'rb-readline' gem 'rspec-rails' + gem 'capybara', '~> 3.23' + gem 'selenium-webdriver', '4.9.0' + gem 'webdrivers' end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index 4d19f0151..d7569adf8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -106,6 +106,15 @@ GEM msgpack (~> 1.0) builder (3.2.4) byebug (11.1.3) + capybara (3.39.2) + addressable + matrix + mini_mime (>= 0.1.3) + nokogiri (~> 1.8) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (>= 1.5, < 3.0) + xpath (~> 3.2) concurrent-ruby (1.1.9) crass (1.0.6) diff-lcs (1.4.4) @@ -173,6 +182,7 @@ GEM mail (2.7.1) mini_mime (>= 0.1.1) marcel (1.0.2) + matrix (0.4.2) method_source (1.0.0) mini_mime (1.1.2) minitest (5.14.4) @@ -181,6 +191,8 @@ GEM multi_xml (0.6.0) multipart-post (2.1.1) nio4r (2.5.8) + nokogiri (1.12.5-arm64-darwin) + racc (~> 1.4) nokogiri (1.12.5-x86_64-darwin) racc (~> 1.4) nokogiri (1.12.5-x86_64-linux) @@ -284,6 +296,7 @@ GEM rubocop (>= 1.7.0, < 2.0) ruby-progressbar (1.11.0) ruby2_keywords (0.0.5) + rubyzip (2.3.2) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) sassc (2.4.0) @@ -294,6 +307,10 @@ GEM sprockets (> 3.0) sprockets-rails tilt + selenium-webdriver (4.9.0) + rexml (~> 3.2, >= 3.2.5) + rubyzip (>= 1.2.2, < 3.0) + websocket (~> 1.0) semantic_range (3.0.0) sorcery (0.16.1) bcrypt (~> 3.1) @@ -318,17 +335,25 @@ GEM activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) + webdrivers (5.3.1) + nokogiri (~> 1.6) + rubyzip (>= 1.3.0) + selenium-webdriver (~> 4.0, < 4.11) webpacker (5.4.3) activesupport (>= 5.2) rack-proxy (>= 0.6.1) railties (>= 5.2) semantic_range (>= 2.3.0) + websocket (1.2.10) websocket-driver (0.7.5) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) + xpath (3.2.0) + nokogiri (~> 1.8) zeitwerk (2.5.1) PLATFORMS + arm64-darwin-22 x86_64-darwin-19 x86_64-linux @@ -336,6 +361,7 @@ DEPENDENCIES aws-sdk-s3 bootsnap (>= 1.4.4) byebug + capybara (~> 3.23) draper enum_help factory_bot_rails @@ -356,11 +382,13 @@ DEPENDENCIES rubocop rubocop-rails sass-rails (>= 6) + selenium-webdriver (= 4.9.0) sorcery spring sqlite3 (~> 1.4) tzinfo-data web-console (>= 4.1.0) + webdrivers webpacker (~> 5.0) RUBY VERSION diff --git a/README.md b/README.md index 64d25a2f7..baa91a27d 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,24 @@ ## 環境構築 ``` -$ bundle install +$ bundle install --without=production $ bin/rails db:setup $ yarn install +$ bin/webpack $ bin/rails s ``` ## 事業をエンジニアリングしよう提案編の回答は以下に記述してください +``` +選択した事業側の課題 +直近一年間で、2回以上もくもく会に参加してくれた人は利用者全体の1%のみ。もくもく会で気の合う仲間を見つけられなかったのではないか? + +提案内容 +・もくもく会にタグ(Ruby, Rails, PHP, iOS, 駆け出しエンジニア etc)を設定 & 絞り込みができるようにする +→ 自分の学習している言語を見つけやすくする。また、人気のタグを表示することで、ユーザーは他の・ユーザープロフィールに、ユーザーのタグ情報を追加する。 +→ 人々がどのようなトピックに関心を持っているかを知り、共通の興味を持つ仲間を見つけやすくなる。 + +実装方針 +もくもく会でよく使用されるタグを抽出し、トレンドや人気のあるトピックを表示する機能を追加する。 +ユーザープロフィールにおいて、タグを表示する機能を追加する。 +``` diff --git a/app/controllers/mypage/profiles_controller.rb b/app/controllers/mypage/profiles_controller.rb index 966f90960..18b0008f5 100644 --- a/app/controllers/mypage/profiles_controller.rb +++ b/app/controllers/mypage/profiles_controller.rb @@ -17,6 +17,6 @@ def update private def profile_params - params.require(:user).permit(:name, :avatar) + params.require(:user).permit(:name, :avatar, :hobby, :profile) end end diff --git a/app/controllers/relationships_controller.rb b/app/controllers/relationships_controller.rb new file mode 100644 index 000000000..855b0fda7 --- /dev/null +++ b/app/controllers/relationships_controller.rb @@ -0,0 +1,12 @@ +class RelationshipsController < ApplicationController + def create + current_user.follow(params[:user_id]) + redirect_to request.referer + end + + # フォロー外すとき + def destroy + current_user.unfollow(params[:user_id]) + redirect_to request.referer + end +end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 136d60eba..5a6772b8a 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -16,7 +16,22 @@ def create end end + def show + @user = User.find(params[:id]) + end + def user_params params.require(:user).permit(:email, :name, :password, :password_confirmation) end + + def follows + user = User.find(params[:id]) + @users = user.following_users + end + + # フォロワー一覧 + def followers + user = User.find(params[:id]) + @user = user.follower_users + end end diff --git a/app/decorators/relationship_decorator.rb b/app/decorators/relationship_decorator.rb new file mode 100644 index 000000000..bb203bbee --- /dev/null +++ b/app/decorators/relationship_decorator.rb @@ -0,0 +1,13 @@ +class RelationshipDecorator < Draper::Decorator + delegate_all + + # Define presentation-specific methods here. Helpers are accessed through + # `helpers` (aka `h`). You can override attributes, for example: + # + # def created_at + # helpers.content_tag :span, class: 'time' do + # object.created_at.strftime("%a %m/%d/%y") + # end + # end + +end diff --git a/app/models/relationship.rb b/app/models/relationship.rb new file mode 100644 index 000000000..c80d25be7 --- /dev/null +++ b/app/models/relationship.rb @@ -0,0 +1,4 @@ +class Relationship < ApplicationRecord + belongs_to :follower, class_name: "User" + belongs_to :followed, class_name: "User" +end diff --git a/app/models/user.rb b/app/models/user.rb index 894c04a65..8dfb66b3b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -14,6 +14,13 @@ class User < ApplicationRecord has_many :notification_timings, through: :user_notification_timings has_one_attached :avatar + has_many :followers, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy + has_many :followeds, class_name: "Relationship", foreign_key: "followed_id", dependent: :destroy + + # 一覧画面で使う + has_many :following_users, through: :followers, source: :followed + has_many :follower_users, through: :followeds, source: :follower + validates :password, length: { minimum: 3 }, if: -> { new_record? || changes[:crypted_password] } validates :password, confirmation: true, if: -> { new_record? || changes[:crypted_password] } validates :password_confirmation, presence: true, if: -> { new_record? || changes[:crypted_password] } @@ -76,4 +83,18 @@ def allow_attended_to_event_notification? def allow_liked_event_notification? notification_timings.liked_event.present? end + + def follow(user_id) + followers.create(followed_id: user_id) + end + + # フォローを外すときの処理 + def unfollow(user_id) + followers.find_by(followed_id: user_id).destroy + end + + #フォローしていればtrueを返す + def following?(user) + following_users.include?(user) + end end diff --git a/app/views/events/_event.html.erb b/app/views/events/_event.html.erb index 4725d15fa..a162db1e8 100644 --- a/app/views/events/_event.html.erb +++ b/app/views/events/_event.html.erb @@ -23,7 +23,7 @@
Hobby: <%= @user.hobby %>
+Profile: <%= @user.profile %>
+ +<% if current_user.following?(@user) %> + <%= link_to "フォローを外す", user_relationships_path(@user.id), method: :delete %> +<% else %> + <%= link_to "フォローする", user_relationships_path(@user.id), method: :post %> +<% end %> diff --git a/config/routes.rb b/config/routes.rb index 018ec9d39..1fab8dfb6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -9,7 +9,13 @@ delete 'logout', to: 'sessions#destroy' get 'signup', to: 'users#new' post 'signup', to: 'users#create' - resources :users, only: %i[new create] + resources :users, only: %i[new create show] do + member do + get :follows, :followers + end + resource :relationships, only: [:create, :destroy] + end + resources :events do collection do get :future diff --git a/db/migrate/20231022153030_add_profile_and_hobby_to_users.rb b/db/migrate/20231022153030_add_profile_and_hobby_to_users.rb new file mode 100644 index 000000000..96ee7873e --- /dev/null +++ b/db/migrate/20231022153030_add_profile_and_hobby_to_users.rb @@ -0,0 +1,6 @@ +class AddProfileAndHobbyToUsers < ActiveRecord::Migration[6.1] + def change + add_column :users, :profile, :string + add_column :users, :hobby, :string + end +end diff --git a/db/migrate/20231022154826_create_relationships.rb b/db/migrate/20231022154826_create_relationships.rb new file mode 100644 index 000000000..1d8203bce --- /dev/null +++ b/db/migrate/20231022154826_create_relationships.rb @@ -0,0 +1,10 @@ +class CreateRelationships < ActiveRecord::Migration[6.1] + def change + create_table :relationships do |t| + t.integer :follower_id + t.integer :followed_id + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 01c4634ac..abecf3ccb 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: 2022_01_19_072358) do +ActiveRecord::Schema.define(version: 2023_10_22_154826) do create_table "active_storage_attachments", force: :cascade do |t| t.string "name", null: false @@ -109,6 +109,13 @@ t.datetime "updated_at", precision: 6, null: false end + create_table "relationships", force: :cascade do |t| + t.integer "follower_id" + t.integer "followed_id" + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + end + create_table "user_notification_timings", force: :cascade do |t| t.integer "user_id", null: false t.integer "notification_timing_id", null: false @@ -135,6 +142,8 @@ t.string "name", null: false t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false + t.string "profile" + t.string "hobby" t.index ["email"], name: "index_users_on_email", unique: true end diff --git a/spec/decorators/relationship_decorator_spec.rb b/spec/decorators/relationship_decorator_spec.rb new file mode 100644 index 000000000..7de6fb702 --- /dev/null +++ b/spec/decorators/relationship_decorator_spec.rb @@ -0,0 +1,4 @@ +require 'rails_helper' + +RSpec.describe RelationshipDecorator do +end diff --git a/spec/factories/relationships.rb b/spec/factories/relationships.rb new file mode 100644 index 000000000..d071cb007 --- /dev/null +++ b/spec/factories/relationships.rb @@ -0,0 +1,6 @@ +FactoryBot.define do + factory :relationship do + follower_id { 1 } + followed_id { 1 } + end +end diff --git a/spec/models/relationship_spec.rb b/spec/models/relationship_spec.rb new file mode 100644 index 000000000..6e545f759 --- /dev/null +++ b/spec/models/relationship_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Relationship, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/requests/relationships_spec.rb b/spec/requests/relationships_spec.rb new file mode 100644 index 000000000..e98f5ea82 --- /dev/null +++ b/spec/requests/relationships_spec.rb @@ -0,0 +1,7 @@ +require 'rails_helper' + +RSpec.describe "Relationships", type: :request do + describe "GET /index" do + pending "add some examples (or delete) #{__FILE__}" + end +end