Create followable concern, follow model. Add followable to proposal model.
This commit is contained in:
28
app/controllers/follows_controller.rb
Normal file
28
app/controllers/follows_controller.rb
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
class FollowsController < ApplicationController
|
||||||
|
before_action :authenticate_user!
|
||||||
|
load_and_authorize_resource
|
||||||
|
|
||||||
|
def create
|
||||||
|
@followable = find_followable
|
||||||
|
@follow = Follow.create(user: current_user, followable: @followable)
|
||||||
|
render :refresh_follow_button
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@follow = Follow.find(params[:id])
|
||||||
|
@followable = @follow.followable
|
||||||
|
@follow.destroy
|
||||||
|
render :refresh_follow_button
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def find_followable
|
||||||
|
params.each do |name, value|
|
||||||
|
if name =~ /(.+)_id$/
|
||||||
|
return $1.classify.constantize.find(value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
28
app/helpers/follows_helper.rb
Normal file
28
app/helpers/follows_helper.rb
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
module FollowsHelper
|
||||||
|
|
||||||
|
def show_follow_action?(followable)
|
||||||
|
current_user && !followed?(followable)
|
||||||
|
end
|
||||||
|
|
||||||
|
def show_unfollow_action?(followable)
|
||||||
|
current_user && followed?(followable)
|
||||||
|
end
|
||||||
|
|
||||||
|
def follow_entity_text(entity)
|
||||||
|
t('shared.follow_entity', entity: t("activerecord.models.#{entity}.one").downcase)
|
||||||
|
end
|
||||||
|
|
||||||
|
def unfollow_entity_text(entity)
|
||||||
|
t('shared.unfollow_entity', entity: t("activerecord.models.#{entity}.one").downcase)
|
||||||
|
end
|
||||||
|
|
||||||
|
def entity_name(followable)
|
||||||
|
followable.class.name.downcase
|
||||||
|
end
|
||||||
|
private
|
||||||
|
|
||||||
|
def followed?(followable)
|
||||||
|
Follow.followed?(current_user, followable)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -34,6 +34,8 @@ module Abilities
|
|||||||
can [:flag, :unflag], Proposal
|
can [:flag, :unflag], Proposal
|
||||||
cannot [:flag, :unflag], Proposal, author_id: user.id
|
cannot [:flag, :unflag], Proposal, author_id: user.id
|
||||||
|
|
||||||
|
can [:create, :destroy], Follow
|
||||||
|
|
||||||
unless user.organization?
|
unless user.organization?
|
||||||
can :vote, Debate
|
can :vote, Debate
|
||||||
can :vote, Comment
|
can :vote, Comment
|
||||||
|
|||||||
8
app/models/concerns/followable.rb
Normal file
8
app/models/concerns/followable.rb
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
module Followable
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
has_many :follows, as: :followable
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
32
app/models/follow.rb
Normal file
32
app/models/follow.rb
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
class Follow < ActiveRecord::Base
|
||||||
|
belongs_to :user
|
||||||
|
#TODO Rock&RoR: Check touch usage on cache system
|
||||||
|
belongs_to :followable, polymorphic: true
|
||||||
|
|
||||||
|
validates :user_id, presence: true
|
||||||
|
validates :followable_id, presence: true
|
||||||
|
validates :followable_type, presence: true
|
||||||
|
|
||||||
|
scope(:by_user_and_followable, lambda do |user, followable|
|
||||||
|
where(user_id: user.id,
|
||||||
|
followable_type: followable.class.to_s,
|
||||||
|
followable_id: followable.id)
|
||||||
|
end)
|
||||||
|
|
||||||
|
# def self.follow(user, followable)
|
||||||
|
# return false if interested?(user, followable)
|
||||||
|
# create(user: user, followable: followable)
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# def self.unfollow(user, followable)
|
||||||
|
# interests = by_user_and_followable(user, followable)
|
||||||
|
# return false if interests.empty?
|
||||||
|
# interests.destroy_all
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
def self.followed?(user, followable)
|
||||||
|
return false unless user
|
||||||
|
!! by_user_and_followable(user, followable).try(:first)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -8,6 +8,7 @@ class Proposal < ActiveRecord::Base
|
|||||||
include Filterable
|
include Filterable
|
||||||
include HasPublicAuthor
|
include HasPublicAuthor
|
||||||
include Graphqlable
|
include Graphqlable
|
||||||
|
include Followable
|
||||||
|
|
||||||
acts_as_votable
|
acts_as_votable
|
||||||
acts_as_paranoid column: :hidden_at
|
acts_as_paranoid column: :hidden_at
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class User < ActiveRecord::Base
|
|||||||
has_many :direct_messages_sent, class_name: 'DirectMessage', foreign_key: :sender_id
|
has_many :direct_messages_sent, class_name: 'DirectMessage', foreign_key: :sender_id
|
||||||
has_many :direct_messages_received, class_name: 'DirectMessage', foreign_key: :receiver_id
|
has_many :direct_messages_received, class_name: 'DirectMessage', foreign_key: :receiver_id
|
||||||
has_many :legislation_answers, class_name: 'Legislation::Answer', dependent: :destroy, inverse_of: :user
|
has_many :legislation_answers, class_name: 'Legislation::Answer', dependent: :destroy, inverse_of: :user
|
||||||
|
has_many :follows
|
||||||
belongs_to :geozone
|
belongs_to :geozone
|
||||||
|
|
||||||
validates :username, presence: true, if: :username_required?
|
validates :username, presence: true, if: :username_required?
|
||||||
|
|||||||
20
app/views/follows/_followable_button.html.erb
Normal file
20
app/views/follows/_followable_button.html.erb
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<span class="followable-content">
|
||||||
|
<% if show_follow_action? followable %>
|
||||||
|
<a id="follow-expand-<%= entity_name(followable) %>-<%= followable.id %>" data-toggle="follow-drop-<%= entity_name(followable) %>-<%= followable.id %>" title="<%= follow_entity_text(entity_name(followable)) %>">
|
||||||
|
<%= t('shared.follow') %>
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-pane" id="follow-drop-<%= entity_name(followable) %>-<%= followable.id %>" data-dropdown data-auto-focus="true">
|
||||||
|
<%= link_to follow_entity_text(entity_name(followable)), follows_path("#{entity_name(followable)}_id": followable.id), method: :post, remote: true, id: "follow-#{entity_name(followable)}-#{ followable.id }" %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% if show_unfollow_action? followable %>
|
||||||
|
<% follow = followable.follows.where(user: current_user).first %>
|
||||||
|
<a id="unfollow-expand-<%= entity_name(followable) %>-<%= followable.id %>" data-toggle="unfollow-drop-<%= entity_name(followable) %>-<%= followable.id %>" title="<%= unfollow_entity_text(entity_name(followable)) %>">
|
||||||
|
<%= t('shared.unfollow') %>
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-pane" id="unfollow-drop-<%= entity_name(followable) %>-<%= followable.id %>" data-dropdown data-auto-focus="true">
|
||||||
|
<%= link_to unfollow_entity_text(entity_name(followable)), follow_path(follow), method: :delete, remote: true, id: "unfollow-#{entity_name(followable)}-#{ followable.id }" %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</span>
|
||||||
1
app/views/follows/refresh_follow_button.js.erb
Normal file
1
app/views/follows/refresh_follow_button.js.erb
Normal file
@@ -0,0 +1 @@
|
|||||||
|
$("#<%= dom_id(@followable) %> .js-follow").html('<%= j render("followable_button", followable: @followable) %>');
|
||||||
@@ -53,6 +53,10 @@
|
|||||||
<span class="js-flag-actions">
|
<span class="js-flag-actions">
|
||||||
<%= render 'proposals/flag_actions', proposal: @proposal %>
|
<%= render 'proposals/flag_actions', proposal: @proposal %>
|
||||||
</span>
|
</span>
|
||||||
|
<span class="bullet"> • </span>
|
||||||
|
<span class="js-follow">
|
||||||
|
<%= render 'follows/followable_button', followable: @proposal %>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|||||||
@@ -500,6 +500,8 @@ en:
|
|||||||
check_none: None
|
check_none: None
|
||||||
collective: Collective
|
collective: Collective
|
||||||
flag: Flag as inappropriate
|
flag: Flag as inappropriate
|
||||||
|
follow: "Follow"
|
||||||
|
follow_entity: "Follow %{entity}"
|
||||||
hide: Hide
|
hide: Hide
|
||||||
print:
|
print:
|
||||||
print_button: Print this info
|
print_button: Print this info
|
||||||
@@ -532,6 +534,8 @@ en:
|
|||||||
target_blank_html: " (link opens in new window)"
|
target_blank_html: " (link opens in new window)"
|
||||||
you_are_in: "You are in"
|
you_are_in: "You are in"
|
||||||
unflag: Unflag
|
unflag: Unflag
|
||||||
|
unfollow: "Unfollow"
|
||||||
|
unfollow_entity: "Unfollow %{entity}"
|
||||||
outline:
|
outline:
|
||||||
debates: Debates
|
debates: Debates
|
||||||
proposals: Proposals
|
proposals: Proposals
|
||||||
@@ -708,4 +712,3 @@ en:
|
|||||||
invisible_captcha:
|
invisible_captcha:
|
||||||
sentence_for_humans: "If you are human, ignore this field"
|
sentence_for_humans: "If you are human, ignore this field"
|
||||||
timestamp_error_message: "Sorry, that was too quick! Please resubmit."
|
timestamp_error_message: "Sorry, that was too quick! Please resubmit."
|
||||||
|
|
||||||
|
|||||||
@@ -500,6 +500,8 @@ es:
|
|||||||
check_none: Ninguno
|
check_none: Ninguno
|
||||||
collective: Colectivo
|
collective: Colectivo
|
||||||
flag: Denunciar como inapropiado
|
flag: Denunciar como inapropiado
|
||||||
|
follow: "Seguir"
|
||||||
|
follow_entity: "Seguir %{entity}"
|
||||||
hide: Ocultar
|
hide: Ocultar
|
||||||
print:
|
print:
|
||||||
print_button: Imprimir esta información
|
print_button: Imprimir esta información
|
||||||
@@ -532,6 +534,8 @@ es:
|
|||||||
target_blank_html: " (se abre en ventana nueva)"
|
target_blank_html: " (se abre en ventana nueva)"
|
||||||
you_are_in: "Estás en"
|
you_are_in: "Estás en"
|
||||||
unflag: Deshacer denuncia
|
unflag: Deshacer denuncia
|
||||||
|
unfollow: Dejar de seguir
|
||||||
|
unfollow_entity: "Dejar de seguir %{entity}"
|
||||||
outline:
|
outline:
|
||||||
debates: Debates
|
debates: Debates
|
||||||
proposals: Propuestas
|
proposals: Propuestas
|
||||||
|
|||||||
@@ -93,6 +93,8 @@ Rails.application.routes.draw do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
resources :follows, only: [:create, :destroy]
|
||||||
|
|
||||||
resources :stats, only: [:index]
|
resources :stats, only: [:index]
|
||||||
|
|
||||||
resources :legacy_legislations, only: [:show], path: 'legislations'
|
resources :legacy_legislations, only: [:show], path: 'legislations'
|
||||||
|
|||||||
12
db/migrate/20170626180127_create_follows.rb
Normal file
12
db/migrate/20170626180127_create_follows.rb
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
class CreateFollows < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
create_table :follows do |t|
|
||||||
|
t.references :user, index: true, foreign_key: true
|
||||||
|
t.references :followable, polymorphic: true, index: true
|
||||||
|
|
||||||
|
t.timestamps null: false
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :follows, [:user_id, :followable_type, :followable_id], name: "access_follows"
|
||||||
|
end
|
||||||
|
end
|
||||||
13
db/schema.rb
13
db/schema.rb
@@ -326,6 +326,18 @@ ActiveRecord::Schema.define(version: 20170704105112) do
|
|||||||
add_index "flags", ["user_id", "flaggable_type", "flaggable_id"], name: "access_inappropiate_flags", using: :btree
|
add_index "flags", ["user_id", "flaggable_type", "flaggable_id"], name: "access_inappropiate_flags", using: :btree
|
||||||
add_index "flags", ["user_id"], name: "index_flags_on_user_id", using: :btree
|
add_index "flags", ["user_id"], name: "index_flags_on_user_id", using: :btree
|
||||||
|
|
||||||
|
create_table "follows", force: :cascade do |t|
|
||||||
|
t.integer "user_id"
|
||||||
|
t.integer "followable_id"
|
||||||
|
t.string "followable_type"
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index "follows", ["followable_type", "followable_id"], name: "index_follows_on_followable_type_and_followable_id", using: :btree
|
||||||
|
add_index "follows", ["user_id", "followable_type", "followable_id"], name: "access_follows", using: :btree
|
||||||
|
add_index "follows", ["user_id"], name: "index_follows_on_user_id", using: :btree
|
||||||
|
|
||||||
create_table "geozones", force: :cascade do |t|
|
create_table "geozones", force: :cascade do |t|
|
||||||
t.string "name"
|
t.string "name"
|
||||||
t.string "html_map_coordinates"
|
t.string "html_map_coordinates"
|
||||||
@@ -1036,6 +1048,7 @@ ActiveRecord::Schema.define(version: 20170704105112) do
|
|||||||
add_foreign_key "failed_census_calls", "poll_officers"
|
add_foreign_key "failed_census_calls", "poll_officers"
|
||||||
add_foreign_key "failed_census_calls", "users"
|
add_foreign_key "failed_census_calls", "users"
|
||||||
add_foreign_key "flags", "users"
|
add_foreign_key "flags", "users"
|
||||||
|
add_foreign_key "follows", "users"
|
||||||
add_foreign_key "geozones_polls", "geozones"
|
add_foreign_key "geozones_polls", "geozones"
|
||||||
add_foreign_key "geozones_polls", "polls"
|
add_foreign_key "geozones_polls", "polls"
|
||||||
add_foreign_key "identities", "users"
|
add_foreign_key "identities", "users"
|
||||||
|
|||||||
@@ -166,8 +166,8 @@ FactoryGirl.define do
|
|||||||
end
|
end
|
||||||
|
|
||||||
trait :flagged do
|
trait :flagged do
|
||||||
after :create do |debate|
|
after :create do |proposal|
|
||||||
Flag.flag(FactoryGirl.create(:user), debate)
|
Flag.flag(FactoryGirl.create(:user), proposal)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -349,6 +349,14 @@ FactoryGirl.define do
|
|||||||
association :user, factory: :user
|
association :user, factory: :user
|
||||||
end
|
end
|
||||||
|
|
||||||
|
factory :follow do
|
||||||
|
association :user, factory: :user
|
||||||
|
|
||||||
|
trait :followed_proposal do
|
||||||
|
association :followable, factory: :proposal
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
factory :comment do
|
factory :comment do
|
||||||
association :commentable, factory: :debate
|
association :commentable, factory: :debate
|
||||||
user
|
user
|
||||||
|
|||||||
@@ -1223,6 +1223,73 @@ feature 'Proposals' do
|
|||||||
expect(Flag.flagged?(user, proposal)).to_not be
|
expect(Flag.flagged?(user, proposal)).to_not be
|
||||||
end
|
end
|
||||||
|
|
||||||
|
feature "Follows" do
|
||||||
|
|
||||||
|
scenario "Should not show follow button when there is no logged user" do
|
||||||
|
proposal = create(:proposal)
|
||||||
|
|
||||||
|
visit proposal_path(proposal)
|
||||||
|
|
||||||
|
within "#proposal_#{proposal.id}" do
|
||||||
|
expect(page).not_to have_link("Follow citizen proposal")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Following", :js do
|
||||||
|
user = create(:user)
|
||||||
|
proposal = create(:proposal)
|
||||||
|
login_as(user)
|
||||||
|
|
||||||
|
visit proposal_path(proposal)
|
||||||
|
within "#proposal_#{proposal.id}" do
|
||||||
|
page.find("#follow-expand-proposal-#{proposal.id}").click
|
||||||
|
page.find("#follow-proposal-#{proposal.id}").click
|
||||||
|
|
||||||
|
expect(page).to have_css("#unfollow-expand-proposal-#{proposal.id}")
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(Follow.followed?(user, proposal)).to be
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Show unfollow button when user already follow this proposal" do
|
||||||
|
user = create(:user)
|
||||||
|
follow = create(:follow, :followed_proposal, user: user)
|
||||||
|
login_as(user)
|
||||||
|
|
||||||
|
visit proposal_path(follow.followable)
|
||||||
|
|
||||||
|
expect(page).to have_link("Unfollow citizen proposal")
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Unfollowing", :js do
|
||||||
|
user = create(:user)
|
||||||
|
proposal = create(:proposal)
|
||||||
|
follow = create(:follow, :followed_proposal, user: user, followable: proposal)
|
||||||
|
login_as(user)
|
||||||
|
|
||||||
|
visit proposal_path(proposal)
|
||||||
|
within "#proposal_#{proposal.id}" do
|
||||||
|
page.find("#unfollow-expand-proposal-#{proposal.id}").click
|
||||||
|
page.find("#unfollow-proposal-#{proposal.id}").click
|
||||||
|
|
||||||
|
expect(page).to have_css("#follow-expand-proposal-#{proposal.id}")
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(Follow.followed?(user, proposal)).not_to be
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Show follow button when user is not following this proposal" do
|
||||||
|
user = create(:user)
|
||||||
|
proposal = create(:proposal)
|
||||||
|
login_as(user)
|
||||||
|
|
||||||
|
visit proposal_path(proposal)
|
||||||
|
|
||||||
|
expect(page).to have_link("Follow citizen proposal")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
scenario 'Erased author' do
|
scenario 'Erased author' do
|
||||||
user = create(:user)
|
user = create(:user)
|
||||||
proposal = create(:proposal, author: user)
|
proposal = create(:proposal, author: user)
|
||||||
|
|||||||
134
spec/models/follow_spec.rb
Normal file
134
spec/models/follow_spec.rb
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe Follow do
|
||||||
|
|
||||||
|
let(:follow) { build(:follow, :followed_proposal) }
|
||||||
|
|
||||||
|
# it_behaves_like "has_public_author"
|
||||||
|
|
||||||
|
it "should be valid" do
|
||||||
|
expect(follow).to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not be valid without an user_id" do
|
||||||
|
follow.user_id = nil
|
||||||
|
expect(follow).to_not be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not be valid without an followable_id" do
|
||||||
|
follow.followable_id = nil
|
||||||
|
expect(follow).to_not be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not be valid without an followable_type" do
|
||||||
|
follow.followable_type = nil
|
||||||
|
expect(follow).to_not be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# describe "proposal" do
|
||||||
|
#
|
||||||
|
# let(:proposal) { create(:proposal) }
|
||||||
|
#
|
||||||
|
# describe 'create' do
|
||||||
|
#
|
||||||
|
# it 'creates a interest when there is none' do
|
||||||
|
# expect { described_class.follow(user, proposal) }.to change{ Interest.count }.by(1)
|
||||||
|
# expect(Interest.last.user).to eq(user)
|
||||||
|
# expect(Interest.last.interestable).to eq(proposal)
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# it 'does nothing if the interest already exists' do
|
||||||
|
# described_class.follow(user, proposal)
|
||||||
|
# expect(described_class.follow(user, proposal)).to eq(false)
|
||||||
|
# expect(Interest.by_user_and_interestable(user, proposal).count).to eq(1)
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# it 'increases the interest count' do
|
||||||
|
# expect { described_class.follow(user, proposal) }.to change{ proposal.reload.interests_count }.by(1)
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# describe 'destroy' do
|
||||||
|
# it 'raises an error if the interest does not exist' do
|
||||||
|
# expect(described_class.unfollow(user, proposal)).to eq(false)
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# describe 'when the interest already exists' do
|
||||||
|
# before(:each) { described_class.follow(user, proposal) }
|
||||||
|
#
|
||||||
|
# it 'removes an existing interest' do
|
||||||
|
# expect { described_class.unfollow(user, proposal) }.to change{ Interest.count }.by(-1)
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# it 'decreases the interest count' do
|
||||||
|
# expect { described_class.unfollow(user, proposal) }.to change{ proposal.reload.interests_count }.by(-1)
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# describe '.interested?' do
|
||||||
|
# it 'returns false when the user has not flagged the proposal' do
|
||||||
|
# expect(described_class.interested?(user, proposal)).to_not be
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# it 'returns true when the user has interested the proposal' do
|
||||||
|
# described_class.follow(user, proposal)
|
||||||
|
# expect(described_class.interested?(user, proposal)).to be
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# describe "debate" do
|
||||||
|
#
|
||||||
|
# let(:debate) { create(:debate) }
|
||||||
|
#
|
||||||
|
# describe 'create' do
|
||||||
|
#
|
||||||
|
# it 'creates a interest when there is none' do
|
||||||
|
# expect { described_class.follow(user, debate) }.to change{ Interest.count }.by(1)
|
||||||
|
# expect(Interest.last.user).to eq(user)
|
||||||
|
# expect(Interest.last.interestable).to eq(debate)
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# it 'does nothing if the interest already exists' do
|
||||||
|
# described_class.follow(user, debate)
|
||||||
|
# expect(described_class.follow(user, debate)).to eq(false)
|
||||||
|
# expect(Interest.by_user_and_interestable(user, debate).count).to eq(1)
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# it 'increases the interest count' do
|
||||||
|
# expect { described_class.follow(user, debate) }.to change{ debate.reload.interests_count }.by(1)
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# describe 'destroy' do
|
||||||
|
# it 'raises an error if the interest does not exist' do
|
||||||
|
# expect(described_class.unfollow(user, debate)).to eq(false)
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# describe 'when the interest already exists' do
|
||||||
|
# before(:each) { described_class.follow(user, debate) }
|
||||||
|
#
|
||||||
|
# it 'removes an existing interest' do
|
||||||
|
# expect { described_class.unfollow(user, debate) }.to change{ Interest.count }.by(-1)
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# it 'decreases the interest count' do
|
||||||
|
# expect { described_class.unfollow(user, debate) }.to change{ debate.reload.interests_count }.by(-1)
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# describe '.interested?' do
|
||||||
|
# it 'returns false when the user has not flagged the debate' do
|
||||||
|
# expect(described_class.interested?(user, debate)).to_not be
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# it 'returns true when the user has interested the debate' do
|
||||||
|
# described_class.follow(user, debate)
|
||||||
|
# expect(described_class.interested?(user, debate)).to be
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user