stream_rails 1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YTMwN2JiNjM1YTNhYjQwZjBkNmNlMTc2YTM3ZjQ0NTllOTRjMjI3Yg==
5
+ data.tar.gz: !binary |-
6
+ OTY1NjJkMzc2YTJjZDI0ZjIwZTY3YjIxYTI3NWVlY2FlNTc1N2NhMg==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MGQ3YWE0NjI5M2I0NzdlMDcyZjhmN2ExMjFjOWU4ZTY2MTc4NzBjYTkyZTI5
10
+ Nzg4ZTNiMTU2OWE3NzI0ZGM2ZmZmNDRjYTNlNzQ3MDA0MTU0ZDFmZDBmOThi
11
+ MzI5YjQ0M2U2NzljNjQ1MjQxNDI0ZmY2Yjg1MzZjNmI1YmZlZWI=
12
+ data.tar.gz: !binary |-
13
+ M2Y4ODA5YWQ0OTZjZjllNjRkYjkyZTNkMmFkYzY2NGFmYmYyZjIzZmQ1ODE4
14
+ YmE1OTk1MzAyMTNlOTUwMGM1NGNlYWE2ZjE3ODIxZDAwMTljMWU0Y2VhZWRi
15
+ NjU0ZjYxZTUwMzQ4MGRhY2UxNjE2YzM4MjEzMWJkZTc5MmNkMWY=
data/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+ Copyright (c) 2014, Tommaso Barbugli
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ * Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ * Neither the name of the {organization} nor the names of its
15
+ contributors may be used to endorse or promote products derived from
16
+ this software without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,262 @@
1
+ Stream Rails
2
+ ============
3
+
4
+ [![image](https://secure.travis-ci.org/GetStream/stream-rails.png?branch=master)](http://travis-ci.org/GetStream/stream-rails)
5
+
6
+
7
+ This package helps you create activity streams & newsfeeds with Ruby on Rails and [GetStream.io](https://getstream.io).
8
+
9
+ ###Activity Streams & Newsfeeds
10
+
11
+ ![](https://dvqg2dogggmn6.cloudfront.net/images/mood-home.png)
12
+
13
+ What you can build:
14
+
15
+ * Activity streams such as seen on Github
16
+ * A twitter style newsfeed
17
+ * A feed like instagram/ pinterest
18
+ * Facebook style newsfeeds
19
+ * A notification system
20
+
21
+ ###Table of Contents
22
+
23
+ ### Gem installation
24
+
25
+ You can install ```stream_rails``` as you would any other gem:
26
+
27
+ ```gem install stream_rails```
28
+
29
+ or in your Gemfile:
30
+
31
+ ```gem 'stream_rails'```
32
+
33
+
34
+ ### Setup
35
+
36
+ Login with Github on getstream.io and get your ```api_key``` and ```api_secret``` from your app configuration (Dashboard screen).
37
+
38
+ Then you can add the StreamRails configuration in ```config/initializers/stream_rails.rb```
39
+
40
+ ```
41
+ require 'stream_rails'
42
+
43
+ StreamRails.configure do |config|
44
+ config.api_key = "YOUR API KEY"
45
+ config.api_secret = "YOUR API SECRET"
46
+ end
47
+ ```
48
+
49
+ ### Model configuration
50
+
51
+ Include StreamRails::Activity and add as_activity to the model you want to integrate with your feeds.
52
+
53
+ ```ruby
54
+ class Pin < ActiveRecord::Base
55
+ belongs_to :user
56
+ belongs_to :item
57
+
58
+ validates :item, presence: true
59
+ validates :user, presence: true
60
+
61
+ include StreamRails::Activity
62
+ as_activity
63
+ end
64
+ ```
65
+ Everytime a Pin is created it will be stored in the feed of the user that created it, and when a Pin instance is deleted than it will get removed as well.
66
+
67
+ ####Activity fields
68
+
69
+ Models are stored in feeds as activities. An activity is composed of at least the following data fields: **actor**, **verb**, **object**, **time**. You can also add more custom data if needed.
70
+
71
+ **object** is a reference to the model instance itself
72
+ **actor** is a reference to the user attribute of the instance
73
+ **verb** is a string representation of the class name
74
+
75
+ In order to work out-of-the-box, the Activity class makes makes few assumptions:
76
+
77
+ 1. the Model class belongs to a user
78
+ 2. the model table has timestamp columns (created_at is required)
79
+
80
+ You can change this behaviour by overriding ```#activity_actor```.
81
+
82
+ Below shows an example how to change your class if the model belongs to an author instead of to a user.
83
+
84
+ ```ruby
85
+ class Pin < ActiveRecord::Base
86
+ belongs_to :author
87
+ belongs_to :item
88
+
89
+ include StreamRails::Activity
90
+ as_activity
91
+
92
+ def activity_actor
93
+ self.author
94
+ end
95
+
96
+ end
97
+ ```
98
+
99
+ ####Activity extra data
100
+
101
+ Often you'll want to store more data than just the basic fields. You achieve this by implementing ```#activity_extra_data``` in your model.
102
+
103
+
104
+ ```ruby
105
+ class Pin < ActiveRecord::Base
106
+ belongs_to :author
107
+ belongs_to :item
108
+
109
+ include StreamRails::Activity
110
+ as_activity
111
+
112
+ def activity_extra_data
113
+ {'is_retweet' => self.is_retweet}
114
+ end
115
+
116
+ end
117
+ ```
118
+
119
+ ###Feed manager
120
+
121
+ ```stream_rails``` comes with a Feed Manager class that helps with all common feed operations. You can get an instance of the manager with ```StreamRails.feed_manager```.
122
+
123
+ ```ruby
124
+ feed = StreamRails.feed_manager.get_user_feed(current_user.id)
125
+ ```
126
+
127
+ ####Feeds bundled with feed_manager
128
+
129
+ To get you started the manager has 4 feeds pre configured. You can add more feeds if your application needs it.
130
+ Feeds are divided in three categories.
131
+
132
+ #####User feed:
133
+ The user feed stores all activities for a user. Think of it as your personal Facebook page. You can easily get this feed from the manager.
134
+ ```ruby
135
+ feed = StreamRails.feed_manager.get_user_feed(current_user.id)
136
+ ```
137
+
138
+ #####News feeds:
139
+ The news feeds store the activities from the people you follow.
140
+ There is both a flat newsfeed (similar to twitter) and an aggregated newsfeed (like facebook).
141
+
142
+ ```php
143
+ feed = StreamRails.feed_manager.get_news_feeds(current_user.id)[:flat]
144
+ aggregated_feed = StreamRails.feed_manager.get_news_feeds(current_user.id)[:aggregated]
145
+ ```
146
+
147
+ #####Notification feed:
148
+ The notification feed can be used to build notification functionality.
149
+
150
+ ![Notification feed](http://feedly.readthedocs.org/en/latest/_images/fb_notification_system.png)
151
+
152
+ Below we show an example of how you can read the notification feed.
153
+ ```ruby
154
+ notification_feed = StreamRails.feed_manager.get_notification_feed(current_user.id)
155
+
156
+ ```
157
+ By default the notification feed will be empty. You can specify which users to notify when your model gets created. In the case of a retweet you probably want to notify the user of the parent tweet.
158
+
159
+ ```ruby
160
+ class Pin < ActiveRecord::Base
161
+ belongs_to :author
162
+ belongs_to :item
163
+
164
+ include StreamRails::Activity
165
+ as_activity
166
+
167
+ def activity_notify
168
+ if self.is_retweet
169
+ [feed_manager.get_notification_feed(self.parent.user_id)]
170
+ end
171
+ end
172
+
173
+ end
174
+ ```
175
+
176
+ Another example would be following a user. You would commonly want to notify the user which is being followed.
177
+
178
+ ```ruby
179
+ class Follow < ActiveRecord::Base
180
+ belongs_to :user
181
+ belongs_to :target
182
+
183
+ validates :target_id, presence: true
184
+ validates :user, presence: true
185
+
186
+ include StreamRails::Activity
187
+ as_activity
188
+
189
+ def activity_notify
190
+ [feed_manager.get_notification_feed(self.target_id)]
191
+ end
192
+
193
+ end
194
+ ```
195
+
196
+ ####Follow a feed
197
+ The create the newsfeeds you need to notify the system about follow relationships. The manager comes with APIs to let a user's news feeds follow another user's feed. This code lets the current user's flat and aggregated feeds follow the target_user's personal feed.
198
+
199
+ ```
200
+ StreamRails.feed_manager.follow_user(user_id, target_id)
201
+ ```
202
+
203
+ ### Showing the newsfeed
204
+
205
+ ####Activity enrichment
206
+
207
+ When you read data from feeds, a pin activity will look like this:
208
+
209
+ ```json
210
+ {"actor": "User:1", "verb": "like", "object": "Pin:42"}
211
+ ```
212
+
213
+ This is far from ready for usage in your template. We call the process of loading the references from the database enrichment. An example is shown below:
214
+
215
+ ```ruby
216
+ enricher = StreamRails::Enrich.new
217
+
218
+ feed = StreamRails.feed_manager.get_news_feeds(current_user.id)[:flat]
219
+ results = feed.get()['results']
220
+ activities = enricher.enrich_activities(results)
221
+ ```
222
+
223
+ ####Templating
224
+
225
+ Now that you've enriched the activities you can render them in a view.
226
+ For convenience we includes a basic view:
227
+
228
+ ```
229
+ <div class="container">
230
+ <div class="container-pins">
231
+ <% for activity in @activities %>
232
+ <%= render_activity activity %>
233
+ <% end %>
234
+ </div>
235
+ </div>
236
+ ```
237
+
238
+ The ```render_activity``` view helper will render the activity by picking the partial ```activity/_pin``` for a pin activity, ```aggregated/_follow``` for an aggregated activity with verb follow.
239
+
240
+ The helper will automatically send ```activity``` to the local scope of the partial; additional parameters can be send as well as use different layouts, and prefix the name
241
+
242
+
243
+ eg. renders the activity partial using the ```small_activity``` layout.
244
+
245
+ ```
246
+ <%= render_activity activity, :layout => "small_activity" %>
247
+ ```
248
+
249
+
250
+ eg. prefixes the name of the template with "notification_"
251
+
252
+ ```
253
+ <%= render_activity activity, :prefix => "notification_" %>
254
+ ```
255
+
256
+ eg. adds the extra_var to the partial scope
257
+
258
+ ```
259
+ <%= render_activity activity, :locals => {:extra_var => 42} %>
260
+ ```
261
+
262
+
@@ -0,0 +1,47 @@
1
+ require 'active_support'
2
+ require 'action_view'
3
+ require 'stream'
4
+ require 'stream_rails/enrich'
5
+ require 'stream_rails/logger'
6
+
7
+ module StreamRails
8
+ extend ActiveSupport::Autoload
9
+
10
+ autoload :Activity
11
+ autoload :Config
12
+ autoload :FeedManager, 'stream_rails/feed_manager'
13
+ autoload :Renderable
14
+ autoload :VERSION
15
+
16
+ def self.client
17
+ Stream::Client.new(self.config.api_key, self.config.api_secret)
18
+ end
19
+
20
+ # Returns StreamRails's configuration object.
21
+ def self.config
22
+ @config ||= StreamRails::Config.new
23
+ end
24
+
25
+ # Returns StreamRails's configuration object.
26
+ def self.feed_manager
27
+ @feed_manager ||= StreamRails::FeedManager.new(self.client, self.config.feed_configs)
28
+ end
29
+
30
+ # Lets you set global configuration options.
31
+ #
32
+ # All available options and their defaults are in the example below:
33
+ # @example Initializer for Rails
34
+ # StreamRails.configure do |config|
35
+ # config.api_key = "key"
36
+ # config.api_secret = "secret"
37
+ # config.api_site_id = "42"
38
+ # config.enabled = true
39
+ # end
40
+ def self.configure(&block)
41
+ yield(config) if block_given?
42
+ end
43
+
44
+ end
45
+
46
+ require 'stream_rails/utils/view_helpers'
47
+ require 'stream_rails/railtie' if defined?(Rails)
@@ -0,0 +1,93 @@
1
+ require 'active_record'
2
+ require 'stream_rails/sync_policies'
3
+
4
+ module StreamRails
5
+
6
+ class << self
7
+ def create_reference(record)
8
+ if record.is_a? ActiveRecord::Base
9
+ "#{record.class.model_name}:#{record.id}"
10
+ else
11
+ record.to_s unless record.nil?
12
+ end
13
+ end
14
+ end
15
+
16
+ module ClassMethods
17
+
18
+ def as_activity(opts = {})
19
+ default_opts = {:track_deletes => true, :sync_policy => nil}
20
+ options = default_opts.merge(opts)
21
+ if options[:sync_policy].nil?
22
+ include StreamRails::SyncPolicy::SyncCreate
23
+ if options[:track_deletes]
24
+ include StreamRails::SyncPolicy::SyncDestroy
25
+ end
26
+ else
27
+ include options[:sync_policy]
28
+ end
29
+ end
30
+
31
+ end
32
+
33
+ module Activity
34
+
35
+ def self.included base
36
+ base.extend ClassMethods
37
+ end
38
+
39
+ def activity_owner_id
40
+ self.user_id
41
+ end
42
+
43
+ def activity_actor
44
+ self.user
45
+ end
46
+
47
+ def activity_owner_feed
48
+ 'user'
49
+ end
50
+
51
+ def activity_actor_id
52
+ StreamRails.create_reference(self.activity_actor)
53
+ end
54
+
55
+ def activity_verb
56
+ self.class.model_name.to_s
57
+ end
58
+
59
+ def activity_object_id
60
+ StreamRails.create_reference(self)
61
+ end
62
+
63
+ def activity_foreign_id
64
+ StreamRails.create_reference(self)
65
+ end
66
+
67
+ def activity_notify
68
+ end
69
+
70
+ def activity_extra_data
71
+ {}
72
+ end
73
+
74
+ def activity_time
75
+ self.created_at
76
+ end
77
+
78
+ def create_activity
79
+ activity = {
80
+ :actor => self.activity_actor_id,
81
+ :verb => self.activity_verb,
82
+ :object => self.activity_object_id,
83
+ :foreign_id => self.activity_foreign_id,
84
+ :time => self.activity_time,
85
+ }
86
+ if !self.activity_notify.nil?
87
+ activity[:to] = self.activity_notify.map{|f| f.feed_id}
88
+ end
89
+ activity.merge(self.activity_extra_data)
90
+ end
91
+
92
+ end
93
+ end
@@ -0,0 +1,27 @@
1
+ module StreamRails
2
+ # Class used to initialize configuration object.
3
+ class Config
4
+ attr_accessor :api_key
5
+ attr_accessor :api_secret
6
+ attr_accessor :api_site_id
7
+ attr_accessor :enabled
8
+
9
+ attr_accessor :news_feeds
10
+ attr_accessor :notification_feed
11
+ attr_accessor :user_feed
12
+
13
+ def initialize
14
+ @enabled = true
15
+ @news_feeds = {:flat=>'flat', :aggregated=>'aggregated'}
16
+ @notification_feed = 'notification'
17
+ @user_feed = 'user'
18
+ end
19
+
20
+ def feed_configs
21
+ {:news_feeds=>@news_feeds,
22
+ :notification_feed=>@notification_feed,
23
+ :user_feed=>@user_feed}
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,104 @@
1
+ require 'active_record'
2
+
3
+ module StreamRails
4
+
5
+ class ActivityResult < Hash
6
+ attr_accessor :enriched
7
+ attr_reader :failed_to_enrich
8
+
9
+ def initialize
10
+ @failed_to_enrich = Hash.new
11
+ super
12
+ end
13
+
14
+ def from_activity(h)
15
+ self.merge(h)
16
+ end
17
+
18
+ def enriched?
19
+ @failed_to_enrich.keys.length == 0
20
+ end
21
+
22
+ def not_enriched_fields
23
+ @failed_to_enrich.keys
24
+ end
25
+
26
+ def track_not_enriched_field(field, value = nil)
27
+ @failed_to_enrich[field] = value
28
+ end
29
+
30
+ end
31
+
32
+ class Enrich
33
+
34
+ def initialize(fields = nil)
35
+ @fields = fields || [:actor, :object]
36
+ end
37
+
38
+ def model_field?(field_value)
39
+ bits = field_value.split(':')
40
+ if bits.length < 2
41
+ return false
42
+ end
43
+ begin
44
+ bits[0].classify.constantize
45
+ rescue NameError
46
+ return false
47
+ else
48
+ return true
49
+ end
50
+ end
51
+
52
+ def enrich_activities(activities)
53
+ references = self.collect_references(activities)
54
+ objects = self.retrieve_objects(references)
55
+ self.inject_objects(activities, objects)
56
+ end
57
+
58
+ def enrich_aggregated_activities(aggregated_activities)
59
+ references = Hash.new
60
+ aggregated_activities.each do |aggregated|
61
+ refs = self.collect_references(aggregated['activities'])
62
+ references = references.merge(refs){|key, v1, v2| v1.merge(v2)}
63
+ end
64
+ objects = self.retrieve_objects(references)
65
+ aggregated_activities.each do |aggregated|
66
+ aggregated['activities'] = self.inject_objects(aggregated['activities'], objects)
67
+ end
68
+ aggregated_activities.map {|a| ActivityResult.new().from_activity(a)}
69
+ end
70
+
71
+ def collect_references(activities)
72
+ model_refs = Hash.new{ |h,k| h[k] = Hash.new}
73
+ activities.each do |activity|
74
+ activity.select{|k,v| @fields.include? k.to_sym}.each do |field, value|
75
+ next unless self.model_field?(value)
76
+ model, id = value.split(':')
77
+ model_refs[model][id] = 0
78
+ end
79
+ end
80
+ model_refs
81
+ end
82
+
83
+ def retrieve_objects(references)
84
+ Hash[references.map{ |model, ids| [model, Hash[model.classify.constantize.where(id: ids.keys).map {|i| [i.id.to_s, i]}] ] }]
85
+ end
86
+
87
+ def inject_objects(activities, objects)
88
+ activities = activities.map {|a| ActivityResult.new().from_activity(a)}
89
+ activities.each do |activity|
90
+ activity.select{|k,v| @fields.include? k.to_sym}.each do |field, value|
91
+ next unless self.model_field?(value)
92
+ model, id = value.split(':')
93
+ activity[field] = objects[model][id] || value
94
+ if objects[model][id].nil?
95
+ activity.track_not_enriched_field(field, value)
96
+ end
97
+ end
98
+ end
99
+ activities
100
+ end
101
+
102
+ end
103
+
104
+ end
@@ -0,0 +1,61 @@
1
+ module StreamRails
2
+ # Class used to manage feeds
3
+ class FeedManager
4
+ attr_reader :client
5
+
6
+ def initialize(client, opts={})
7
+ @client = client
8
+ @user_feed = opts[:user_feed]
9
+ @news_feeds = opts[:news_feeds]
10
+ @notification_feed = opts[:notification_feed]
11
+ end
12
+
13
+ def get_user_feed(user_id)
14
+ @client.feed("#{@user_feed}:#{user_id}")
15
+ end
16
+
17
+ def get_news_feeds(user_id)
18
+ Hash[@news_feeds.map{ |k,v| [k, self.get_feed(k, user_id)] }]
19
+ end
20
+
21
+ def get_notification_feed(user_id)
22
+ @client.feed("#{@notification_feed}:#{user_id}")
23
+ end
24
+
25
+ def get_feed(feed_type, user_id)
26
+ @client.feed("#{feed_type}:#{user_id}")
27
+ end
28
+
29
+ def follow_user(user_id, target_id)
30
+ target_feed = self.get_user_feed(target_id)
31
+ @news_feeds.each do |_, feed|
32
+ news_feed = self.get_feed(feed, user_id)
33
+ news_feed.follow(target_feed.feed_id)
34
+ end
35
+ end
36
+
37
+ def unfollow_user(user_id, target_id)
38
+ target_feed = self.get_user_feed(target_id)
39
+ @news_feeds.each do |_, feed|
40
+ news_feed = self.get_feed(feed, user_id)
41
+ news_feed.unfollow(target_feed.feed_id)
42
+ end
43
+ end
44
+
45
+ def get_owner_feed(instance)
46
+ self.get_feed(instance.activity_owner_feed, instance.activity_owner_id)
47
+ end
48
+
49
+ def created_activity(instance)
50
+ activity = instance.create_activity
51
+ feed = self.get_owner_feed(instance)
52
+ feed.add_activity(activity)
53
+ end
54
+
55
+ def destroyed_activity(instance)
56
+ feed = self.get_owner_feed(instance)
57
+ feed.remove(instance.activity_foreign_id, foreign_id=true)
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,6 @@
1
+ module StreamRails
2
+ class << self
3
+ attr_accessor :logger
4
+ end
5
+ self.logger = Logger.new(STDOUT)
6
+ end
@@ -0,0 +1,7 @@
1
+ module StreamRails
2
+ class Railtie < ::Rails::Railtie
3
+ initializer 'stream_rails.setup_logging' do
4
+ StreamRails.logger = Rails.logger
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,66 @@
1
+ module StreamRails
2
+ # Provides logic for rendering activities. (different templates per activity verb).
3
+ module Renderable
4
+
5
+ class << self
6
+
7
+ def render(activity, context, params = {})
8
+ aggregated = activity.has_key? 'activities'
9
+ partial = partial_path(activity, aggregated, *params.values_at(:prefix, :partial, :partial_root))
10
+ layout = layout_path(*params.values_at(:layout, :layout_root))
11
+ locals = prepare_locals(activity, params)
12
+ params = params.merge(partial: partial, locals: locals, layout: layout)
13
+ if aggregated
14
+ render_aggregated(activity, context, params)
15
+ else
16
+ render_simple(activity, context, params)
17
+ end
18
+ end
19
+
20
+ def render_simple(activity, context, params)
21
+ if activity.enriched?
22
+ context.render params
23
+ else
24
+ StreamRails.logger.warn "trying to display a non enriched activity #{activity.inspect} #{activity.failed_to_enrich}"
25
+ return ''
26
+ end
27
+ end
28
+
29
+ def render_aggregated(activity, context, params)
30
+ if !activity['activities'].map {|a| !a.enriched?}.all?
31
+ context.render params
32
+ else
33
+ first_activity = activity['activities'][0]
34
+ StreamRails.logger.warn "trying to display a non enriched activity #{first_activity.inspect} #{first_activity.failed_to_enrich}"
35
+ return ''
36
+ end
37
+ end
38
+
39
+ def layout_path(path = nil, root = nil)
40
+ path.nil? and return
41
+ root ||= 'layouts'
42
+ select_path path, root
43
+ end
44
+
45
+ def partial_path(activity, aggregated, prefix = '', path = nil, root = nil)
46
+ root ||= (if aggregated then 'aggregated_activity' else 'activity' end)
47
+ path ||= "#{activity['verb']}".downcase
48
+ path = "#{prefix}_#{path}" if prefix
49
+ select_path path, root
50
+ end
51
+
52
+ def prepare_locals(activity, params)
53
+ locals = params.delete(:locals) || Hash.new
54
+ locals.merge\
55
+ activity: activity,
56
+ parameters: params
57
+ end
58
+
59
+ private
60
+ def select_path path, root
61
+ [root, path].map(&:to_s).join('/')
62
+ end
63
+ end
64
+ end
65
+
66
+ end
@@ -0,0 +1,30 @@
1
+ module StreamRails
2
+
3
+ module SyncPolicy
4
+
5
+ module SyncCreate
6
+
7
+ def self.included(base)
8
+ base.after_commit :add_to_feed, on: [:create]
9
+ end
10
+
11
+ private
12
+ def add_to_feed
13
+ StreamRails.feed_manager.created_activity(self)
14
+ end
15
+ end
16
+
17
+ module SyncDestroy
18
+
19
+ def self.included(base)
20
+ base.after_commit :remove_from_feed, on: [:destroy]
21
+ end
22
+
23
+ private
24
+ def remove_from_feed
25
+ StreamRails.feed_manager.destroyed_activity(self)
26
+ end
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,15 @@
1
+ # Provides a shortcut from views to the rendering method.
2
+ module StreamRails
3
+ # Module extending ActionView::Base and adding `render_activity` helper.
4
+ module ViewHelpers
5
+ # View helper for rendering an activity
6
+ def render_activity activity, options = {}
7
+ Renderable.render(activity, self, options)
8
+ end
9
+ # View helper for rendering many activities
10
+ def render_activities activities, options = {}
11
+ activities.map {|activity| Renderable.render(activity, self, options.dup) }.join.html_safe
12
+ end
13
+ end
14
+ ActionView::Base.class_eval { include ViewHelpers }
15
+ end
@@ -0,0 +1,3 @@
1
+ module StreamRails
2
+ VERSION = '1.0'
3
+ end
metadata ADDED
@@ -0,0 +1,185 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stream_rails
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.0'
5
+ platform: ruby
6
+ authors:
7
+ - Tommaso Barbugli
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-10-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: actionpack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 3.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 3.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: railties
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 3.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: 3.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: stream-ruby
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 1.0.2
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.0.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: activerecord
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 3.0.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: 3.0.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: fakeweb
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: sqlite3
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: '2.10'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ~>
123
+ - !ruby/object:Gem::Version
124
+ version: '2.10'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ~>
130
+ - !ruby/object:Gem::Version
131
+ version: 0.7.1
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ~>
137
+ - !ruby/object:Gem::Version
138
+ version: 0.7.1
139
+ description:
140
+ email: tbarbugli@gmail.com
141
+ executables: []
142
+ extensions: []
143
+ extra_rdoc_files:
144
+ - README.md
145
+ - LICENSE
146
+ files:
147
+ - LICENSE
148
+ - README.md
149
+ - lib/stream_rails.rb
150
+ - lib/stream_rails/activity.rb
151
+ - lib/stream_rails/config.rb
152
+ - lib/stream_rails/enrich.rb
153
+ - lib/stream_rails/feed_manager.rb
154
+ - lib/stream_rails/logger.rb
155
+ - lib/stream_rails/railtie.rb
156
+ - lib/stream_rails/renderable.rb
157
+ - lib/stream_rails/sync_policies.rb
158
+ - lib/stream_rails/utils/view_helpers.rb
159
+ - lib/stream_rails/version.rb
160
+ homepage: http://github.com/tbarbugli/stream-ruby
161
+ licenses:
162
+ - Apache-2.0
163
+ metadata: {}
164
+ post_install_message:
165
+ rdoc_options: []
166
+ require_paths:
167
+ - lib
168
+ required_ruby_version: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ! '>='
171
+ - !ruby/object:Gem::Version
172
+ version: 1.9.2
173
+ required_rubygems_version: !ruby/object:Gem::Requirement
174
+ requirements:
175
+ - - ! '>='
176
+ - !ruby/object:Gem::Version
177
+ version: '0'
178
+ requirements: []
179
+ rubyforge_project:
180
+ rubygems_version: 2.2.2
181
+ signing_key:
182
+ specification_version: 4
183
+ summary: A gem that provides a client interface for getstream.io
184
+ test_files: []
185
+ has_rdoc: true