Skip to content

Commit

Permalink
implement category subscriptions
Browse files Browse the repository at this point in the history
  • Loading branch information
NARKOZ committed Apr 4, 2015
1 parent 75b55d7 commit 547c553
Show file tree
Hide file tree
Showing 11 changed files with 169 additions and 6 deletions.
28 changes: 27 additions & 1 deletion app/controllers/categories_controller.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,36 @@
class CategoriesController < ApplicationController
before_action :authenticate_user!, only: [:subscribe, :unsubscribe]
before_action :find_category, only: [:show, :subscribe, :unsubscribe]

def index
@categories = Category.order(:name)
end

def show
@category = Category.find_by_permalink! params[:permalink]
@questions = @category.questions.includes(:answers, :author).recent.page(params[:page]).per(20)
end

def subscribe
current_user.subscribe_to @category

respond_to do |format|
format.html { redirect_to @category }
format.js
end
end

def unsubscribe
current_user.unsubscribe_from @category

respond_to do |format|
format.html { redirect_to @category }
format.js
end
end

private

def find_category
@category = Category.find_by_permalink! params[:permalink]
end
end
15 changes: 15 additions & 0 deletions app/helpers/categories_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module CategoriesHelper
def link_to_category_subscription(category)
return link_to('subscribe', new_user_session_path) unless user_signed_in?

if current_user.subscribed_to? category
title = 'unsubscribe'
path = unsubscribe_category_path(category)
else
title = 'subscribe'
path = subscribe_category_path(category)
end

link_to title, path, method: :post, remote: true, class: 'btn btn-primary', data: { category_id: category.id }
end
end
1 change: 1 addition & 0 deletions app/models/category.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ class Category < ActiveRecord::Base
acts_as_url :name, url_attribute: :permalink

has_many :questions, dependent: :destroy
has_many :subscriptions, as: :subscribable, dependent: :destroy

validates :name, presence: true

Expand Down
18 changes: 18 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,24 @@ def to_param
username
end

def subscribe_to(subscribable)
subscriptions.create(subscribable: subscribable) unless subscribed_to?(subscribable)
end

def unsubscribe_from(subscribable)
subscriptions.where(
subscribable_id: subscribable.id,
subscribable_type: subscribable.class
).destroy_all if subscribed_to?(subscribable)
end

def subscribed_to?(subscribable)
subscriptions.where(
subscribable_id: subscribable.id,
subscribable_type: subscribable.class
).any?
end

private

def self.find_for_database_authentication(warden_conditions)
Expand Down
9 changes: 6 additions & 3 deletions app/views/categories/show.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
h2 = link_to @category.name, @category
p No questions in this category.
- else
h2
' Recent questions in
= link_to @category.name, @category
.clearfix
h2.pull-left
' Recent questions in
= link_to @category.name, @category
.pull-right
= link_to_category_subscription(@category)

.question-list
= render partial: 'questions/question', collection: @questions
Expand Down
1 change: 1 addition & 0 deletions app/views/categories/subscribe.js.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
$('a[data-category-id=<%= @category.id %>]').replaceWith('<%= escape_javascript(link_to_category_subscription @category) %>');
1 change: 1 addition & 0 deletions app/views/categories/unsubscribe.js.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
$('a[data-category-id=<%= @category.id %>]').replaceWith('<%= escape_javascript(link_to_category_subscription @category) %>');
9 changes: 8 additions & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@
end
end

concern :subscribable do
member do
post :subscribe
post :unsubscribe
end
end

get '/ask', to: redirect('/questions/new')
get '/q/:id', to: redirect('/questions/%{id}'), as: :question_short
get '/settings', to: redirect('/settings/profile')
Expand All @@ -33,7 +40,7 @@
end

resources :tags, only: [:show], param: :name
resources :categories, only: [:index, :show], param: :permalink
resources :categories, only: [:index, :show], param: :permalink, concerns: :subscribable
resources :users, only: [:show], param: :username do
member do
get :answers
Expand Down
54 changes: 54 additions & 0 deletions spec/controllers/categories_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

RSpec.describe CategoriesController, type: :controller do
let(:category) { create :category }
let(:user) { create :confirmed_user }

describe "GET #index" do
it "returns http success" do
Expand All @@ -16,4 +17,57 @@
expect(response).to be_success
end
end

describe "POST #subscribe" do
context "when not signed in" do
it "redirects to sign in page" do
post :subscribe, permalink: category.permalink
expect(response).to redirect_to(new_user_session_path)
end
end

context "when signed in" do
before { sign_in user }

it "subscribes user to category and redirects to category page" do
expect {
post :subscribe, permalink: category.permalink
}.to change(category.subscriptions, :count).by(1)
expect(response).to redirect_to(category)
end

it "returns http success for remote request" do
xhr :post, :subscribe, permalink: category.permalink
expect(response).to be_success
end
end
end

describe "POST #unsubscribe" do
context "when not signed in" do
it "redirects to sign in page" do
post :unsubscribe, permalink: category.permalink
expect(response).to redirect_to(new_user_session_path)
end
end

context "when signed in" do
before do
sign_in user
user.subscriptions.create subscribable: category
end

it "unsubscribes user from category and redirects to category page" do
expect {
post :unsubscribe, permalink: category.permalink
}.to change(category.subscriptions, :count).by(-1)
expect(response).to redirect_to(category)
end

it "returns http success for remote request" do
xhr :post, :unsubscribe, permalink: category.permalink
expect(response).to be_success
end
end
end
end
5 changes: 4 additions & 1 deletion spec/factories/subscriptions.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
FactoryGirl.define do
factory :subscription do
subscriber
# association :subscribable, factory: :category
end

factory :category_subscription, parent: :subscription do
association :subscribable, factory: :category
end
end
34 changes: 34 additions & 0 deletions spec/models/user_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
require 'rails_helper'

RSpec.describe User, type: :model do
let(:user) { create :confirmed_user }
let(:category) { create :category }

describe "relations" do
it { should have_many(:answers).conditions(anonymous: false).
with_foreign_key('author_id').dependent(:destroy) }
Expand All @@ -19,4 +22,35 @@
it { should allow_value('', nil).for(:fullname) }
it { should validate_length_of(:bio).is_at_most(400) }
end

describe "#subscribe_to" do
it "subscribes user to subscribable" do
subscribable = category
expect { user.subscribe_to(subscribable) }.to change(user.subscriptions, :count).by(1)

subscription = user.subscriptions.last
expect(subscription.subscribable_id).to eq(subscribable.id)
expect(subscription.subscribable_type).to eq(subscribable.class.to_s)
expect(subscription.subscriber_id).to eq(user.id)
end
end

describe "#unsubscribe_from" do
it "unsubscribes user from subscribable" do
subscribable = category
create :subscription, subscribable: subscribable, subscriber: user

expect { user.unsubscribe_from(subscribable) }.to change(user.subscriptions, :count).by(-1)
end
end

describe "#subscribed_to?" do
it "checks if user subscribed to subscribable" do
create :subscription, subscribable: category, subscriber: user
category2 = create :category

expect(user.subscribed_to?(category)).to be true
expect(user.subscribed_to?(category2)).to be false
end
end
end

0 comments on commit 547c553

Please sign in to comment.