Git Product home page Git Product logo

streama's Introduction

Streama

  • THIS PROJECT IS NO LONGER MAINTAINED *

Streama is a simple Ruby activity stream gem for use with the Mongoid ODM framework.

It works by posting to and querying from a firehose of individual activity items.

Currently Streama uses a Fan Out On Read approach. This is great for single instance databases, however if you plan on Sharding then please be aware that it'll hit every shard when querying. I plan on changing the schema soon so that it Fans Out On Write with bucketing.

Data Modeling Examples from the real world

travis Code Climate

Project Tracking

Install

gem install streama

Usage

Define Activities

Create an Activity model and define the activities and the fields you would like to cache within the activity.

An activity consists of an actor, a verb, an object, and a target.

class Activity
  include Streama::Activity

  activity :new_photo do
    actor :user, :cache => [:full_name]
    object :photo, :cache => [:subject, :comment]
    target_object :album, :cache => [:title]
  end

end

The activity verb is implied from the activity name, in the above example the verb is :new_photo

The object may be the entity performing the activity, or the entity on which the activity was performed. e.g John(actor) shared a video(object)

The target is the object that the verb is enacted on. e.g. Geraldine(actor) posted a photo(object) to her album(target)

This is based on the Activity Streams 1.0 specification (http://activitystrea.ms)

Setup Actors

Include the Actor module in a class and override the default followers method.

class User
	include Mongoid::Document
	include Streama::Actor

	field :full_name, :type => String

	def followers
		User.excludes(:id => self.id).all
	end
end

Setup Indexes

Create the indexes for the Activities collection. You can do so by calling the create_indexes method.

Activity.create_indexes

Publishing Activity

In your controller or background worker:

current_user.publish_activity(:new_photo, :object => @photo, :target_object => @album)

This will publish the activity to the mongoid objects returned by the #followers method in the Actor.

To send your activity to different receievers, pass in an additional :receivers parameter.

current_user.publish_activity(:new_photo, :object => @photo, :target_object => @album, :receivers => :friends) # calls friends method
current_user.publish_activity(:new_photo, :object => @photo, :target_object => @album, :receivers => current_user.find(:all, :conditions => {:group_id => mygroup}))

Retrieving Activity

To retrieve the activity stream for an actor

current_user.activity_stream

To retrieve the activity stream and filter by activity type

current_user.activity_stream(:type => :activity_verb)

To retrieve all activities published by an actor

current_user.published_activities

To retrieve all activities published by an actor and filtered by activity type

current_user.published_activities(:type => :activity_verb)

If you need to return the instance of an :actor, :object or :target_object from an activity call the Activity#load_instance method

activity.load_instance(:actor)

You can also refresh the cached activity data by calling the Activity#refresh_data method

activity.refresh_data

Upgrading

0.3.8

Mongoid 4 support added.

0.3.6

Mongoid 3.0 support added.

0.3.3

The Activity "target" field was renamed to "target_object". If you are upgrading from a previous version of Streama you will need to rename the field in existing documents.

http://www.mongodb.org/display/DOCS/Updating#Updating-%24rename

Contributing

Once you've made your great commits

  1. Fork
  2. Create a topic branch - git checkout -b my_branch
  3. Push to your branch - git push origin my_branch
  4. Create a Pull Request from your branch
  5. That's it!

streama's People

Contributors

blackxored avatar christospappas avatar dependabot[bot] avatar hadees avatar hookercookerman avatar l4u avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

streama's Issues

Set a flag when a user has viewed an activity.

I've noticed that streama does a pretty good job acting as a way of displaying notifications to users. The issue i'm running into is that I can't tell a user what notifications are new or not because I'm not tracking when they viewed them. I started writing a simple patch for this but I quickly realized it didn't make sense because users share activities models. So i'm open to suggestions on how best to do this. Would you even accept a patch?

I've also being thinking how hard it would be to allow a model to use streama twice. So a user model could have Activity and Notification.

Duplicate activity entries

Add the option to check whether the same activity has recently been made, if it has then update the timestamp, otherwise create a new activity.

Streama uses reserved mongoid field

Activity class is broken because it uses the reserved field :target ( https://github.com/christospappas/streama/blob/master/lib/streama/activity.rb#L13 ).

Using mongo (1.5.2)
Using mongoid (2.4.3)

mongoid (2.4.3) lib/mongoid/fields.rb:328:in`check_field_name!'
mongoid (2.4.3) lib/mongoid/fields.rb:192:in `field'
bundler/gems/streama-c9a3c3e891bc/lib/streama/activity.rb:13:in`block in module:Activity'
activesupport (3.1.0) lib/active_support/concern.rb:122:in `class_eval'
activesupport (3.1.0) lib/active_support/concern.rb:122:in`append_features'
app/models/activity.rb:2:in `include'
app/models/activity.rb:2:in`class:Activity'
app/models/activity.rb:1:in `<top (required)>'

Specifying DSL in YML instead of ruby data structures

I am wondering if creating an activity in Streama could be faster if the activities were specified in a YML file that was loaded at program start-up instead of a DSL that is parsed every time an Activity is created. Have you considered using YML? Do you believe it would give a decent speedup?

adding SQL database support for actor

So, I commented out:

 # raise Errors::NotMongoid, "Must be included in a Mongoid::Document" unless self.ancestors.include? Mongoid::Document

in actor.rb. And it looks like it's still working with my User<ActiveRecord::Base model. I only needed to make a new Mongoid based Activity model. As a noob, am I wondering into dangerous territory? It would be really cool if this also support my current data schema.Thanks for the great work!

Actor could be a polymorphic resource

Hello,

I have been experimenting a bit more with the Streama code.
For my current idea, I would need to work with an ActivityStream where an Actor would be a polymorphic resource, i.e. a user and a company could take part in the same activity definition.

For this, I have been experimenting with some small refactorings, as shown here: https://github.com/mulderp/streama/commits/actors I probably would introduce an Actor class that is embedded or referred to from an Activity.

Still some path to go, but eventually, feedback might be interesting, what you think on this.

Small testapp for Streama

It would be helpful to creatte a small test application, to see how Streama can be used in existing applications.

I created a small start here: https://github.com/mulderp/streama_testapp

The idea would be to have a NetworkUpdates#create publish to a public and/or private newsstream.

I got so far:

param_hash = {:user => current_user.id}.merge(params[:network_update])
network_update = NetworkUpdate.create(param_hash)
#current_user.publish_activity(:share, :object => network_update, :receivers => User.all )
# Activity.publish(:share, {:user => current_user, :object => network_update, :receivers => User.all })

However, either current_user and the :receivers part is not yet working out. Will have to check again when time allows.

Thank in any case for feedback!

0.3.6 - NoMethodError: undefined method `find' for Object:Class

Using mongoid 2.0. Works in steama 0.3.5, but not in 0.3.6.

NoMethodError: undefined method `find' for Object:Class
    from /Users/anton/.rvm/gems/ruby-1.9.3-p194@oddsense/gems/streama-0.3.6/lib/streama/activity.rb:90:in `load_instance'
    from /Users/anton/.rvm/gems/ruby-1.9.3-p194@oddsense/gems/streama-0.3.6/lib/streama/activity.rb:78:in `publish'
    from /Users/anton/.rvm/gems/ruby-1.9.3-p194@oddsense/gems/streama-0.3.6/lib/streama/activity.rb:55:in `publish'
    from /Users/anton/.rvm/gems/ruby-1.9.3-p194@oddsense/gems/streama-0.3.6/lib/streama/actor.rb:29:in `publish_activity'
    from (irb):3

did some debugging:

error happens here: https://github.com/christospappas/streama/blob/master/lib/streama/activity.rb#L90

    def load_instance(type)
      (data = self.read_attribute(type)).is_a?(Hash) ? data['type'].to_s.camelcase.constantize.find(data['id']) : data
    end

type == :actor
self.read_attribute(type) returns hash which has '_type' but no 'type' key.

After plain a bit more and reverting that line
9010eeb#L2R11

to this:

    field :actor,         :type => Hash

I have only actor but probably other fields will have the same issue.

Everything works after that reverted line. self.read_attribute(type) returns Object but not hash. Can't really explain that behaviour, but hopefully it will give you some ideas where to look.

Do you need help on fan out on write?

Hi Christos,

I see that you plan on changing the schema to fan out on write. Do you need any help on getting this completed? I am interested in helping with schema design or some of the work required as this seems like an important change.

Single table inheritance - type field breaks `load_instance` when cached

I noticed that if I am using a type column in my object and I want to cache it, I run into unexpected problems. I believe the reason lies in activity.rb

  # stores the correct class
  hash = {'id' => object.id, 'type' => object.class.name}

  if fields = definition.send(type)[class_sym].try(:[],:cache)
    fields.each do |field|
      raise Errors::InvalidField.new(field) unless object.respond_to?(field)
      # here it gets overriten by STI "type" field
      hash[field.to_s] = object.send(field)
    end
  end
  write_attribute(type, hash)
end

Where the type is rewritten by the one from the model's attributes and the load_instance is than throwing an error because it could not find an object based on this type. Note that this only happens if the type column is being cached.

Activity Stream with MongoID How To

Dears,

kindly, i came across streama as i'd like to implement Activity Stream to my in development application using mongodb and Mongoid.

my application activity stream i'd like to implement is same as twitter stream for tweets of your account and accounts you follow.
how that can be implemented using streama.

and i was looking for a How To document for How To using streama in the application,an a detailed information and use cases for the dsl Definition but i didn't find any. please what is target, receivers.

Thanks and Best Regards,
Shenouda Bertel

Integrate the likes/comments for activity

It would be nice to have the comments and likes included in this project. Also if there is a way to calculate the number of people who liked it and number of people who commented as metadata that would be slick.

Index definition syntax

I'm able to use streama with mongoid 2.4.12 and when I'm trying to perform rake db:mongoid:create_indexes it says me:

Invalid index specification {:name=>1}; should be either a string, symbol, or an array of arrays.

It's caused by Streama::Activity module content.

Also I can not understand, why this module is trying to index name field, that was not defined before.
Thanks.

Invalid Data for class with namespace

I have a class in a module as below. It runs into a error "Invalid Data: mongoid/comment" when user published the comment activity.

class Comment

Module Mongoid
class Comment
...
end
end

class Activity

activity :new_comment do
actor :user
object :"Mongoid::Comment"
target_object :community
end

The class Comment has to have a namespace. How to solve the issue?

Find activities by target_object or object

First of all, thank you for the great useful gem! I think there could be a common scenario for retrieving activities by target_object or object, say I want to retrieve all update happened in a community or some communities.

The weired thing is empty result is retrieved, no matter which way to query. For example:

Check data existed

Activity.first
=>#<Activity _id: 51e4b533f9dffb599a000002, _type: nil, created_at: 2013-07-16 02:51:31 UTC, updated_at: 2013-07-16 02:51:31 UTC, verb: :new_topic, actor: {"id"=>"51e3661af9dffbce7c000001", "type"=>"User"}, object: {"id"=>"51e4b533f9dffb599a000001", "type"=>"Topic"}, target_object: {"id"=>"51e37648f9dffb5e4c000013", "type"=>"Community"}, receivers: [{"id"=>"51e3fb35f9dffbafff000001", "type"=>"User"}]>

Query all activities happened in some communities

Activity.in(target_object: [{'id' => '51e37648f9dffb5e4c000013', 'type' => 'Community'}]).count
=> 0

or

Activity.where(:target_object.in => [{'id' => '51e37648f9dffb5e4c000013', 'type' => 'Community'}]).count
=> 0

Query all activities happened in a community

Activity.where({'target_object.id' => '51e37648f9dffb5e4c000013', 'target_object.type' => 'Community'}).count
=> 0

or

Activity.where(target_object: {'id' => '51e37648f9dffb5e4c000013', 'type' => 'Community'}).count
=> 0

I cannot figure out why this happens!!!

Whether it is because the target_object field type is undefined? Why not define the target_object field as Hash type, but left it as undefined?

Activities grouped by post

We allow users to comment on Post, which generates new_comment activity. if multiple users comment on a same post, it result in multiple activities. is there a way to group activities by post?

Aggregated similar events together

I'm not 100% sure how this should work. But basically I think we need something that'll let you collapse similar activities into one. For example if one of my activities is someone liked my post it isn't a problem but what happens if 100 people liked my post. Then my stream is going to be spammed and it won't be very useful. It would be better if I got John Doe and 99 others liked your post.

I was thinking this might be a good problem for map reduce although that would probably require Streama to pull activities from a separate collection and run the map reduce every so often to update it.

Possible discrepancy in the class to symbol casting

When an activity is defined, it is allowed to specify the actor/object classes as symbols.
Even the example in the readme is

activity :new_photo do
    actor :user, :cache => [:full_name]
    object :photo, :cache => [:subject, :comment]
    target_object :album, :cache => [:title]
  end

Note, that the symbols (user/photo/album) are all lower-case.
But in the assign_data method of class Activity the error check goes as:

class_sym = object.class.name.underscore.to_sym
raise Errors::InvalidData.new(class_sym) unless definition.send(type).has_key?(class_sym)

So if I send an object of the class User, class_sym would be :User and not :user
which should cause the check to fail and the error to be raised.

PS I haven't seen any such error till now (not till I started tinkering with the source in my fork), which is why I mentioned 'possbile discrepancy' ๐Ÿ˜•

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.