From c0082ce1674d77f7f6bfbe8c04cad497d2340361 Mon Sep 17 00:00:00 2001 From: "SHIOYA, Hiromu" Date: Wed, 14 Jan 2015 20:36:10 +0900 Subject: [PATCH 01/21] [Tagging] create model and migration --- app/models/user_tag.rb | 2 ++ app/models/user_tagging.rb | 2 ++ ...50114120333_create_user_tag_and_tagging.rb | 21 +++++++++++++++++++ db/schema.rb | 20 +++++++++++++++++- spec/factories/user_taggings.rb | 7 +++++++ spec/factories/user_tags.rb | 7 +++++++ spec/models/user_tag_spec.rb | 5 +++++ spec/models/user_tagging_spec.rb | 5 +++++ 8 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 app/models/user_tag.rb create mode 100644 app/models/user_tagging.rb create mode 100644 db/migrate/20150114120333_create_user_tag_and_tagging.rb create mode 100644 spec/factories/user_taggings.rb create mode 100644 spec/factories/user_tags.rb create mode 100644 spec/models/user_tag_spec.rb create mode 100644 spec/models/user_tagging_spec.rb diff --git a/app/models/user_tag.rb b/app/models/user_tag.rb new file mode 100644 index 0000000..a346f8b --- /dev/null +++ b/app/models/user_tag.rb @@ -0,0 +1,2 @@ +class UserTag < ActiveRecord::Base +end diff --git a/app/models/user_tagging.rb b/app/models/user_tagging.rb new file mode 100644 index 0000000..04446fe --- /dev/null +++ b/app/models/user_tagging.rb @@ -0,0 +1,2 @@ +class UserTagging < ActiveRecord::Base +end diff --git a/db/migrate/20150114120333_create_user_tag_and_tagging.rb b/db/migrate/20150114120333_create_user_tag_and_tagging.rb new file mode 100644 index 0000000..fd76739 --- /dev/null +++ b/db/migrate/20150114120333_create_user_tag_and_tagging.rb @@ -0,0 +1,21 @@ +class CreateUserTagAndTagging < ActiveRecord::Migration + def change + create_table :user_tags do |t| + t.string :name, null: false + t.string :search_hash, null: false + + t.timestamps null: false + end + + add_index :user_tags, :search_hash, unique: true + + create_table :user_taggings do |t| + t.integer :user_id, null: false + t.integer :user_tag_id, null: false + end + + add_index :user_taggings, :user_id + add_index :user_taggings, :user_tag_id + add_index :user_taggings, [:user_id, :user_tag_id], unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index db14c1d..a8edd72 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20150114033834) do +ActiveRecord::Schema.define(version: 20150114120333) do create_table "user_resumes", force: :cascade do |t| t.integer "user_id", null: false @@ -22,6 +22,24 @@ add_index "user_resumes", ["user_id"], name: "index_user_resumes_on_user_id" + create_table "user_taggings", force: :cascade do |t| + t.integer "user_id", null: false + t.integer "user_tag_id", null: false + end + + add_index "user_taggings", ["user_id", "user_tag_id"], name: "index_user_taggings_on_user_id_and_user_tag_id", unique: true + add_index "user_taggings", ["user_id"], name: "index_user_taggings_on_user_id" + add_index "user_taggings", ["user_tag_id"], name: "index_user_taggings_on_user_tag_id" + + create_table "user_tags", force: :cascade do |t| + t.string "name", null: false + t.string "search_hash", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + add_index "user_tags", ["search_hash"], name: "index_user_tags_on_search_hash", unique: true + create_table "users", force: :cascade do |t| t.string "name", null: false t.string "email", null: false diff --git a/spec/factories/user_taggings.rb b/spec/factories/user_taggings.rb new file mode 100644 index 0000000..d215508 --- /dev/null +++ b/spec/factories/user_taggings.rb @@ -0,0 +1,7 @@ +FactoryGirl.define do + factory :user_tagging do + user_id "" +user_tag_id 1 + end + +end diff --git a/spec/factories/user_tags.rb b/spec/factories/user_tags.rb new file mode 100644 index 0000000..453224b --- /dev/null +++ b/spec/factories/user_tags.rb @@ -0,0 +1,7 @@ +FactoryGirl.define do + factory :user_tag do + name "" +search_hash "MyString" + end + +end diff --git a/spec/models/user_tag_spec.rb b/spec/models/user_tag_spec.rb new file mode 100644 index 0000000..65c5f34 --- /dev/null +++ b/spec/models/user_tag_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe UserTag, :type => :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/user_tagging_spec.rb b/spec/models/user_tagging_spec.rb new file mode 100644 index 0000000..23f07d1 --- /dev/null +++ b/spec/models/user_tagging_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe UserTagging, :type => :model do + pending "add some examples to (or delete) #{__FILE__}" +end From a3f2c517773c52242fe0ea724bf49e5bd72a939f Mon Sep 17 00:00:00 2001 From: "SHIOYA, Hiromu" Date: Wed, 14 Jan 2015 21:02:49 +0900 Subject: [PATCH 02/21] specify association between models --- app/models/user.rb | 2 ++ app/models/user_tag.rb | 2 ++ app/models/user_tagging.rb | 2 ++ 3 files changed, 6 insertions(+) diff --git a/app/models/user.rb b/app/models/user.rb index f38b8d6..1fb685e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -8,6 +8,8 @@ class User < ActiveRecord::Base } has_one :resume, class_name: 'UserResume' + has_many :user_taggings + has_many :tags, through: :user_taggings, class_name: 'UserTag' devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable, :omniauthable diff --git a/app/models/user_tag.rb b/app/models/user_tag.rb index a346f8b..6737e8e 100644 --- a/app/models/user_tag.rb +++ b/app/models/user_tag.rb @@ -1,2 +1,4 @@ class UserTag < ActiveRecord::Base + has_many :user_taggings + has_many :users, through: :user_taggings end diff --git a/app/models/user_tagging.rb b/app/models/user_tagging.rb index 04446fe..b84665b 100644 --- a/app/models/user_tagging.rb +++ b/app/models/user_tagging.rb @@ -1,2 +1,4 @@ class UserTagging < ActiveRecord::Base + belongs_to :user + belongs_to :tag, class_name: 'UserTag', foreign_key: 'user_tag_id' end From 400632e9f31641c7a4ffa9243ae03864bba7ed52 Mon Sep 17 00:00:00 2001 From: "SHIOYA, Hiromu" Date: Thu, 15 Jan 2015 19:02:35 +0900 Subject: [PATCH 03/21] implement UserTag.normalize_keyword --- app/models/user_tag.rb | 6 ++++++ spec/models/user_tag_spec.rb | 28 ++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/app/models/user_tag.rb b/app/models/user_tag.rb index 6737e8e..c708158 100644 --- a/app/models/user_tag.rb +++ b/app/models/user_tag.rb @@ -1,4 +1,10 @@ class UserTag < ActiveRecord::Base + require 'nkf' + has_many :user_taggings has_many :users, through: :user_taggings + + def self.normalize_keyword(keyword) + NKF.nkf('-w -X -Z', keyword.gsub(/[\s ]/, '')) + end end diff --git a/spec/models/user_tag_spec.rb b/spec/models/user_tag_spec.rb index 65c5f34..8bdf859 100644 --- a/spec/models/user_tag_spec.rb +++ b/spec/models/user_tag_spec.rb @@ -1,5 +1,29 @@ require 'rails_helper' -RSpec.describe UserTag, :type => :model do - pending "add some examples to (or delete) #{__FILE__}" +RSpec.describe UserTag, type: :model do + describe '.normalize_keyword' do + let(:keyword) { 'keyword' } + subject(:result) { described_class.normalize_keyword(keyword) } + + context 'includes blank' do + let(:keyword) { "A B C\rD\nE\tF\fG\vH" } + it 'removes blank characters and full-width blank' do + expect(result).to eq 'ABCDEFGH' + end + end + + context 'includes HIRAGANA / KATAKANA' do + let(:keyword) { '漢字カタカナひらがなカタカナ' } + it 'converts hankaku-kana to zenkaku-kana' do + expect(result).to eq '漢字カタカナひらがなカタカナ' + end + end + + context 'includes ZENKAKU alphabet and mark' do + let(:keyword) { 'javascript function()' } + it 'converts to ascii' do + expect(result).to eq 'javascriptfunction()' + end + end + end end From 0039d0a093448e8f7187250cc3a9a48163cb22eb Mon Sep 17 00:00:00 2001 From: "SHIOYA, Hiromu" Date: Thu, 15 Jan 2015 19:08:57 +0900 Subject: [PATCH 04/21] implement UserTag.hash_keyword --- app/models/user_tag.rb | 4 ++++ spec/models/user_tag_spec.rb | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/app/models/user_tag.rb b/app/models/user_tag.rb index c708158..4e45f72 100644 --- a/app/models/user_tag.rb +++ b/app/models/user_tag.rb @@ -7,4 +7,8 @@ class UserTag < ActiveRecord::Base def self.normalize_keyword(keyword) NKF.nkf('-w -X -Z', keyword.gsub(/[\s ]/, '')) end + + def self.hash_keyword(keyword) + Digest::SHA256.hexdigest(self.normalize_keyword(keyword).downcase) + end end diff --git a/spec/models/user_tag_spec.rb b/spec/models/user_tag_spec.rb index 8bdf859..364bf6f 100644 --- a/spec/models/user_tag_spec.rb +++ b/spec/models/user_tag_spec.rb @@ -26,4 +26,14 @@ end end end + + describe '.hash_keyword' do + let(:keyword) { 'A B Cカタカナひらがなfunction()' } + let(:normalized_and_downcased_keyword) { 'abcカタカナひらがなfunction()' } + subject(:result) { described_class.hash_keyword(keyword) } + + it 'creates digest by keyword that normalized and downcased' do + expect(result).to eq described_class.hash_keyword(normalized_and_downcased_keyword) + end + end end From fdaa9cdf30e5df5fa761c2d267f78be49e6eadfe Mon Sep 17 00:00:00 2001 From: "SHIOYA, Hiromu" Date: Thu, 15 Jan 2015 19:14:27 +0900 Subject: [PATCH 05/21] implement UserTag.retrieve (WIP) * always create new tag, yet --- app/models/user_tag.rb | 4 ++++ spec/models/user_tag_spec.rb | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/app/models/user_tag.rb b/app/models/user_tag.rb index 4e45f72..dbe12ac 100644 --- a/app/models/user_tag.rb +++ b/app/models/user_tag.rb @@ -4,6 +4,10 @@ class UserTag < ActiveRecord::Base has_many :user_taggings has_many :users, through: :user_taggings + def self.retrieve(name) + create(name: name, search_hash: hash_keyword(name)) + end + def self.normalize_keyword(keyword) NKF.nkf('-w -X -Z', keyword.gsub(/[\s ]/, '')) end diff --git a/spec/models/user_tag_spec.rb b/spec/models/user_tag_spec.rb index 364bf6f..2d6cca7 100644 --- a/spec/models/user_tag_spec.rb +++ b/spec/models/user_tag_spec.rb @@ -1,8 +1,16 @@ require 'rails_helper' RSpec.describe UserTag, type: :model do + let(:keyword) { 'keyword' } + + describe '.retrieve' do + subject(:tag) { described_class.retrieve(keyword) } + context 'when new keyword given' do + it { expect { tag }.to change { described_class.count }.from(0).to(1) } + end + end + describe '.normalize_keyword' do - let(:keyword) { 'keyword' } subject(:result) { described_class.normalize_keyword(keyword) } context 'includes blank' do From e92297611652bd655c4839a67d9e6ec1574694ec Mon Sep 17 00:00:00 2001 From: "SHIOYA, Hiromu" Date: Thu, 15 Jan 2015 19:28:45 +0900 Subject: [PATCH 06/21] implement UserTag.retrieve * find existing keyword * create with normalized name --- app/models/user_tag.rb | 2 +- spec/models/user_tag_spec.rb | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/models/user_tag.rb b/app/models/user_tag.rb index dbe12ac..72b3d97 100644 --- a/app/models/user_tag.rb +++ b/app/models/user_tag.rb @@ -5,7 +5,7 @@ class UserTag < ActiveRecord::Base has_many :users, through: :user_taggings def self.retrieve(name) - create(name: name, search_hash: hash_keyword(name)) + create_with(name: normalize_keyword(name)).find_or_create_by(search_hash: hash_keyword(name)) end def self.normalize_keyword(keyword) diff --git a/spec/models/user_tag_spec.rb b/spec/models/user_tag_spec.rb index 2d6cca7..5929047 100644 --- a/spec/models/user_tag_spec.rb +++ b/spec/models/user_tag_spec.rb @@ -5,9 +5,15 @@ describe '.retrieve' do subject(:tag) { described_class.retrieve(keyword) } + context 'when new keyword given' do it { expect { tag }.to change { described_class.count }.from(0).to(1) } end + + context 'when keyword already exist' do + before { described_class.retrieve(keyword) } + it { expect { tag }.to_not change { described_class.count }.from(1) } + end end describe '.normalize_keyword' do From 6790fe9674b3f4f94ae50cb7691cea62d1884606 Mon Sep 17 00:00:00 2001 From: "SHIOYA, Hiromu" Date: Thu, 15 Jan 2015 19:33:06 +0900 Subject: [PATCH 07/21] improve spec of UserTag.retrieve --- spec/models/user_tag_spec.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/spec/models/user_tag_spec.rb b/spec/models/user_tag_spec.rb index 5929047..fbef9c0 100644 --- a/spec/models/user_tag_spec.rb +++ b/spec/models/user_tag_spec.rb @@ -1,19 +1,27 @@ require 'rails_helper' RSpec.describe UserTag, type: :model do - let(:keyword) { 'keyword' } + let(:keyword) { 'normalized K e y w o r d' } describe '.retrieve' do subject(:tag) { described_class.retrieve(keyword) } context 'when new keyword given' do it { expect { tag }.to change { described_class.count }.from(0).to(1) } + it 'creates with normalized keyword' do + expect(tag.name).to eq 'normalizedKeyword' + end end context 'when keyword already exist' do before { described_class.retrieve(keyword) } it { expect { tag }.to_not change { described_class.count }.from(1) } end + + context 'when same keyword already exist but with another case' do + before { described_class.retrieve(keyword.upcase) } + it { expect { tag }.to_not change { described_class.count }.from(1) } + end end describe '.normalize_keyword' do From 583715a09335bf9f352bb0a38c14f80303139787 Mon Sep 17 00:00:00 2001 From: "SHIOYA, Hiromu" Date: Thu, 15 Jan 2015 19:45:15 +0900 Subject: [PATCH 08/21] implement UserTag.attach --- app/models/user_tag.rb | 7 +++++++ spec/models/user_tag_spec.rb | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/app/models/user_tag.rb b/app/models/user_tag.rb index 72b3d97..bac1d29 100644 --- a/app/models/user_tag.rb +++ b/app/models/user_tag.rb @@ -15,4 +15,11 @@ def self.normalize_keyword(keyword) def self.hash_keyword(keyword) Digest::SHA256.hexdigest(self.normalize_keyword(keyword).downcase) end + + def attach(user) + unless (user.tags.include?(self)) + UserTagging.create(user_id: user.id, user_tag_id: self.id) + end + self + end end diff --git a/spec/models/user_tag_spec.rb b/spec/models/user_tag_spec.rb index fbef9c0..e10b32e 100644 --- a/spec/models/user_tag_spec.rb +++ b/spec/models/user_tag_spec.rb @@ -58,4 +58,22 @@ expect(result).to eq described_class.hash_keyword(normalized_and_downcased_keyword) end end + + describe '#attach' do + let(:first_tag) { described_class.retrieve('first tag') } + let(:second_tag) { described_class.retrieve('second tag') } + let(:alice) { create(:user) } + + context 'with tag that is not attached' do + subject(:attach) { first_tag.attach(alice) } + it { expect { attach }.to change { alice.tags.count }.from(0).to(1) } + end + + context 'with tag that is already attached' do + before { first_tag.attach(alice) } + subject(:attach) { first_tag.attach(alice) } + it { expect { attach }.to_not change { alice.tags.count }.from(1) } + it { expect { second_tag.attach(alice) }.to change { alice.tags.count }.from(1).to(2) } + end + end end From 67df655b4e7e0601a3b4a19f06da53092428a292 Mon Sep 17 00:00:00 2001 From: "SHIOYA, Hiromu" Date: Thu, 15 Jan 2015 20:10:03 +0900 Subject: [PATCH 09/21] implement User#tag_keyword --- app/models/user.rb | 4 ++++ spec/models/user_spec.rb | 26 +++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/app/models/user.rb b/app/models/user.rb index 1fb685e..868518d 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -22,4 +22,8 @@ class User < ActiveRecord::Base scope :order_by_nick, -> { order(:nick) } scope :recent, -> { order(updated_at: :desc) } scope :order_by_member_number, -> { order(:member_number) } + + def tag_keyword(keyword) + UserTag.retrieve(keyword).attach(self) + end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 6ebe9f8..0d74b72 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1,9 +1,9 @@ require 'rails_helper' RSpec.describe User, type: :model do - let(:user) { build(:user) } describe 'validations' do + let(:user) { build(:user) } subject(:user) { build(:user, attr) } let(:attr) { { } } @@ -168,4 +168,28 @@ it { expect(User.order_by_member_number.all).to match([bob, alice, charlie]) } end end + + describe 'tag operation' do + let(:user) { create(:user) } + + describe '#tag_keyword' do + let(:keyword) { 'a keyword' } + let(:another_keyword) { 'another keyword' } + subject(:tagging) { user.tag_keyword(keyword) } + + context 'with a keyword' do + it { expect { tagging }.to change { user.tags.count }.from(0).to(1) } + end + + context 'repeat with same keyword' do + before { user.tag_keyword(keyword) } + it { expect { tagging }.to_not change { user.tags.count }.from(1) } + end + + context 'repeat with another keyword' do + before { user.tag_keyword(another_keyword) } + it { expect { tagging }.to change { user.tags.count }.from(1).to(2) } + end + end + end end From e6db4f9a7ef06adfed8a560e75a19e6a2d066909 Mon Sep 17 00:00:00 2001 From: "SHIOYA, Hiromu" Date: Thu, 15 Jan 2015 20:35:06 +0900 Subject: [PATCH 10/21] implement User#detach --- app/models/user.rb | 4 ++++ spec/models/user_spec.rb | 19 +++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index 868518d..aec6ff7 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -26,4 +26,8 @@ class User < ActiveRecord::Base def tag_keyword(keyword) UserTag.retrieve(keyword).attach(self) end + + def detach(tag) + user_taggings.find_by(user_tag_id: tag).try(:destroy) + end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 0d74b72..9407548 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -171,10 +171,10 @@ describe 'tag operation' do let(:user) { create(:user) } + let(:keyword) { 'a keyword' } + let(:another_keyword) { 'another keyword' } describe '#tag_keyword' do - let(:keyword) { 'a keyword' } - let(:another_keyword) { 'another keyword' } subject(:tagging) { user.tag_keyword(keyword) } context 'with a keyword' do @@ -191,5 +191,20 @@ it { expect { tagging }.to change { user.tags.count }.from(1).to(2) } end end + + describe '#detach_tag' do + let(:tag) { UserTag.retrieve(keyword) } + subject(:detach) { user.detach(tag) } + before { user.tag_keyword(another_keyword) } + + context 'with not attached tag' do + it { expect { detach }.to_not change { user.tags.count }.from(1) } + end + + context 'with attached tag' do + before { user.tag_keyword(keyword) } + it { expect { detach }.to change { user.tags.count }.from(2).to(1) } + end + end end end From aec6dec52b91f925acca7bb5cc340e669895e8dd Mon Sep 17 00:00:00 2001 From: "SHIOYA, Hiromu" Date: Fri, 16 Jan 2015 18:31:16 +0900 Subject: [PATCH 11/21] [WIP] enable to attach / detach tag to user * add routes * add controller(DUMMY) * add form to attach tag --- app/controllers/user_tags_controller.rb | 23 +++++++++++++++++++++++ app/views/users/show.html.haml | 18 ++++++++++++++++++ config/routes.rb | 4 ++++ 3 files changed, 45 insertions(+) create mode 100644 app/controllers/user_tags_controller.rb diff --git a/app/controllers/user_tags_controller.rb b/app/controllers/user_tags_controller.rb new file mode 100644 index 0000000..a9d5b7a --- /dev/null +++ b/app/controllers/user_tags_controller.rb @@ -0,0 +1,23 @@ +class UserTagsController < ApplicationController + before_action :authenticate_user! + before_action :set_target_user + + def attach + redirect_to home_path(@user.nick) + end + + def detach + redirect_to home_path(@user.nick) + end + + private + + def set_target_user + @user = User.find_by(nick: params[:nick]) + raise ActiveRecord::RecordNotFound unless @user + end + + def user_tag_params + params.require(:user_tag).permit(:user_id, :name) + end +end diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 6a97727..8915e2a 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -34,6 +34,24 @@ Member Number %td = @user.member_number + %div.posts + %h1.content-subhead + %section.post + %header.post-header + %h2 + %i.fa.fa-tags.fa-lg + Tags + %div.post-description + %div.user_tags + - @user.tags.each do |tag| + %p.user_tag= tag.name + - if user_signed_in? + %div.attach_user_tag + = form_tag(user_tag_attach_path(@user.nick)) do + = text_field_tag :name + = button_tag do + %i.fa.fa-tag.fa-lg + Attach %div.posts %h1.content-subhead %section.post diff --git a/config/routes.rb b/config/routes.rb index 4c88ff1..cb45cf4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -13,5 +13,9 @@ scope ':nick' do get '/', controller: :users, action: :show, as: :home + scope :user_tags, controller: :user_tags, as: :user_tag, path: :tag do + post :attach + post :detach + end end end From ab0efd2a76a5cecc04f41fbe1d79aaa0550e3729 Mon Sep 17 00:00:00 2001 From: "SHIOYA, Hiromu" Date: Sat, 17 Jan 2015 00:25:23 +0900 Subject: [PATCH 12/21] enable to attach tag to user * attach tag to user * add spec --- app/controllers/user_tags_controller.rb | 1 + spec/controllers/user_tags_controller_spec.rb | 56 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 spec/controllers/user_tags_controller_spec.rb diff --git a/app/controllers/user_tags_controller.rb b/app/controllers/user_tags_controller.rb index a9d5b7a..6373a35 100644 --- a/app/controllers/user_tags_controller.rb +++ b/app/controllers/user_tags_controller.rb @@ -3,6 +3,7 @@ class UserTagsController < ApplicationController before_action :set_target_user def attach + @user.tag_keyword(params[:name]) redirect_to home_path(@user.nick) end diff --git a/spec/controllers/user_tags_controller_spec.rb b/spec/controllers/user_tags_controller_spec.rb new file mode 100644 index 0000000..46e570a --- /dev/null +++ b/spec/controllers/user_tags_controller_spec.rb @@ -0,0 +1,56 @@ +require 'rails_helper' + +RSpec.describe UserTagsController, type: :controller do + let!(:alice) { create(:user, nick: 'alice') } + let!(:bob) { create(:user, nick: 'bob') } + let(:tag_name) { 'tag_name' } + + describe '#attach' do + let(:target_nick) { alice.nick } + subject(:attach) { post :attach, nick: target_nick, name: tag_name } + + context 'when attach to myself' do + before { sign_in alice } + + context 'when new keyword is given' do + it 'create and attach new tag to alice' do + expect(alice.tags.count).to eq 0 + expect(UserTag.count).to eq 0 + attach + expect(alice.tags.count).to eq 1 + expect(UserTag.count).to eq 1 + end + end + + context 'when keyword that already exist is given' do + before { UserTag.retrieve(tag_name) } + it 'attach tag to alice' do + expect(alice.tags.count).to eq 0 + expect(UserTag.count).to eq 1 + attach + expect(alice.tags.count).to eq 1 + expect(UserTag.count).to eq 1 + end + end + end + + context 'when attach to other user' do + before { sign_in bob } + + it 'create and attach new tag to alice' do + expect { attach }.to change { alice.tags.count }.from(0).to(1) + end + end + + context 'when user does not exist' do + let(:target_nick) { 'NOT_EXISTING_USER' } + before { sign_in alice } + it { expect { attach }.to raise_error ActiveRecord::RecordNotFound } + end + + context 'when guest user' do + before { attach } + specify { expect(response).to redirect_to new_user_session_path } + end + end +end From 5baa9622aba859d5472f4119945375541883bea0 Mon Sep 17 00:00:00 2001 From: "SHIOYA, Hiromu" Date: Sat, 17 Jan 2015 17:29:23 +0900 Subject: [PATCH 13/21] enable to detach tag from user * modify routes, controller and view * add spec * improve style --- app/assets/stylesheets/users/profile.css.scss | 12 +++++++ app/controllers/user_tags_controller.rb | 4 +++ app/views/users/show.html.haml | 9 ++++- config/routes.rb | 2 +- spec/controllers/user_tags_controller_spec.rb | 33 +++++++++++++++++++ 5 files changed, 58 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/users/profile.css.scss b/app/assets/stylesheets/users/profile.css.scss index 421397b..4c42b60 100755 --- a/app/assets/stylesheets/users/profile.css.scss +++ b/app/assets/stylesheets/users/profile.css.scss @@ -68,6 +68,17 @@ a.edit_link { font-size: 0.7em; } +form.tag_detach_form { + display: inline; + button { + border: none; + background: none; + font-size: 50%; + margin: 0; + padding: 0; + } +} + .sidebar { background: rgb(61, 79, 93); color: #fff; @@ -220,3 +231,4 @@ img.gravatar_icon { white-space: pre-wrap; font-family: Consolas,"Liberation Mono",Menlo,Courier,monospace; } + diff --git a/app/controllers/user_tags_controller.rb b/app/controllers/user_tags_controller.rb index 6373a35..4e4a860 100644 --- a/app/controllers/user_tags_controller.rb +++ b/app/controllers/user_tags_controller.rb @@ -8,6 +8,10 @@ def attach end def detach + if view_context.myself?(@user) + tag = UserTag.find(params[:tag_id]) + @user.detach(tag) if tag.present? + end redirect_to home_path(@user.nick) end diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 8915e2a..16f90e9 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -44,7 +44,14 @@ %div.post-description %div.user_tags - @user.tags.each do |tag| - %p.user_tag= tag.name + %div.user_tag + %i.fa.fa-tag.fa-lg + = tag.name + - if myself?(@user) + = form_tag(user_tag_detach_path(@user.nick), method: :delete, class: 'tag_detach_form', data: { confirm: 'foobar' }) do + = hidden_field_tag :tag_id, tag.id + = button_tag do + %i.fa.fa-remove.fa-lg - if user_signed_in? %div.attach_user_tag = form_tag(user_tag_attach_path(@user.nick)) do diff --git a/config/routes.rb b/config/routes.rb index cb45cf4..7a9492a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -15,7 +15,7 @@ get '/', controller: :users, action: :show, as: :home scope :user_tags, controller: :user_tags, as: :user_tag, path: :tag do post :attach - post :detach + delete :detach end end end diff --git a/spec/controllers/user_tags_controller_spec.rb b/spec/controllers/user_tags_controller_spec.rb index 46e570a..9f584cb 100644 --- a/spec/controllers/user_tags_controller_spec.rb +++ b/spec/controllers/user_tags_controller_spec.rb @@ -53,4 +53,37 @@ specify { expect(response).to redirect_to new_user_session_path } end end + + describe '#detach' do + let(:tag) { UserTag.retrieve(tag_name) } + let(:tag_id) { tag.id } + let(:target_nick) { alice.nick } + subject(:detach) { delete :detach, nick: target_nick, tag_id: tag_id } + before { tag.attach(alice) } + + context 'when guest user' do + before { detach } + specify { expect(response).to redirect_to new_user_session_path } + end + + context 'when alice' do + before { sign_in alice } + + context 'with existing tag' do + it 'removes tag from user' do + expect { detach }.to change { alice.tags.count }.from(1).to(0) + end + end + + context 'with invalid tag_id' do + let(:tag_id) { UserTag.maximum(:id) + 1 } + it { expect { detach }.to raise_error ActiveRecord::RecordNotFound } + end + end + + context 'when bob' do + before { sign_in bob } + it { expect { detach }.to_not change { alice.tags.count }.from(1) } + end + end end From 09d7b65dbc9e6a45bea5dea1ad30c00ba8239275 Mon Sep 17 00:00:00 2001 From: "SHIOYA, Hiromu" Date: Sat, 17 Jan 2015 17:52:49 +0900 Subject: [PATCH 14/21] reject blank tag --- app/models/user.rb | 2 +- app/models/user_tag.rb | 4 +++- spec/models/user_tag_spec.rb | 5 +++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index aec6ff7..f91d279 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -24,7 +24,7 @@ class User < ActiveRecord::Base scope :order_by_member_number, -> { order(:member_number) } def tag_keyword(keyword) - UserTag.retrieve(keyword).attach(self) + UserTag.retrieve(keyword).try(:attach, self) end def detach(tag) diff --git a/app/models/user_tag.rb b/app/models/user_tag.rb index bac1d29..9a660e0 100644 --- a/app/models/user_tag.rb +++ b/app/models/user_tag.rb @@ -5,7 +5,9 @@ class UserTag < ActiveRecord::Base has_many :users, through: :user_taggings def self.retrieve(name) - create_with(name: normalize_keyword(name)).find_or_create_by(search_hash: hash_keyword(name)) + keyword = normalize_keyword(name) + return nil if keyword.blank? + create_with(name: keyword).find_or_create_by(search_hash: hash_keyword(name)) end def self.normalize_keyword(keyword) diff --git a/spec/models/user_tag_spec.rb b/spec/models/user_tag_spec.rb index e10b32e..c31f8e9 100644 --- a/spec/models/user_tag_spec.rb +++ b/spec/models/user_tag_spec.rb @@ -6,6 +6,11 @@ describe '.retrieve' do subject(:tag) { described_class.retrieve(keyword) } + context 'when blank keywrod given' do + let(:keyword) { '' } + it { expect(tag).to be_nil } + end + context 'when new keyword given' do it { expect { tag }.to change { described_class.count }.from(0).to(1) } it 'creates with normalized keyword' do From 473cee556d7b41029884453bbff52f96f95d339f Mon Sep 17 00:00:00 2001 From: "SHIOYA, Hiromu" Date: Mon, 19 Jan 2015 07:38:27 +0900 Subject: [PATCH 15/21] include and precompile application.js --- app/views/layouts/application.html.haml | 1 + config/application.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index d361de6..da9a073 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -3,6 +3,7 @@ %head %title Ena = csrf_meta_tags + = javascript_include_tag 'application' = yield :header %body = content_for?(:content) ? yield(:content) : yield diff --git a/config/application.rb b/config/application.rb index 0210233..e0190aa 100644 --- a/config/application.rb +++ b/config/application.rb @@ -14,7 +14,7 @@ class Application < Rails::Application config.autoload_paths += [ Rails.root.join('lib/autoload'), ] - config.assets.precompile += %w(*.png *.jpg *.jpeg *.gif *.css) + config.assets.precompile += %w(*.png *.jpg *.jpeg *.gif *.css *.js) config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } config.generators do |g| From 5b18dd8c848e1d595e3720acaf0bb202abd4e4ef Mon Sep 17 00:00:00 2001 From: "SHIOYA, Hiromu" Date: Mon, 19 Jan 2015 08:01:21 +0900 Subject: [PATCH 16/21] improve style of tags * import cleafix * modify style * add confirm before detach tag --- app/assets/stylesheets/application.css.scss | 1 + app/assets/stylesheets/users/profile.css.scss | 33 ++++++++++++++----- app/views/users/show.html.haml | 4 +-- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss index b8b3960..92f5049 100644 --- a/app/assets/stylesheets/application.css.scss +++ b/app/assets/stylesheets/application.css.scss @@ -14,6 +14,7 @@ @import 'compass'; @import 'font-awesome'; @import 'pure'; +@import 'compass/utilities/general/clearfix'; @import 'normalize'; @import 'pygments_default'; diff --git a/app/assets/stylesheets/users/profile.css.scss b/app/assets/stylesheets/users/profile.css.scss index 4c42b60..6538535 100755 --- a/app/assets/stylesheets/users/profile.css.scss +++ b/app/assets/stylesheets/users/profile.css.scss @@ -68,14 +68,31 @@ a.edit_link { font-size: 0.7em; } -form.tag_detach_form { - display: inline; - button { - border: none; - background: none; - font-size: 50%; - margin: 0; - padding: 0; + +.user_tags { + @include clearfix; + margin: 16px 4px; + + .user_tag { + @include border-radius(16px); + float: left; + background-color: whitesmoke; + border: 1px solid silver; + padding: 2px 8px; + margin: 8px 4px; + } + + form.tag_detach_form { + display: inline; + button { + position: relative; + top: -0.5em; + border: none; + background: none; + font-size: 50%; + margin: 0; + padding: 0; + } } } diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 16f90e9..81cb74d 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -48,7 +48,7 @@ %i.fa.fa-tag.fa-lg = tag.name - if myself?(@user) - = form_tag(user_tag_detach_path(@user.nick), method: :delete, class: 'tag_detach_form', data: { confirm: 'foobar' }) do + = form_tag(user_tag_detach_path(@user.nick), method: :delete, class: "tag_detach_form", data: { confirm: "detach tag [#{tag.name}] from you. are yo sure?" }) do = hidden_field_tag :tag_id, tag.id = button_tag do %i.fa.fa-remove.fa-lg @@ -56,7 +56,7 @@ %div.attach_user_tag = form_tag(user_tag_attach_path(@user.nick)) do = text_field_tag :name - = button_tag do + = button_tag class: 'pure-button' do %i.fa.fa-tag.fa-lg Attach %div.posts From 4a3b8cfe245a1a0df0c4e47590926a1883335cbe Mon Sep 17 00:00:00 2001 From: "SHIOYA, Hiromu" Date: Mon, 19 Jan 2015 14:01:49 +0900 Subject: [PATCH 17/21] prepare to implement #index and #show for user_tags * add route, controller and dummy template * prepare current user at application_controller * reserve 'user_tags' for user name --- app/controllers/application_controller.rb | 6 ++++++ app/controllers/user_tags_controller.rb | 12 ++++++++++-- app/controllers/users_controller.rb | 1 - app/models/user.rb | 2 +- app/views/users/_common_linkbar.html.haml | 3 +++ config/routes.rb | 2 ++ 6 files changed, 22 insertions(+), 4 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 4073ba7..59f6393 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -8,6 +8,8 @@ class ApplicationController < ActionController::Base ] before_action :configure_permitted_parameters, if: :devise_controller? + before_action :prepare_current_user + def configure_permitted_parameters PERMITED_COLUMNS_FOR_USER.each do |column| devise_parameter_sanitizer.for(:sign_up) << column @@ -17,4 +19,8 @@ def configure_permitted_parameters end protect_from_forgery with: :exception + + def prepare_current_user + @user = current_user if user_signed_in? + end end diff --git a/app/controllers/user_tags_controller.rb b/app/controllers/user_tags_controller.rb index 4e4a860..eefc589 100644 --- a/app/controllers/user_tags_controller.rb +++ b/app/controllers/user_tags_controller.rb @@ -1,6 +1,8 @@ class UserTagsController < ApplicationController - before_action :authenticate_user! - before_action :set_target_user + before_action :authenticate_user!, only: [:attach, :detach] + before_action :set_target_user, only: [:attach, :detach] + + layout 'users' def attach @user.tag_keyword(params[:name]) @@ -15,6 +17,12 @@ def detach redirect_to home_path(@user.nick) end + def index + end + + def show + end + private def set_target_user diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index abdbc3a..3d7ab10 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -19,7 +19,6 @@ def show end def list - @user = current_user relation = case params[:sort] when 'recent' then User.recent when 'member_number' then User.order_by_member_number diff --git a/app/models/user.rb b/app/models/user.rb index f91d279..912ec2b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -4,7 +4,7 @@ class User < ActiveRecord::Base format: /\A[a-zA-Z0-9_\-]+\Z/, uniqueness: { case_sensitive: false }, length: { minimum: 3, maximum: 240 }, - username_not_reserved: true + username_not_reserved: { additional_reserved_names: %w[foo bar] }, } has_one :resume, class_name: 'UserResume' diff --git a/app/views/users/_common_linkbar.html.haml b/app/views/users/_common_linkbar.html.haml index de51f0d..6296a3c 100644 --- a/app/views/users/_common_linkbar.html.haml +++ b/app/views/users/_common_linkbar.html.haml @@ -6,6 +6,9 @@ = link_to users_list_path, class: 'pure-button' do %i.fa.fa-users.fa-lg + = link_to user_tags_path, class: 'pure-button' do + %i.fa.fa-tags.fa-lg + - if user_signed_in? = form_tag(destroy_user_session_path, method: :delete) do %button.pure-button{ type: 'submit' } diff --git a/config/routes.rb b/config/routes.rb index 7a9492a..dc7bb66 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -11,6 +11,8 @@ resource :user_resumes, controller: '/user_resumes', as: :resume, path: :resume end + resources :user_tags, only: [:index, :show] + scope ':nick' do get '/', controller: :users, action: :show, as: :home scope :user_tags, controller: :user_tags, as: :user_tag, path: :tag do From dc6630c5df841309556c474571483c018feb3b2c Mon Sep 17 00:00:00 2001 From: "SHIOYA, Hiromu" Date: Mon, 19 Jan 2015 14:14:41 +0900 Subject: [PATCH 18/21] implement user_tags#index to show list of user tags * partialize template * fetch and paginate user tags --- app/controllers/user_tags_controller.rb | 3 +++ app/views/user_tags/_tags.html.haml | 11 +++++++++++ app/views/user_tags/index.html.haml | 11 +++++++++++ app/views/user_tags/show.html.haml | 2 ++ app/views/users/show.html.haml | 11 +---------- 5 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 app/views/user_tags/_tags.html.haml create mode 100644 app/views/user_tags/index.html.haml create mode 100644 app/views/user_tags/show.html.haml diff --git a/app/controllers/user_tags_controller.rb b/app/controllers/user_tags_controller.rb index eefc589..7d7df79 100644 --- a/app/controllers/user_tags_controller.rb +++ b/app/controllers/user_tags_controller.rb @@ -1,4 +1,6 @@ class UserTagsController < ApplicationController + TAGS_PER_PAGE = 100 + before_action :authenticate_user!, only: [:attach, :detach] before_action :set_target_user, only: [:attach, :detach] @@ -18,6 +20,7 @@ def detach end def index + @tags = UserTag.page(params[:page]).per(TAGS_PER_PAGE) end def show diff --git a/app/views/user_tags/_tags.html.haml b/app/views/user_tags/_tags.html.haml new file mode 100644 index 0000000..d05947e --- /dev/null +++ b/app/views/user_tags/_tags.html.haml @@ -0,0 +1,11 @@ +- user ||= user +%div.user_tags + - tags.each do |tag| + %div.user_tag + %i.fa.fa-tag.fa-lg + = tag.name + - if user.present? && myself?(user) + = form_tag(user_tag_detach_path(user.nick), method: :delete, class: "tag_detach_form", data: { confirm: "detach tag [#{tag.name}] from you. are yo sure?" }) do + = hidden_field_tag :tag_id, tag.id + = button_tag do + %i.fa.fa-remove.fa-lg diff --git a/app/views/user_tags/index.html.haml b/app/views/user_tags/index.html.haml new file mode 100644 index 0000000..e1a8a5f --- /dev/null +++ b/app/views/user_tags/index.html.haml @@ -0,0 +1,11 @@ +%div.content.pure-u-1.pure-u-md-3-4 + %div + %div.posts + %h1.content-subhead + %section.post + %header.post-header + %h2 + User Tags + %div.post-description + = render 'tags', tags: @tags + = paginate @tags diff --git a/app/views/user_tags/show.html.haml b/app/views/user_tags/show.html.haml new file mode 100644 index 0000000..216f994 --- /dev/null +++ b/app/views/user_tags/show.html.haml @@ -0,0 +1,2 @@ +show + diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 81cb74d..e53f3d8 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -42,16 +42,7 @@ %i.fa.fa-tags.fa-lg Tags %div.post-description - %div.user_tags - - @user.tags.each do |tag| - %div.user_tag - %i.fa.fa-tag.fa-lg - = tag.name - - if myself?(@user) - = form_tag(user_tag_detach_path(@user.nick), method: :delete, class: "tag_detach_form", data: { confirm: "detach tag [#{tag.name}] from you. are yo sure?" }) do - = hidden_field_tag :tag_id, tag.id - = button_tag do - %i.fa.fa-remove.fa-lg + = render 'user_tags/tags', tags: @user.tags, user: @user - if user_signed_in? %div.attach_user_tag = form_tag(user_tag_attach_path(@user.nick)) do From daa484cf9583ed0fdc2d8f6daaeb52863f69bf1a Mon Sep 17 00:00:00 2001 From: "SHIOYA, Hiromu" Date: Mon, 19 Jan 2015 14:23:02 +0900 Subject: [PATCH 19/21] implement user_tags#show * partilaize list of users * link from each tag to detail of tag --- app/controllers/user_tags_controller.rb | 2 ++ app/views/user_tags/_tags.html.haml | 2 +- app/views/user_tags/index.html.haml | 1 + app/views/user_tags/show.html.haml | 14 ++++++++++++-- app/views/users/list.html.haml | 18 +----------------- 5 files changed, 17 insertions(+), 20 deletions(-) diff --git a/app/controllers/user_tags_controller.rb b/app/controllers/user_tags_controller.rb index 7d7df79..dfcac9e 100644 --- a/app/controllers/user_tags_controller.rb +++ b/app/controllers/user_tags_controller.rb @@ -24,6 +24,8 @@ def index end def show + @tag = UserTag.find(params[:id]) + @members = @tag.users.page(params[:page]).per(UsersController::MEMBERS_PER_PAGE) end private diff --git a/app/views/user_tags/_tags.html.haml b/app/views/user_tags/_tags.html.haml index d05947e..d9bbfe5 100644 --- a/app/views/user_tags/_tags.html.haml +++ b/app/views/user_tags/_tags.html.haml @@ -3,7 +3,7 @@ - tags.each do |tag| %div.user_tag %i.fa.fa-tag.fa-lg - = tag.name + = link_to tag.name, user_tag_path(tag) - if user.present? && myself?(user) = form_tag(user_tag_detach_path(user.nick), method: :delete, class: "tag_detach_form", data: { confirm: "detach tag [#{tag.name}] from you. are yo sure?" }) do = hidden_field_tag :tag_id, tag.id diff --git a/app/views/user_tags/index.html.haml b/app/views/user_tags/index.html.haml index e1a8a5f..e44213f 100644 --- a/app/views/user_tags/index.html.haml +++ b/app/views/user_tags/index.html.haml @@ -5,6 +5,7 @@ %section.post %header.post-header %h2 + %i.fa.fa-tags.fa-lg User Tags %div.post-description = render 'tags', tags: @tags diff --git a/app/views/user_tags/show.html.haml b/app/views/user_tags/show.html.haml index 216f994..f27cddf 100644 --- a/app/views/user_tags/show.html.haml +++ b/app/views/user_tags/show.html.haml @@ -1,2 +1,12 @@ -show - +%div.content.pure-u-1.pure-u-md-3-4 + %div + %div.posts + %h1.content-subhead + %section.post + %header.post-header + %h2 + %i.fa.fa-tag.fa-lg + = @tag.name + %div.post-description + = render 'users/user_list', members: @members + = paginate @members diff --git a/app/views/users/list.html.haml b/app/views/users/list.html.haml index 722e7dd..4455114 100644 --- a/app/views/users/list.html.haml +++ b/app/views/users/list.html.haml @@ -7,21 +7,5 @@ %h2 Member List %div.post-description - %table.user_list.pure-table - %thead - %tr - %th icon - %th nick - %th name - %th member number - %th last update - %tbody - - @members.each_with_index do |member, line| - %tr{ class: line.odd? ? 'pure-table-odd' : '' } - %td= gravatar_image_tag(member) - %td - = link_to member.nick, home_path(member.nick) - %td= member.name - %td= member.member_number - %td= member.updated_at + = render 'user_list', members: @members = paginate @members From ae8694c1bc64457d5d38e37f555c5897561e89ac Mon Sep 17 00:00:00 2001 From: "SHIOYA, Hiromu" Date: Mon, 19 Jan 2015 15:29:53 +0900 Subject: [PATCH 20/21] add controller spec for #index and #show * modify factory --- spec/controllers/user_tags_controller_spec.rb | 36 +++++++++++++++++++ spec/factories/user_tags.rb | 7 ++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/spec/controllers/user_tags_controller_spec.rb b/spec/controllers/user_tags_controller_spec.rb index 9f584cb..d6ca3d0 100644 --- a/spec/controllers/user_tags_controller_spec.rb +++ b/spec/controllers/user_tags_controller_spec.rb @@ -5,6 +5,42 @@ let!(:bob) { create(:user, nick: 'bob') } let(:tag_name) { 'tag_name' } + describe '#index' do + before do + 5.times { create(:user_tag) } + get(:index) + end + + it 'assigns list of tags' do + expect(assigns[:tags]).to match_array UserTag.page(1) + end + end + + describe '#show' do + let(:tag_id) { 0 } + subject(:show) { get :show, id: tag_id } + + context 'when tag does not exist' do + specify { expect { show }.to raise_error ActiveRecord::RecordNotFound } + end + + context 'when tag exists' do + let!(:tag) { create(:user_tag) } + let(:tag_id) { tag.id } + + before do + tag.attach(alice) + tag.attach(bob) + show + end + + it 'assigns tag and members' do + expect(assigns[:members]).to match_array User.page(1) + expect(assigns[:tag]).to eq UserTag.first + end + end + end + describe '#attach' do let(:target_nick) { alice.nick } subject(:attach) { post :attach, nick: target_nick, name: tag_name } diff --git a/spec/factories/user_tags.rb b/spec/factories/user_tags.rb index 453224b..65d295e 100644 --- a/spec/factories/user_tags.rb +++ b/spec/factories/user_tags.rb @@ -1,7 +1,10 @@ FactoryGirl.define do factory :user_tag do - name "" -search_hash "MyString" + name + search_hash end + sequence :search_hash do |n| + Digest::SHA256.hexdigest(n.to_s) + end end From e815b318047a161cb2a9edf67af6bdc106100f71 Mon Sep 17 00:00:00 2001 From: "SHIOYA, Hiromu" Date: Mon, 19 Jan 2015 18:51:49 +0900 Subject: [PATCH 21/21] commit missing template --- app/views/users/_user_list.html.haml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 app/views/users/_user_list.html.haml diff --git a/app/views/users/_user_list.html.haml b/app/views/users/_user_list.html.haml new file mode 100644 index 0000000..814e2fd --- /dev/null +++ b/app/views/users/_user_list.html.haml @@ -0,0 +1,17 @@ +%table.user_list.pure-table + %thead + %tr + %th icon + %th nick + %th name + %th member number + %th last update + %tbody + - members.each_with_index do |member, line| + %tr{ class: line.odd? ? 'pure-table-odd' : '' } + %td= gravatar_image_tag(member) + %td + = link_to member.nick, home_path(member.nick) + %td= member.name + %td= member.member_number + %td= member.updated_at