read_activity 0.0.4 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4a505cc9665d3fbc592d8e08c232aecab8c8f955
4
- data.tar.gz: 3ed4a918d476407b1c4186a354bc40903f8017f4
3
+ metadata.gz: 1f23a993cd5ea8af4de3fe027645d22413746d39
4
+ data.tar.gz: f999afb9b8bc45f737658abec73edb706f94ac63
5
5
  SHA512:
6
- metadata.gz: 99ce880aace3ccdcaa1ba0706cdb10ef8c1c428404901f673b81c66c69d088c599d9684bc57b57692a34a7a668e29364403453df010b7276dd4cdff56ecd9926
7
- data.tar.gz: 91b45d17da9f3f8f742e945fa24b058fb462cf5cb84cb2e88dc3b13124d1197488ad55a67c20e4762f056fedc5e8893b05616056459c562c3b89f2c9fd260176
6
+ metadata.gz: c8b52e2215b02a37524e4576c1a4f0a7abbbfe15e13f853c07d5b520fc1a0134e120f4b9f92eba57ad527fe863fdfb8b480248bc7fdd7ea4eda046b4f6d29660
7
+ data.tar.gz: 2ed81496b4533bb17b1b840d10b38e62736d882e8bf3a6c23baee8ce93db9821951d7754cfd6b97c047b1eaa74b1c41dad50a0fcc8bec63775bc1b8d0d5ed65e
data/README.md CHANGED
@@ -20,9 +20,51 @@ Or install it yourself as:
20
20
 
21
21
  $ gem install read_activity
22
22
 
23
- ## Usage
23
+ ## Usage example
24
24
 
25
- TODO: Write usage instructions here
25
+ ```ruby
26
+
27
+ class User < ActiveRecord::Base
28
+ acts_as_reader
29
+ end
30
+
31
+ class Article < ActiveRecord::Base
32
+ acts_as_readable
33
+ end
34
+
35
+ user = User.create!
36
+ article = Article.create!
37
+
38
+ user.read!(article)
39
+ # or article.read_by!(user)
40
+
41
+ user.read?(article) # == true
42
+ # or article.read_by?(user) == true
43
+
44
+ user.read_at(article)
45
+ # or article.read_by_at(user)
46
+
47
+ article.readers # == [user]
48
+ # or user.read_articles == [article]
49
+ # user.read_#{reader_table_name} (the plural form)
50
+
51
+ article.unreaders # == []
52
+ # or user.unread_articles == []
53
+ # user.unread_#{readable_table_name} (the plural form)
54
+
55
+ reader = article.readers.first
56
+ reader.read_at # no required params when you have fetched readers using #readers
57
+
58
+ read_article = user.read_articles.first
59
+ read_article.read_by_at
60
+
61
+ User.find_who_read(article)
62
+ User.find_who_unread(article)
63
+
64
+ Article.find_read_by(user)
65
+ Article.find_unread_by(user)
66
+
67
+ ```
26
68
 
27
69
  ## Contributing
28
70
 
@@ -1,8 +1,8 @@
1
1
  class CreateReadActivityMarks < ActiveRecord::Migration
2
2
  def change
3
3
  create_table :read_activity_marks do |t|
4
- t.references :reader, null: false
5
- t.references :readable, polymorphic: true
4
+ t.references :reader, null: false, index: true
5
+ t.references :readable, polymorphic: true, index: true
6
6
  t.integer :mark, default: 0
7
7
 
8
8
  t.timestamps
@@ -10,7 +10,7 @@ module ReadActivity
10
10
 
11
11
  module ClassMethods
12
12
  def find_read_by(reader)
13
- self.joins(:read_activity_marks).merge(ReadActivityMark.where(reader: reader))
13
+ self.includes(:read_activity_marks).merge(ReadActivityMark.where(reader: reader)).references(:read_activity_marks)
14
14
  end
15
15
 
16
16
  def find_unread_by(reader)
@@ -31,14 +31,25 @@ module ReadActivity
31
31
  end
32
32
 
33
33
  def read_by?(reader)
34
- mark = self.read_activity_marks.where(reader: reader)
35
- mark.exists?
34
+ mark = self.read_activity_marks.exists?(reader: reader)
36
35
  end
37
36
 
38
- def read_by_at(reader)
39
- mark = ReadActivityMark.find_by(readable: self, reader: reader)
40
- return mark.created_at if mark
41
- return nil
37
+ def read_by_at(reader = nil)
38
+ read_by_at = nil
39
+
40
+ if self.read_activity_marks.loaded?
41
+ read_by_at = self.read_activity_marks.first.try(:created_at)
42
+ end
43
+
44
+ if read_by_at.nil? && reader
45
+ if reader.read_activity_marks.loaded?
46
+ read_by_at = reader.read_activity_marks.first.try(:created_at)
47
+ else
48
+ read_by_at = self.read_activity_marks.where(reader: reader).first.try(:created_at)
49
+ end
50
+ end
51
+
52
+ return read_by_at
42
53
  end
43
54
 
44
55
  def readers
@@ -9,7 +9,7 @@ module ReadActivity
9
9
 
10
10
  module ClassMethods
11
11
  def find_who_read(readable)
12
- self.joins(:read_activity_marks).merge(ReadActivityMark.where(readable: readable))
12
+ self.includes(:read_activity_marks).merge(ReadActivityMark.where(readable: readable)).references(:read_activity_marks)
13
13
  end
14
14
 
15
15
  def find_who_unread(readable)
@@ -40,9 +40,22 @@ module ReadActivity
40
40
  klass.send(:find_unread_by, self)
41
41
  end
42
42
 
43
- # inverse of Readable#read_by_at
44
- def read_at(readable)
45
- readable.read_by_at(self)
43
+ def read_at(readable = nil)
44
+ read_at = nil
45
+
46
+ if self.read_activity_marks.loaded?
47
+ read_at = self.read_activity_marks.first.try(:created_at)
48
+ end
49
+
50
+ if read_at.nil? && readable
51
+ if readable.read_activity_marks.loaded?
52
+ read_at = readable.read_activity_marks.first.try(:created_at)
53
+ else
54
+ read_at = self.read_activity_marks.where(readable: readable).first.try(:created_at)
55
+ end
56
+ end
57
+
58
+ return read_at
46
59
  end
47
60
 
48
61
  def method_missing(method, *arguments, &block)
@@ -1,3 +1,3 @@
1
1
  module ReadActivity
2
- VERSION = "0.0.4"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -39,7 +39,7 @@ RSpec.describe ReadActivity::Readable do
39
39
  expect(mark.reader).to eq(user)
40
40
  expect(mark.readable).to eq(article)
41
41
  end
42
-
42
+
43
43
  it "should create only ReadActivityMark for specific readable" do
44
44
  user = FactoryGirl.create(:user)
45
45
  article = FactoryGirl.create(:article)
@@ -87,7 +87,7 @@ RSpec.describe ReadActivity::Readable do
87
87
  end
88
88
 
89
89
  describe "#read_by_at" do
90
- it "should return when user read readables" do
90
+ it "should return when users read readables" do
91
91
  user = FactoryGirl.create(:user)
92
92
  article = FactoryGirl.create(:article)
93
93
 
@@ -96,5 +96,15 @@ RSpec.describe ReadActivity::Readable do
96
96
 
97
97
  expect(article.read_by_at(user)).to eq(user.read_activity_marks.take.created_at)
98
98
  end
99
+
100
+ it "should return when readers read readables" do
101
+ user = FactoryGirl.create(:user)
102
+ article = FactoryGirl.create(:article)
103
+
104
+ article.read_by!(user)
105
+
106
+ articles = user.read_articles
107
+ expect(articles.first.read_by_at).to eq(user.read_activity_marks.take.created_at)
108
+ end
99
109
  end
100
110
  end
@@ -132,10 +132,28 @@ RSpec.describe ReadActivity::Reader do
132
132
  user = FactoryGirl.create(:user)
133
133
  article = FactoryGirl.create(:article)
134
134
 
135
- expect(user.read_at(article)).to eq(nil)
136
135
  user.read!(article)
137
136
 
138
137
  expect(user.read_at(article)).to eq(user.read_activity_marks.take.created_at)
139
138
  end
139
+
140
+ it "should return when readers read readables" do
141
+ user = FactoryGirl.create(:user)
142
+ article = FactoryGirl.create(:article)
143
+
144
+ user.read!(article)
145
+
146
+ readers = article.readers
147
+ expect(readers.first.read_at).to eq(user.read_activity_marks.take.created_at)
148
+ end
149
+
150
+ it "should be optimized" do
151
+ users = FactoryGirl.create_list(:user, 3)
152
+ article = FactoryGirl.create(:article)
153
+
154
+ users.each { |user| user.read!(article) }
155
+
156
+ expect { article.readers.each{ |user| user.read_at } }.to under_query_limit(1)
157
+ end
140
158
  end
141
159
  end
@@ -4,6 +4,7 @@ SimpleCov.start
4
4
  require "active_record"
5
5
  require "database_cleaner"
6
6
  require "factory_girl"
7
+ Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
7
8
 
8
9
  require "read_activity"
9
10
 
@@ -0,0 +1,19 @@
1
+ # https://gist.github.com/rsutphin/af06c9e3dadf658d2293
2
+ # Derived from http://stackoverflow.com/a/13423584/153896. Updated for RSpec 3.
3
+ RSpec::Matchers.define :under_query_limit do |expected|
4
+ supports_block_expectations
5
+
6
+ match do |block|
7
+ query_count(&block) <= expected
8
+ end
9
+
10
+ failure_message do |actual|
11
+ "Expected to run maximum #{expected} queries, got #{@counter.query_count}"
12
+ end
13
+
14
+ def query_count(&block)
15
+ @counter = ActiveRecord::QueryCounter.new
16
+ ActiveSupport::Notifications.subscribed(@counter.to_proc, 'sql.active_record', &block)
17
+ @counter.query_count
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ # Derived from http://stackoverflow.com/a/13423584/153896
2
+ module ActiveRecord
3
+ class QueryCounter
4
+ attr_reader :query_count
5
+
6
+ def initialize
7
+ @query_count = 0
8
+ end
9
+
10
+ def to_proc
11
+ lambda(&method(:callback))
12
+ end
13
+
14
+ def callback(name, start, finish, message_id, values)
15
+ @query_count += 1 unless %w(CACHE SCHEMA).include?(values[:name])
16
+ end
17
+ end
18
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: read_activity
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hong ChulJu
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-18 00:00:00.000000000 Z
11
+ date: 2014-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -169,6 +169,8 @@ files:
169
169
  - spec/read_activity/reader_spec.rb
170
170
  - spec/schema.rb
171
171
  - spec/spec_helper.rb
172
+ - spec/support/matchers/under_query_limit.rb
173
+ - spec/support/query_counter.rb
172
174
  homepage: https://github.com/FeGs/read_activity
173
175
  licenses:
174
176
  - MIT
@@ -202,3 +204,5 @@ test_files:
202
204
  - spec/read_activity/reader_spec.rb
203
205
  - spec/schema.rb
204
206
  - spec/spec_helper.rb
207
+ - spec/support/matchers/under_query_limit.rb
208
+ - spec/support/query_counter.rb