Commit abd35970 by tady

watching 追加

parent 863ec620
...@@ -11,4 +11,6 @@ $ -> ...@@ -11,4 +11,6 @@ $ ->
# TODO # TODO
prettyPrint() prettyPrint()
$(document).on 'ajax:success', '.ajax_link', (data, res, xhr) ->
console.log(res)
$('#yield').html(res)
...@@ -9,7 +9,7 @@ $.extend ...@@ -9,7 +9,7 @@ $.extend
dataType: 'json' dataType: 'json'
done: (e, data) -> done: (e, data) ->
$.each data.result.files, (index, _file) -> $.each data.result.files, (index, _file) ->
settings.$textarea.val(settings.$textarea.val() + "![" + _file.name + "](" + _file.url + ")\n") settings.$textarea.val(settings.$textarea.val() + "\n![" + _file.name + "](" + _file.url + ")\n")
settings.$textarea.trigger("change") settings.$textarea.trigger("change")
# $('<p/>').text(file.name).appendTo('#files') # TODO # $('<p/>').text(file.name).appendTo('#files') # TODO
progressall: (e, data) -> progressall: (e, data) ->
......
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
// Place all the styles related to the watchings controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
require 'nkf' require 'nkf'
class PostsController < ApplicationController class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy, :slideshow] before_action :set_post, only: [:show, :edit, :update, :destroy, :slideshow, :watch]
include RV::Mailer include RV::Mailer
...@@ -108,6 +108,19 @@ class PostsController < ApplicationController ...@@ -108,6 +108,19 @@ class PostsController < ApplicationController
render layout: 'slideshow' render layout: 'slideshow'
end end
def watch
if current_user.watching?(post: @post)
@post.watchers.where(user: current_user).destroy_all
else
@post.watchers.create!(user: current_user)
end
respond_to do |format|
format.html { render action: :show, layout: false }
format.json { head :no_content }
end
end
private private
# Use callbacks to share common setup or constraints between actions. # Use callbacks to share common setup or constraints between actions.
......
class WatchingsController < ApplicationController
def show
@posts = current_user.watching_posts.order(updated_at: :desc).page(params[:page]).decorate
end
end
class WatchingDecorator < 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
module WatchingsHelper
end
...@@ -21,6 +21,7 @@ class Post < ActiveRecord::Base ...@@ -21,6 +21,7 @@ class Post < ActiveRecord::Base
belongs_to :author, class_name: 'User' belongs_to :author, class_name: 'User'
has_many :comments has_many :comments
has_many :footprints has_many :footprints
has_many :watchers, :as => :resource
# default_scope { where(is_draft: false).order(:updated_at => :desc) } # default_scope { where(is_draft: false).order(:updated_at => :desc) }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
class Tag < ActiveRecord::Base class Tag < ActiveRecord::Base
has_many :post_tags has_many :post_tags
has_many :posts, through: :post_tags has_many :posts, through: :post_tags
has_many :watchers, :as => :resource
# for tree structure # for tree structure
has_ancestry has_ancestry
......
...@@ -39,6 +39,8 @@ class User < ActiveRecord::Base ...@@ -39,6 +39,8 @@ class User < ActiveRecord::Base
has_many :comments, foreign_key: 'author_id' has_many :comments, foreign_key: 'author_id'
has_many :notifications has_many :notifications
has_many :footprints has_many :footprints
has_many :watchings, class_name: 'Watcher'
has_many :watchers, :as => :resource
###################################################################### ######################################################################
# scope # scope
...@@ -119,4 +121,19 @@ class User < ActiveRecord::Base ...@@ -119,4 +121,19 @@ class User < ActiveRecord::Base
def visit_post!(post) def visit_post!(post)
footprints.create!(post: post) footprints.create!(post: post)
end end
# check if user watching post/tag/user
# TODO: tag/user
def watching?(hash)
if hash[:post]
hash[:post].watchers.where(user_id: self.id).exists?
else
false
end
end
def watching_posts
ids = watchings.where(resource_type: "Post").pluck(:resource_id)
Post.where(id: ids)
end
end end
class Watcher < ActiveRecord::Base
belongs_to :user
belongs_to :resource, polymorphic: true
end
...@@ -9,6 +9,7 @@ html lang="ja" ...@@ -9,6 +9,7 @@ html lang="ja"
link href="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/1.6.4/fullcalendar.css" rel="stylesheet" / link href="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/1.6.4/fullcalendar.css" rel="stylesheet" /
link href="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/1.6.4/fullcalendar.print.css" rel="stylesheet" / link href="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/1.6.4/fullcalendar.print.css" rel="stylesheet" /
link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet" link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet"
script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"
= stylesheet_link_tag "application", media: "all" = stylesheet_link_tag "application", media: "all"
= render_style = render_style
= csrf_meta_tags = csrf_meta_tags
...@@ -16,12 +17,11 @@ html lang="ja" ...@@ -16,12 +17,11 @@ html lang="ja"
= render partial: 'partials/header_notifications' = render partial: 'partials/header_notifications'
- if params[:controller] != 'welcome' - if params[:controller] != 'welcome'
= render partial: 'partials/app_header' = render partial: 'partials/app_header'
.container.container-main .container.container-main#yield
= yield = yield
script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js" script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js"
script src="//cdnjs.cloudflare.com/ajax/libs/underscore.string/2.3.3/underscore.string.min.js" script src="//cdnjs.cloudflare.com/ajax/libs/underscore.string/2.3.3/underscore.string.min.js"
script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"
script src="//netdna.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js" script src="//netdna.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"
script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.5.1/moment.min.js" script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.5.1/moment.min.js"
script src="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/1.6.4/fullcalendar.min.js" script src="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/1.6.4/fullcalendar.min.js"
......
...@@ -41,6 +41,8 @@ nav.navbar.navbar-default.navbar-fixed-top role="navigation" ...@@ -41,6 +41,8 @@ nav.navbar.navbar-default.navbar-fixed-top role="navigation"
span.badge.pull-right = current_user.decorate.draft_count span.badge.pull-right = current_user.decorate.draft_count
li li
a href=edit_user_path マイページ a href=edit_user_path マイページ
li
a href=watching_path Watchings
li.divider li.divider
li li
a href=destroy_user_session_path data-method="delete" rel="nofollow" SignOut a href=destroy_user_session_path data-method="delete" rel="nofollow" SignOut
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
.col-xs-3 .col-xs-3
p.btn-group .btn-group
a.btn.btn-primary href=edit_post_path(@post) a.btn.btn-primary href=edit_post_path(@post)
| 編集&nbsp; | 編集&nbsp;
span.glyphicon.glyphicon-pencil span.glyphicon.glyphicon-pencil
...@@ -29,7 +29,16 @@ ...@@ -29,7 +29,16 @@
li.divider li.divider
li= link_to 'Delete', post_path(@post), method: :delete, data: { confirm: 'Are you sure?' } li= link_to 'Delete', post_path(@post), method: :delete, data: { confirm: 'Are you sure?' }
.well | &nbsp;
.btn-group
- if current_user.watching?(post: @post)
= link_to 'Watching <span class="glyphicon glyphicon-eye-open"></span>'.html_safe, watch_post_path, :remote => true, :'data-type' => :html, :class => 'btn btn-warning ajax_link'
- else
= link_to 'Watch <span class="glyphicon glyphicon-eye-open"></span>'.html_safe, watch_post_path, :remote => true, :'data-type' => :html, :class => 'btn btn-default ajax_link'
.well style="margin-top:20px"
dl dl
dt 作成者 dt 作成者
dd dd
...@@ -64,8 +73,6 @@ ...@@ -64,8 +73,6 @@
dd dd
= @post.comments.count = @post.comments.count
.row .row
.panel.panel-success .panel.panel-success
.panel-heading .panel-heading
......
/! view:flow/show
.row
h1
| Watchings
small - ウォッチ中の項目
.col-xs-8 role="navigation"
.list-group
- @posts.each do |_post|
= render partial: 'posts/large_item', locals: { post: _post }
= paginate(@posts)
Rendezvous::Application.routes.draw do Rendezvous::Application.routes.draw do
get 'templates/show'
post 'apis/markdown_preview' post 'apis/markdown_preview'
post 'apis/file_receiver' post 'apis/file_receiver'
get 'apis/user_mention' get 'apis/user_mention'
...@@ -14,11 +12,13 @@ Rendezvous::Application.routes.draw do ...@@ -14,11 +12,13 @@ Rendezvous::Application.routes.draw do
get 'flow' => 'flow#show', as: 'flow' get 'flow' => 'flow#show', as: 'flow'
get 'search' => 'search#show', as: 'search' get 'search' => 'search#show', as: 'search'
get 'templates' => 'templates#show', as: 'templates' get 'templates' => 'templates#show', as: 'templates'
get 'watchings' => 'watchings#show', as: 'watching'
get 'posts/:id/fork' => 'posts#fork', as: 'fork_post' get 'posts/:id/fork' => 'posts#fork', as: 'fork_post'
post 'posts/:id/mail' => 'posts#mail', as: 'mail_post' post 'posts/:id/mail' => 'posts#mail', as: 'mail_post'
post 'posts/:id/comment' => 'posts#comment', as: 'comment_post' post 'posts/:id/comment' => 'posts#comment', as: 'comment_post'
get 'posts/:id/slideshow' => 'posts#slideshow', as: 'slideshow_post' get 'posts/:id/slideshow' => 'posts#slideshow', as: 'slideshow_post'
get 'posts/:id/watch' => 'posts#watch', as: 'watch_post'
resources :posts, except: [:index] resources :posts, except: [:index]
get 'notification_bridge/:id' => 'notifications#bridge', as: 'notification_bridge' get 'notification_bridge/:id' => 'notifications#bridge', as: 'notification_bridge'
......
class CreateWatchers < ActiveRecord::Migration
def change
create_table :watchers do |t|
t.integer :user_id, null: false
t.string :resource_type, null: false
t.integer :resource_id, null: false
t.timestamps
end
add_index :watchers, [:user_id, :resource_type, :resource_id], unique: true
add_index :watchers, [:resource_type, :resource_id]
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20140719132802) do ActiveRecord::Schema.define(version: 20140719145016) do
create_table "comments", force: true do |t| create_table "comments", force: true do |t|
t.integer "author_id" t.integer "author_id"
...@@ -115,4 +115,15 @@ ActiveRecord::Schema.define(version: 20140719132802) do ...@@ -115,4 +115,15 @@ ActiveRecord::Schema.define(version: 20140719132802) do
add_index "versions", ["item_type", "item_id"], name: "index_versions_on_item_type_and_item_id", using: :btree add_index "versions", ["item_type", "item_id"], name: "index_versions_on_item_type_and_item_id", using: :btree
create_table "watchers", force: true do |t|
t.integer "user_id", null: false
t.string "resource_type", null: false
t.integer "resource_id", null: false
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "watchers", ["resource_type", "resource_id"], name: "index_watchers_on_resource_type_and_resource_id", using: :btree
add_index "watchers", ["user_id", "resource_type", "resource_id"], name: "index_watchers_on_user_id_and_resource_type_and_resource_id", unique: true, using: :btree
end end
require 'rails_helper'
RSpec.describe WatchingsController, :type => :controller do
describe "GET 'show' without login" do
it "returns http redirect" do
get 'show'
expect(response).to redirect_to('/')
end
end
describe "GET 'show' with login" do
it "returns http success" do
sign_in FactoryGirl.create(:alice)
get 'show'
expect(response).to be_success
end
end
end
require 'spec_helper'
describe WatchingDecorator do
end
require 'rails_helper'
# Specs in this file have access to a helper object that includes
# the WatchingsHelper. For example:
#
# describe WatchingsHelper 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 WatchingsHelper, :type => :helper do
pending "add some examples to (or delete) #{__FILE__}"
end
require 'rails_helper'
RSpec.describe Watcher, :type => :model do
pending "add some examples to (or delete) #{__FILE__}"
end
require 'rails_helper'
RSpec.describe "watchings/show.html.erb", :type => :view do
pending "add some examples to (or delete) #{__FILE__}"
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment