feeder 0.3.0 → 0.5.1
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 +4 -4
- data/README.md +119 -2
- data/app/controllers/feeder/application_controller.rb +1 -1
- data/app/controllers/feeder/items_controller.rb +7 -0
- data/app/models/feeder/feedable_observer.rb +43 -7
- data/app/models/feeder/item.rb +2 -6
- data/app/views/feeder/items/_item.html.erb +1 -1
- data/app/views/feeder/items/_item.json.jbuilder +1 -0
- data/app/views/feeder/{feeds → items}/index.html.erb +1 -1
- data/app/views/feeder/items/index.json.jbuilder +1 -0
- data/config/routes.rb +1 -1
- data/db/migrate/20140321085409_add_sticky_to_feeder_items.rb +5 -0
- data/db/migrate/20140401131911_prohibit_null_on_feeder_item_stickies.rb +13 -0
- data/db/migrate/20140526110451_add_blocked_to_feeder_items.rb +5 -0
- data/db/migrate/20140526110501_add_reported_to_feeder_items.rb +5 -0
- data/lib/feeder.rb +18 -2
- data/lib/feeder/active_record.rb +9 -0
- data/lib/feeder/concerns.rb +6 -0
- data/lib/feeder/concerns/controllers.rb +5 -0
- data/lib/feeder/concerns/controllers/items_controller.rb +22 -0
- data/lib/feeder/concerns/feedable.rb +27 -0
- data/lib/feeder/concerns/helpers.rb +5 -0
- data/lib/feeder/concerns/helpers/filter.rb +20 -0
- data/lib/feeder/concerns/models.rb +5 -0
- data/lib/feeder/concerns/models/item.rb +31 -0
- data/lib/feeder/configuration.rb +19 -5
- data/lib/feeder/engine.rb +3 -2
- data/lib/feeder/version.rb +1 -1
- data/spec/controllers/feeder/items_controller_spec.rb +36 -0
- data/spec/dummy/app/models/message.rb +2 -0
- data/spec/dummy/config/initializers/feeder.rb +1 -1
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/schema.rb +4 -1
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +359 -0
- data/spec/dummy/log/test.log +53050 -0
- data/spec/factories/feeder/items.rb +10 -0
- data/spec/lib/feeder/concerns/feedable_spec.rb +33 -0
- data/spec/lib/feeder/configuration_spec.rb +6 -6
- data/spec/lib/feeder_spec.rb +14 -2
- data/spec/models/feeder/feedable_observer_spec.rb +95 -0
- data/spec/models/feeder/item_spec.rb +38 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/support/shared_examples/filterable.rb +48 -0
- metadata +97 -39
- data/app/controllers/feeder/feeds_controller.rb +0 -9
- data/app/views/layouts/feeder/application.html.erb +0 -14
- data/spec/controllers/feeder/feeds_controller_spec.rb +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04e9d95c32a3be20252ca3365e9e3e9aa6d61599
|
4
|
+
data.tar.gz: d6765c13e947c4a5d30b6f30125b9afcbfc79106
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7bc92c030d928c6642485ca8dd2ecb2c74866bd5a630c3589bdd2d9aa50141cecf0ca0c71f98fef0a9d441a1ffa02d9d81fb45f4c348af385491b21621eee572
|
7
|
+
data.tar.gz: 527433e9fb8feae052f6b99e192d10064676bb303a3b69fda212ba1523e58d3f94b0c3f3c31e2251524119f68ef56d5d83c4cb0aaf5e21568b7524a3ae29b3e6
|
data/README.md
CHANGED
@@ -1,4 +1,10 @@
|
|
1
|
-
#
|
1
|
+
# Feeder
|
2
|
+
|
3
|
+
[](https://rubygems.org/gems/feeder)
|
4
|
+
[](https://travis-ci.org/hyperoslo/feeder)
|
5
|
+
[](https://gemnasium.com/hyperoslo/feeder)
|
6
|
+
[](https://codeclimate.com/github/hyperoslo/feeder)
|
7
|
+
[](https://coveralls.io/r/hyperoslo/feeder)
|
2
8
|
|
3
9
|
Feeder gives you a mountable engine that provides a route to a feed page in your
|
4
10
|
Ruby on Rails application.
|
@@ -20,11 +26,122 @@ Or install it yourself as:
|
|
20
26
|
Install the migrations:
|
21
27
|
|
22
28
|
rake feeder:install:migrations
|
23
|
-
|
29
|
+
|
24
30
|
Run the migrations:
|
25
31
|
|
26
32
|
rake db:migrate
|
27
33
|
|
34
|
+
## Usage
|
35
|
+
|
36
|
+
To make Feeder available, mount it to a route by adding the following somewhere
|
37
|
+
in your _config/routes.rb_:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
mount Feeder::Engine => "/feed"
|
41
|
+
```
|
42
|
+
|
43
|
+
You will now be able to display a feed on _/feed_ in your application. In order
|
44
|
+
for Feeder to display anything in your feed, however, you will need to make
|
45
|
+
views per item type in the feed. Feeder looks up these views in
|
46
|
+
_app/views/feeder/types_ by default, and then checks for a partial with the same
|
47
|
+
name as your item type. As an example, if you have a `Message` model that you
|
48
|
+
wish to list out on your feed, you would make a file called *_message.html.erb*
|
49
|
+
in _app/views/feeder/types_.
|
50
|
+
|
51
|
+
Feeder also comes with an observer for automatically generating wrapper items
|
52
|
+
for your feedables (e.g. messages). In order to use it, you only need to register
|
53
|
+
`Feeder::FeedableObserver` into your app, which can be done in
|
54
|
+
_config/application.rb_ like this:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
config.active_record.observers = [ 'Feeder::FeedableObserver' ]
|
58
|
+
```
|
59
|
+
|
60
|
+
Then, all you need to do is tell Feeder what to
|
61
|
+
observe, which is done through an initializer, like this:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
Feeder.configure do |config|
|
65
|
+
config.observe Message
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
... and declare that your `Message` model is feedable:
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
class Message < ActiveRecord::Base
|
73
|
+
feedable
|
74
|
+
end
|
75
|
+
```
|
76
|
+
|
77
|
+
If you don't want to publish every message in the feed, you can supply a condition
|
78
|
+
to `observe`:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
Feeder.configure do |config|
|
82
|
+
config.observe Message, if: -> message { message.show_in_feed? }
|
83
|
+
end
|
84
|
+
```
|
85
|
+
|
86
|
+
Pretty neat.
|
87
|
+
|
88
|
+
### Filtering
|
89
|
+
|
90
|
+
Want to filter out what feedables to display in your feed? We've got you covered
|
91
|
+
through the all-powerful `filter` scope! Give it a hash of feedables and the
|
92
|
+
IDs that you want to fetch, and Feeder makes sure to only return feed items with
|
93
|
+
the specified feedables. You may also pass in the symbol `:all` instead of a
|
94
|
+
list of IDs, which would fetch each of them. For example: say you have the
|
95
|
+
following feedables:
|
96
|
+
|
97
|
+
- `ShortMessage`
|
98
|
+
- `Tweet`
|
99
|
+
- `NewsArticle`
|
100
|
+
|
101
|
+
To get `Feeder::Item`s with news articles having IDs `[1, 2, 3, 4, 5]`, tweets
|
102
|
+
`[2, 4, 6, 7]` and all short message, you could do like this:
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
Feeder::Item.filter(
|
106
|
+
NewsArticle => [1, 2, 3, 4, 5],
|
107
|
+
Tweet => [2, 4, 6, 7],
|
108
|
+
ShortMessage => :all,
|
109
|
+
)
|
110
|
+
```
|
111
|
+
|
112
|
+
**NOTE:** The `filter` scope is _exclusive_, meaning that anything you _do not_
|
113
|
+
pass in to it will also not be brought back. With the above feedables, if you
|
114
|
+
only want short messages `[1, 3, 4]`, but all of the tweets and news articles,
|
115
|
+
you would have to specify them as well, like this:
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
Feeder::Item.filter(
|
119
|
+
ShortMessage => [1, 3, 4],
|
120
|
+
Tweet => :all,
|
121
|
+
NewsArticle => :all
|
122
|
+
)
|
123
|
+
```
|
124
|
+
|
125
|
+
The following would only return feed items with short messages:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
Feeder::Item.filter(ShortMessage => [1, 3, 4])
|
129
|
+
```
|
130
|
+
|
131
|
+
### Configuration
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
Feeder.configure do |config|
|
135
|
+
# A list of scopes that will be applied to the feed items in the controller.
|
136
|
+
config.scopes << proc { limit 5 }
|
137
|
+
end
|
138
|
+
```
|
139
|
+
|
140
|
+
### Stickies
|
141
|
+
|
142
|
+
You can "sticky" messages in your feed so they're pinned at the top regardless of when
|
143
|
+
they were created. Just set the `sticky` attribute and Feeder will take care of the rest.
|
144
|
+
|
28
145
|
## Contributing
|
29
146
|
|
30
147
|
1. Fork it
|
@@ -1,13 +1,49 @@
|
|
1
1
|
module Feeder
|
2
|
-
class FeedableObserver < ActiveRecord::Observer
|
3
|
-
observe Feeder.config.observables
|
2
|
+
class FeedableObserver < ::ActiveRecord::Observer
|
3
|
+
observe Feeder.config.observables.keys
|
4
4
|
|
5
5
|
def after_create(feedable)
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
options = options_for feedable
|
7
|
+
|
8
|
+
if condition = options[:if]
|
9
|
+
if condition.respond_to? :call
|
10
|
+
return unless condition.call feedable
|
11
|
+
else
|
12
|
+
return unless feedable.send condition
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
feedable.create_feeder_item! do |item|
|
17
|
+
item.feedable = feedable
|
18
|
+
item.created_at = feedable.created_at
|
19
|
+
item.published_at = Time.zone.now
|
20
|
+
|
21
|
+
if feedable.respond_to? :sticky
|
22
|
+
item.sticky = feedable.sticky
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def after_save(feedable)
|
28
|
+
item = feedable.feeder_item
|
29
|
+
|
30
|
+
if item
|
31
|
+
if feedable.respond_to? :sticky
|
32
|
+
item.sticky = feedable.sticky
|
33
|
+
end
|
34
|
+
|
35
|
+
item.save!
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def options_for(feedable)
|
42
|
+
(observables[feedable.class] || observables[feedable.class.to_s]) or raise StandardError, "#{feedable} is not observed"
|
43
|
+
end
|
44
|
+
|
45
|
+
def observables
|
46
|
+
Feeder.config.observables
|
11
47
|
end
|
12
48
|
end
|
13
49
|
end
|
data/app/models/feeder/item.rb
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
json.partial! "feeder/types/#{item.type}", feedable: item.feedable
|
@@ -0,0 +1 @@
|
|
1
|
+
json.array! @items, partial: "feeder/items/item", as: :item
|
data/config/routes.rb
CHANGED
@@ -0,0 +1,13 @@
|
|
1
|
+
class ProhibitNullOnFeederItemStickies < ActiveRecord::Migration
|
2
|
+
class Feeder::Item < ActiveRecord::Base; end
|
3
|
+
|
4
|
+
def up
|
5
|
+
Feeder::Item.where(sticky: nil).update_all sticky: false
|
6
|
+
|
7
|
+
change_column :feeder_items, :sticky, :boolean, null: false
|
8
|
+
end
|
9
|
+
|
10
|
+
def down
|
11
|
+
change_column :feeder_items, :sticky, :boolean, null: true
|
12
|
+
end
|
13
|
+
end
|
data/lib/feeder.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require "feeder/engine"
|
2
2
|
require "feeder/configuration"
|
3
|
+
require "feeder/concerns"
|
4
|
+
require "feeder/active_record"
|
5
|
+
require "kaminari"
|
3
6
|
|
4
7
|
module Feeder
|
5
8
|
|
@@ -9,9 +12,22 @@ module Feeder
|
|
9
12
|
end
|
10
13
|
|
11
14
|
def configure
|
12
|
-
|
15
|
+
yield config if block_given?
|
16
|
+
end
|
17
|
+
|
18
|
+
# Set temporary configuration options for the duration of the given block.
|
19
|
+
#
|
20
|
+
# options - A Hash describing temporary configuration options.
|
21
|
+
def temporarily options = {}
|
22
|
+
original = @configuration.dup
|
23
|
+
|
24
|
+
options.each do |key, value|
|
25
|
+
@configuration.send "#{key}=", value
|
26
|
+
end
|
13
27
|
|
14
|
-
yield
|
28
|
+
yield
|
29
|
+
ensure
|
30
|
+
@configuration = original
|
15
31
|
end
|
16
32
|
end
|
17
33
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Feeder
|
2
|
+
module Concerns::Controllers::ItemsController
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
respond_to :html, :json
|
7
|
+
|
8
|
+
def index
|
9
|
+
@items = Item.order(sticky: :desc)
|
10
|
+
|
11
|
+
Feeder.config.scopes.each do |scope|
|
12
|
+
@items = @items.instance_eval &scope
|
13
|
+
end
|
14
|
+
|
15
|
+
@items = @items.page(params[:page] || 1)
|
16
|
+
@items = @items.per(params[:limit] || 25)
|
17
|
+
|
18
|
+
respond_with @items
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Feeder::Concerns::Feedable
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
attr_accessor :sticky
|
6
|
+
|
7
|
+
has_one :feeder_item, as: :feedable, class_name: 'Feeder::Item', dependent: :destroy
|
8
|
+
|
9
|
+
def sticky
|
10
|
+
if feeder_item
|
11
|
+
feeder_item.sticky
|
12
|
+
else
|
13
|
+
!!@sticky
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def sticky= value
|
18
|
+
@sticky = value
|
19
|
+
|
20
|
+
if feeder_item
|
21
|
+
feeder_item.sticky = value
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
delegate :block, :unblock, :blocked?, :report, :unreport, :reported?, to: :feeder_item
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Feeder
|
2
|
+
module Concerns::Helpers::Filter
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
scope :filter, ->(options) {
|
7
|
+
args = []
|
8
|
+
wheres = options.each.map do |feedable, ids|
|
9
|
+
ids = feedable.pluck :id if ids == :all
|
10
|
+
|
11
|
+
args << feedable << ids
|
12
|
+
|
13
|
+
"(feedable_type = ? AND feedable_id IN (?))"
|
14
|
+
end.join " OR "
|
15
|
+
|
16
|
+
where(wheres, *(args))
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Feeder
|
2
|
+
module Concerns::Models::Item
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
include Feeder::Concerns::Helpers::Filter
|
7
|
+
|
8
|
+
belongs_to :feedable, polymorphic: true
|
9
|
+
|
10
|
+
def type
|
11
|
+
feedable_type.underscore
|
12
|
+
end
|
13
|
+
|
14
|
+
def report
|
15
|
+
self.update reported: true
|
16
|
+
end
|
17
|
+
|
18
|
+
def block
|
19
|
+
self.update blocked: true
|
20
|
+
end
|
21
|
+
|
22
|
+
def unreport
|
23
|
+
self.update reported: false
|
24
|
+
end
|
25
|
+
|
26
|
+
def unblock
|
27
|
+
self.update blocked: false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|