acts_as_followable 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +86 -0
- data/Rakefile +36 -0
- data/lib/acts_as_followable/followable.rb +84 -0
- data/lib/acts_as_followable/version.rb +9 -0
- data/lib/acts_as_followable.rb +7 -0
- data/lib/generators/USAGE +5 -0
- data/lib/generators/acts_as_followable_generator.rb +26 -0
- data/lib/generators/templates/migration.rb +16 -0
- data/test/TESTING +48 -0
- data/test/acts_as_followable_test.rb +241 -0
- data/test/database.yml.example +10 -0
- data/test/factories/bands.rb +0 -0
- data/test/factories/users.rb +0 -0
- data/test/follow_test.rb +10 -0
- data/test/models/band.rb +4 -0
- data/test/models/user.rb +4 -0
- data/test/schema.rb +21 -0
- data/test/test_helper.rb +20 -0
- metadata +88 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 [Kristijan Sedlak]
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
= ActsAsFollowable - Model following
|
2
|
+
|
3
|
+
This plugin is a Rails3 alternative of the plugin called {acts_as_follower}[https://github.com/tcocca/acts_as_follower]
|
4
|
+
by tcocca. It allows any model to follow other models and a model can be followed by other models.
|
5
|
+
|
6
|
+
Usually you will use this plugin when implementing a blog-style website where users will follow other users or for
|
7
|
+
users to follow Books, etc...
|
8
|
+
|
9
|
+
== Installation (Rails 3 ready)
|
10
|
+
|
11
|
+
Add this line to your Gemfile (and run bundle install):
|
12
|
+
|
13
|
+
gem 'acts_as_followable'
|
14
|
+
|
15
|
+
Run the generator which will generate a migration file.
|
16
|
+
|
17
|
+
script/generate acts_as_followable
|
18
|
+
|
19
|
+
The plugin comes with a Follow model file. You can override the default model definition by creating a new
|
20
|
+
app/models/follow.rb file with the content:
|
21
|
+
|
22
|
+
class Follow < ActiveRecord::Base
|
23
|
+
belongs_to :followable, :polymorphic => true
|
24
|
+
belongs_to :follower, :polymorphic => true
|
25
|
+
end
|
26
|
+
|
27
|
+
== Setup
|
28
|
+
|
29
|
+
If you would like a model to follow or to be followed by any other model, just add the mixin:
|
30
|
+
class User < ActiveRecord::Base
|
31
|
+
...
|
32
|
+
acts_as_followable
|
33
|
+
...
|
34
|
+
end
|
35
|
+
|
36
|
+
== Examples
|
37
|
+
|
38
|
+
To have an object start following another use the following:
|
39
|
+
|
40
|
+
book = Book.find(1)
|
41
|
+
user = User.find(1)
|
42
|
+
user.follow(book)
|
43
|
+
|
44
|
+
To stop following an object use the following
|
45
|
+
|
46
|
+
user.stop_following(book)
|
47
|
+
|
48
|
+
You can check to see if an object is following another object through the following:
|
49
|
+
|
50
|
+
user.following?(book)
|
51
|
+
|
52
|
+
You can check to see if an object is followed by another object through the following:
|
53
|
+
|
54
|
+
book.followed_by?(user)
|
55
|
+
|
56
|
+
To get a list of followers by a given type use the following (e.g. list of users that follow a book):
|
57
|
+
|
58
|
+
User.following(book)
|
59
|
+
or
|
60
|
+
book.followers_by_type('User')
|
61
|
+
or
|
62
|
+
book.user_followers
|
63
|
+
|
64
|
+
# Also
|
65
|
+
|
66
|
+
User.following(book).order('name').limit(2)
|
67
|
+
or
|
68
|
+
book.followers_by_type('User').limit(2)
|
69
|
+
or
|
70
|
+
book.user_followers.order('name')
|
71
|
+
|
72
|
+
To get a list of records of a particular type which this record is following (e.g. list of books followed by a user)
|
73
|
+
|
74
|
+
Book.followed_by(user)
|
75
|
+
or
|
76
|
+
user.following_by_type('Book')
|
77
|
+
or
|
78
|
+
user.following_book
|
79
|
+
|
80
|
+
# Also
|
81
|
+
|
82
|
+
Book.followed_by(user).order('title').limit(2)
|
83
|
+
or
|
84
|
+
user.following_by_type('Book').limit(2)
|
85
|
+
or
|
86
|
+
user.following_book('title')
|
data/Rakefile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the acts_as_taggable_on_steroids plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.pattern = 'test/**/*_test.rb'
|
12
|
+
t.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Generate documentation for the acts_as_taggable_on_steroids plugin.'
|
16
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
17
|
+
rdoc.rdoc_dir = 'rdoc'
|
18
|
+
rdoc.title = 'Acts As Follower'
|
19
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
20
|
+
rdoc.rdoc_files.include('README')
|
21
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
22
|
+
end
|
23
|
+
|
24
|
+
namespace :rcov do
|
25
|
+
|
26
|
+
desc "Generate a coverage report in coverage/"
|
27
|
+
task :gen do
|
28
|
+
sh "rcov --output coverage test/*_test.rb --exclude 'gems/*'"
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "Remove generated coverage files."
|
32
|
+
task :clobber do
|
33
|
+
sh "rm -rdf coverage"
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module ActsAsFollowable
|
2
|
+
module Followable
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.extend ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def acts_as_followable
|
10
|
+
include ActsAsFollowable::Followable::InstanceMethods
|
11
|
+
|
12
|
+
scope :following, lambda{|followable| includes(:follows).where(['follows.followable_id=? AND follows.followable_type=?', followable.id, followable.class.name]) }
|
13
|
+
scope :followed_by, lambda{|follower| includes(:followings).where(['follows.follower_id=? AND follows.follower_type=?', follower.id, follower.class.name]) }
|
14
|
+
|
15
|
+
has_many :followings, :as => :followable, :dependent => :destroy, :class_name => 'Follow'
|
16
|
+
has_many :follows, :as => :follower, :dependent => :destroy
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module InstanceMethods
|
21
|
+
|
22
|
+
# Returns the followers by a given type
|
23
|
+
def followers_by_type(type)
|
24
|
+
type.constantize.following(self)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the actual records of a particular type which this record is following.
|
28
|
+
def following_by_type(type)
|
29
|
+
type.constantize.followed_by(self)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Allows magic names on followers_by_type
|
33
|
+
# e.g. followers_by_type('User') > user_followers
|
34
|
+
# e.g. following_by_type('User') > following_user
|
35
|
+
def method_missing(m, *args)
|
36
|
+
if m.to_s[/(.+)_followers/]
|
37
|
+
followers_by_type($1.singularize.classify)
|
38
|
+
elsif m.to_s[/following_(.+)/]
|
39
|
+
following_by_type($1.singularize.classify)
|
40
|
+
else
|
41
|
+
super
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Creates a new follow record for this instance to follow the passed object.
|
46
|
+
# Does not allow duplicate records to be created.
|
47
|
+
def follow(followable)
|
48
|
+
follow = follow_for_follawable(followable).first
|
49
|
+
if follow.blank? && self != followable
|
50
|
+
Follow.create(:followable => followable, :follower => self)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns true if this instance is following the object passed as an argument.
|
55
|
+
def following?(followable)
|
56
|
+
0 < follow_for_follawable(followable).limit(1).count
|
57
|
+
end
|
58
|
+
|
59
|
+
# Deletes the follow record if it exists.
|
60
|
+
def stop_following(followable)
|
61
|
+
if follow = follow_for_follawable(followable).first
|
62
|
+
follow.destroy
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns true if the current instance is followed by the passed record
|
67
|
+
def followed_by?(follower)
|
68
|
+
0 < follow_for_follower(follower).limit(1).count
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def follow_for_follawable(followable)
|
74
|
+
Follow.where(["follower_id = ? AND follower_type = ? AND followable_id = ? AND followable_type = ?", self.id, self.class.name, followable.id, followable.class.name])
|
75
|
+
end
|
76
|
+
|
77
|
+
def follow_for_follower(follower)
|
78
|
+
Follow.where(["follower_id = ? AND follower_type = ? AND followable_id = ? AND followable_type = ?", follower.id, follower.class.name, self.id, self.class.name])
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/migration'
|
3
|
+
|
4
|
+
class ActsAsFollowableGenerator < Rails::Generators::Base
|
5
|
+
|
6
|
+
include Rails::Generators::Migration
|
7
|
+
|
8
|
+
def self.source_root
|
9
|
+
@source_root ||= File.join(File.dirname(__FILE__), 'templates')
|
10
|
+
end
|
11
|
+
|
12
|
+
# Implement the required interface for Rails::Generators::Migration.
|
13
|
+
# taken from http://github.com/rails/rails/blob/master/activerecord/lib/generators/active_record.rb
|
14
|
+
def self.next_migration_number(dirname)
|
15
|
+
if ActiveRecord::Base.timestamped_migrations
|
16
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
17
|
+
else
|
18
|
+
"%.3d" % (current_migration_number(dirname) + 1)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_migration_file
|
23
|
+
migration_template 'migration.rb', 'db/migrate/acts_as_followable_migration.rb'
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class ActsAsFollowableMigration < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :follows, :force => true do |t|
|
4
|
+
t.references :followable, :polymorphic => true, :null => false
|
5
|
+
t.references :follower, :polymorphic => true, :null => false
|
6
|
+
t.timestamps
|
7
|
+
end
|
8
|
+
|
9
|
+
add_index :follows, ["follower_id", "follower_type"], :name => "fk_follows"
|
10
|
+
add_index :follows, ["followable_id", "followable_type"], :name => "fk_followables"
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.down
|
14
|
+
drop_table :follows
|
15
|
+
end
|
16
|
+
end
|
data/test/TESTING
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
Testing
|
2
|
+
==============
|
3
|
+
|
4
|
+
Tests are written with Shoulda on top of Test::Unit and Factory Girl is used instead of fixtures. Tests are run using rake.
|
5
|
+
Test can either be run against a MySQL database or the faster in-memory SQLite3.
|
6
|
+
|
7
|
+
|
8
|
+
MySQL
|
9
|
+
=======
|
10
|
+
|
11
|
+
1. Create a new Rails app.
|
12
|
+
2. Install acts_as_follower as a plugin.
|
13
|
+
3. Copy the database config within the plugin:
|
14
|
+
cp test/database.yml.example test/database.yml
|
15
|
+
4. Create a database as specified in test/database.yml.
|
16
|
+
5. Run the tests:
|
17
|
+
rake test
|
18
|
+
|
19
|
+
|
20
|
+
SQLite3
|
21
|
+
=======
|
22
|
+
|
23
|
+
1. Create a new Rails app.
|
24
|
+
2. Install acts_as_follower as a plugin.
|
25
|
+
3. Copy the database config within the plugin:
|
26
|
+
cp test/database.yml.example test/database.yml
|
27
|
+
4. Install the sqlite3 library (if you don't have it already):
|
28
|
+
sudo gem install sqlite3-ruby
|
29
|
+
5. Run the tests:
|
30
|
+
DB=sqlite3 rake test
|
31
|
+
|
32
|
+
|
33
|
+
Coverage
|
34
|
+
=======
|
35
|
+
|
36
|
+
Test coverage can be calculated using Rcov. Make sure you have the rcov gem installed.
|
37
|
+
|
38
|
+
Again in the acts_as_follower directory:
|
39
|
+
|
40
|
+
rake rcov:gen # For mysql
|
41
|
+
|
42
|
+
or:
|
43
|
+
|
44
|
+
rake rcov:gen DB=sqlite3 # For sqlite
|
45
|
+
|
46
|
+
The coverage will now be available in the test/coverage directory.
|
47
|
+
|
48
|
+
rake rcov:clobber will delete the coverage directory.
|
@@ -0,0 +1,241 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class ActsAsFollowableTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
context "instance methods" do
|
6
|
+
setup do
|
7
|
+
@sam = Factory(:sam)
|
8
|
+
end
|
9
|
+
|
10
|
+
should "be defined" do
|
11
|
+
assert @sam.respond_to?(:followers_count)
|
12
|
+
assert @sam.respond_to?(:followers)
|
13
|
+
assert @sam.respond_to?(:followed_by?)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "acts_as_followable" do
|
18
|
+
setup do
|
19
|
+
@sam = Factory(:sam)
|
20
|
+
@jon = Factory(:jon)
|
21
|
+
@oasis = Factory(:oasis)
|
22
|
+
@metallica = Factory(:metallica)
|
23
|
+
@sam.follow(@jon)
|
24
|
+
end
|
25
|
+
|
26
|
+
context "followers_count" do
|
27
|
+
should "return the number of followers" do
|
28
|
+
assert_equal 0, @sam.followers_count
|
29
|
+
assert_equal 1, @jon.followers_count
|
30
|
+
end
|
31
|
+
|
32
|
+
should "return the proper number of multiple followers" do
|
33
|
+
@bob = Factory(:bob)
|
34
|
+
@sam.follow(@bob)
|
35
|
+
assert_equal 0, @sam.followers_count
|
36
|
+
assert_equal 1, @jon.followers_count
|
37
|
+
assert_equal 1, @bob.followers_count
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "followers" do
|
42
|
+
should "return users" do
|
43
|
+
assert_equal [], @sam.followers
|
44
|
+
assert_equal [@sam], @jon.followers
|
45
|
+
end
|
46
|
+
|
47
|
+
should "return users (multiple followers)" do
|
48
|
+
@bob = Factory(:bob)
|
49
|
+
@sam.follow(@bob)
|
50
|
+
assert_equal [], @sam.followers
|
51
|
+
assert_equal [@sam], @jon.followers
|
52
|
+
assert_equal [@sam], @bob.followers
|
53
|
+
end
|
54
|
+
|
55
|
+
should "return users (multiple followers, complex)" do
|
56
|
+
@bob = Factory(:bob)
|
57
|
+
@sam.follow(@bob)
|
58
|
+
@jon.follow(@bob)
|
59
|
+
assert_equal [], @sam.followers
|
60
|
+
assert_equal [@sam], @jon.followers
|
61
|
+
assert_equal [@sam, @jon], @bob.followers
|
62
|
+
end
|
63
|
+
|
64
|
+
should "accept AR options" do
|
65
|
+
@bob = Factory(:bob)
|
66
|
+
@bob.follow(@jon)
|
67
|
+
assert_equal 1, @jon.followers(:limit => 1).count
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "followed_by" do
|
72
|
+
should "return_follower_status" do
|
73
|
+
assert_equal true, @jon.followed_by?(@sam)
|
74
|
+
assert_equal false, @sam.followed_by?(@jon)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "destroying a followable" do
|
79
|
+
setup do
|
80
|
+
@jon.destroy
|
81
|
+
end
|
82
|
+
|
83
|
+
should_change("follow count", :by => -1) { Follow.count }
|
84
|
+
should_change("@sam.all_following.size", :by => -1) { @sam.all_following.size }
|
85
|
+
end
|
86
|
+
|
87
|
+
context "blocks" do
|
88
|
+
setup do
|
89
|
+
@bob = Factory(:bob)
|
90
|
+
@jon.block(@sam)
|
91
|
+
@jon.block(@bob)
|
92
|
+
end
|
93
|
+
|
94
|
+
should "accept AR options" do
|
95
|
+
assert_equal 1, @jon.blocks(:limit => 1).count
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context "blocking a follower" do
|
100
|
+
context "in my following list" do
|
101
|
+
setup do
|
102
|
+
@jon.block(@sam)
|
103
|
+
end
|
104
|
+
|
105
|
+
should "remove him from followers" do
|
106
|
+
assert_equal 0, @jon.followers_count
|
107
|
+
end
|
108
|
+
|
109
|
+
should "add him to the blocked followers" do
|
110
|
+
assert_equal 1, @jon.blocked_followers_count
|
111
|
+
end
|
112
|
+
|
113
|
+
should "not be able to follow again" do
|
114
|
+
@jon.follow(@sam)
|
115
|
+
assert_equal 0, @jon.followers_count
|
116
|
+
end
|
117
|
+
|
118
|
+
should "not be present when listing followers" do
|
119
|
+
assert_equal [], @jon.followers
|
120
|
+
end
|
121
|
+
|
122
|
+
should "be in the list of blocks" do
|
123
|
+
assert_equal [@sam], @jon.blocks
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context "not in my following list" do
|
128
|
+
setup do
|
129
|
+
@sam.block(@jon)
|
130
|
+
end
|
131
|
+
|
132
|
+
should "add him to the blocked followers" do
|
133
|
+
assert_equal 1, @sam.blocked_followers_count
|
134
|
+
end
|
135
|
+
|
136
|
+
should "not be able to follow again" do
|
137
|
+
@sam.follow(@jon)
|
138
|
+
assert_equal 0, @sam.followers_count
|
139
|
+
end
|
140
|
+
|
141
|
+
should "not be present when listing followers" do
|
142
|
+
assert_equal [], @sam.followers
|
143
|
+
end
|
144
|
+
|
145
|
+
should "be in the list of blocks" do
|
146
|
+
assert_equal [@jon], @sam.blocks
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context "unblocking a blocked follow" do
|
152
|
+
setup do
|
153
|
+
@jon.block(@sam)
|
154
|
+
@jon.unblock(@sam)
|
155
|
+
end
|
156
|
+
|
157
|
+
should "not include the unblocked user in the list of followers" do
|
158
|
+
assert_equal [], @jon.followers
|
159
|
+
end
|
160
|
+
|
161
|
+
should "remove him from the blocked followers" do
|
162
|
+
assert_equal 0, @jon.blocked_followers_count
|
163
|
+
assert_equal [], @jon.blocks
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context "unblock a non-existent follow" do
|
168
|
+
setup do
|
169
|
+
@sam.stop_following(@jon)
|
170
|
+
@jon.unblock(@sam)
|
171
|
+
end
|
172
|
+
|
173
|
+
should "not be in the list of followers" do
|
174
|
+
assert_equal [], @jon.followers
|
175
|
+
end
|
176
|
+
|
177
|
+
should "not be in the blockked followers count" do
|
178
|
+
assert_equal 0, @jon.blocked_followers_count
|
179
|
+
end
|
180
|
+
|
181
|
+
should "not be in the blocks list" do
|
182
|
+
assert_equal [], @jon.blocks
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
context "followers_by_type" do
|
187
|
+
setup do
|
188
|
+
@sam.follow(@oasis)
|
189
|
+
@jon.follow(@oasis)
|
190
|
+
end
|
191
|
+
|
192
|
+
should "return the followers for given type" do
|
193
|
+
assert_equal [@sam], @jon.followers_by_type('User')
|
194
|
+
assert_equal [@sam,@jon], @oasis.followers_by_type('User')
|
195
|
+
end
|
196
|
+
|
197
|
+
should "not return block followers in the followers for a given type" do
|
198
|
+
@oasis.block(@jon)
|
199
|
+
assert_equal [@sam], @oasis.followers_by_type('User')
|
200
|
+
end
|
201
|
+
|
202
|
+
should "return the count for followers_by_type_count for a given type" do
|
203
|
+
assert_equal 1, @jon.followers_by_type_count('User')
|
204
|
+
assert_equal 2, @oasis.followers_by_type_count('User')
|
205
|
+
end
|
206
|
+
|
207
|
+
should "not count blocked follows in the count" do
|
208
|
+
@oasis.block(@sam)
|
209
|
+
assert_equal 1, @oasis.followers_by_type_count('User')
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
context "method_missing" do
|
214
|
+
setup do
|
215
|
+
@sam.follow(@oasis)
|
216
|
+
@jon.follow(@oasis)
|
217
|
+
end
|
218
|
+
|
219
|
+
should "return the followers for given type" do
|
220
|
+
assert_equal [@sam], @jon.user_followers
|
221
|
+
assert_equal [@sam,@jon], @oasis.user_followers
|
222
|
+
end
|
223
|
+
|
224
|
+
should "not return block followers in the followers for a given type" do
|
225
|
+
@oasis.block(@jon)
|
226
|
+
assert_equal [@sam], @oasis.user_followers
|
227
|
+
end
|
228
|
+
|
229
|
+
should "return the count for followers_by_type_count for a given type" do
|
230
|
+
assert_equal 1, @jon.count_user_followers
|
231
|
+
assert_equal 2, @oasis.count_user_followers
|
232
|
+
end
|
233
|
+
|
234
|
+
should "not count blocked follows in the count" do
|
235
|
+
@oasis.block(@sam)
|
236
|
+
assert_equal 1, @oasis.count_user_followers
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
end
|
File without changes
|
File without changes
|
data/test/follow_test.rb
ADDED
data/test/models/band.rb
ADDED
data/test/models/user.rb
ADDED
data/test/schema.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
ActiveRecord::Schema.define :version => 0 do
|
2
|
+
|
3
|
+
create_table :follows, :force => true do |t|
|
4
|
+
t.integer "followable_id", :null => false
|
5
|
+
t.string "followable_type", :null => false
|
6
|
+
t.integer "follower_id", :null => false
|
7
|
+
t.string "follower_type", :null => false
|
8
|
+
t.boolean "blocked", :default => false, :null => false
|
9
|
+
t.datetime "created_at"
|
10
|
+
t.datetime "updated_at"
|
11
|
+
end
|
12
|
+
|
13
|
+
create_table :users, :force => true do |t|
|
14
|
+
t.column :name, :string
|
15
|
+
end
|
16
|
+
|
17
|
+
create_table :bands, :force => true do |t|
|
18
|
+
t.column :name, :string
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'logger'
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + '/debug.log')
|
6
|
+
ActiveRecord::Base.configurations = YAML::load(File.open(File.dirname(__FILE__) + '/database.yml'))
|
7
|
+
ActiveRecord::Base.establish_connection(ENV['DB'] || 'mysql')
|
8
|
+
|
9
|
+
require File.dirname(__FILE__) + '/../init.rb'
|
10
|
+
require File.dirname(__FILE__) + '/models/band'
|
11
|
+
require File.dirname(__FILE__) + '/models/user'
|
12
|
+
require File.dirname(__FILE__) + '/../lib/generators/templates/model.rb'
|
13
|
+
|
14
|
+
require 'test/unit'
|
15
|
+
require 'active_support'
|
16
|
+
require 'shoulda'
|
17
|
+
require 'factory_girl'
|
18
|
+
Factory.find_definitions
|
19
|
+
|
20
|
+
load(File.dirname(__FILE__) + '/schema.rb')
|
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: acts_as_followable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Kristijan Sedlak
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-11-10 00:00:00 +01:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Implements the following functionality where one model can be followed by other models and and vice versa.
|
23
|
+
email: xpepermint@gmail.com
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files:
|
29
|
+
- README.rdoc
|
30
|
+
- MIT-LICENSE
|
31
|
+
files:
|
32
|
+
- Rakefile
|
33
|
+
- lib/acts_as_followable/followable.rb
|
34
|
+
- lib/acts_as_followable/version.rb
|
35
|
+
- lib/acts_as_followable.rb
|
36
|
+
- lib/generators/acts_as_followable_generator.rb
|
37
|
+
- lib/generators/templates/migration.rb
|
38
|
+
- lib/generators/USAGE
|
39
|
+
- test/acts_as_followable_test.rb
|
40
|
+
- test/database.yml.example
|
41
|
+
- test/factories/bands.rb
|
42
|
+
- test/factories/users.rb
|
43
|
+
- test/follow_test.rb
|
44
|
+
- test/models/band.rb
|
45
|
+
- test/models/user.rb
|
46
|
+
- test/schema.rb
|
47
|
+
- test/test_helper.rb
|
48
|
+
- test/TESTING
|
49
|
+
- README.rdoc
|
50
|
+
- MIT-LICENSE
|
51
|
+
has_rdoc: true
|
52
|
+
homepage: http://github.com/xpepermint/acts_as_followable
|
53
|
+
licenses: []
|
54
|
+
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options:
|
57
|
+
- --main
|
58
|
+
- README.rdoc
|
59
|
+
- --charset=UTF-8
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
hash: 3
|
68
|
+
segments:
|
69
|
+
- 0
|
70
|
+
version: "0"
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
hash: 3
|
77
|
+
segments:
|
78
|
+
- 0
|
79
|
+
version: "0"
|
80
|
+
requirements: []
|
81
|
+
|
82
|
+
rubyforge_project:
|
83
|
+
rubygems_version: 1.3.7
|
84
|
+
signing_key:
|
85
|
+
specification_version: 3
|
86
|
+
summary: ActsAsFollowable - Model following.
|
87
|
+
test_files: []
|
88
|
+
|