Sitelet https://github.com/Zorros/unread
Skip to content
 
 

Latest commit

 

History

79 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Unread

Ruby gem to manage read/unread status of ActiveRecord objects - and it's fast.

Build Status

About this fork

The original gem creates a new read mark whenever a "reader" is created. That way, this new user is not going to be able to read past messages, that could be important for him. So this fork avoid the creation of that read mark, so the user have access to all messages, from the beginning.

Features

  • Manages unread records for anything you want users to read (like messages, documents, comments etc.)
  • Supports mark as read to mark a single record as read
  • Supports mark all as read to mark all records as read in a single step
  • Gives you a scope to get the unread records for a given user
  • Needs only one additional database table
  • Most important: Great performance

Requirements

  • Ruby 1.8.7 or 1.9.x
  • Rails >= 2.3.6 (including 3.0, 3.1, 3.2)
  • Tested with SQLite and MySQL
  • Needs a timestamp field in your models (e.g. created_at) with a database index on it

Installation

Step 1: Add this to your Gemfile:

gem 'unread'

and run

bundle

Step 2: Add this migration:

class CreateReadMarks < ActiveRecord::Migration
  def self.up
    create_table :read_marks, :force => true do |t|
      t.integer  :readable_id
      t.integer  :user_id,       :null => false
      t.string   :readable_type, :null => false, :limit => 20
      t.datetime :timestamp
    end

    add_index :read_marks, [:user_id, :readable_type, :readable_id]
  end

  def self.down
    drop_table :read_marks
  end
end

and run the migration:

rake db:migrate

Usage

class User < ActiveRecord::Base
  acts_as_reader
end

class Message < ActiveRecord::Base
  acts_as_readable :on => :created_at
end

message1 = Message.create!
message2 = Message.create!

## Get unread messages for a given user
Message.unread_by(current_user)
# => [ message1, message2 ]

message1.mark_as_read! :for => current_user
Message.unread_by(current_user)
# => [ message2 ]

## Get all messages including the read status for a given user
messages = Message.with_read_marks_for(current_user)
# => [ message1, message2 ]
messages[0].unread?(current_user)
# => false
messages[1].unread?(current_user)
# => true

Message.mark_as_read! :all, :for => current_user
Message.unread_by(current_user)
# => [ ]

# Optional: Cleaning up unneeded markers
# Do this in a cron job once a day.
Message.cleanup_read_marks!

How does it work?

The main idea of this gem is to manage a list of read items for every reader after a certain timestamp.

The gem defines a scope doing a LEFT JOIN to this list, so your app can get the unread items in a performant manner. Of course, other scopes can be combined.

It will be ensured that the list of read items will not grow up too much:

  • If a user uses "mark all as read", his list gets deleted and the timestamp is set to the current time.
  • If a user never uses "mark all as read", the list will grow and grow with each item he reads. But there is help: Your app can use a cleanup method which removes unnecessary list items.

Overall, this gem can be used for large data. Please have a look at the generated SQL queries, here is an example:

# Assuming we have a user who has marked all messages as read on 2010-10-20 08:50
current_user = User.find(42)

# Get the unread messages for this user
Message.unread_by(current_user)

Generates query:

SELECT messages.*
FROM messages
LEFT JOIN read_marks ON read_marks.readable_type = 'Message'
                    AND read_marks.readable_id = messages.id
                    AND read_marks.user_id = 42
                    AND read_marks.timestamp >= messages.created_at
WHERE read_marks.id IS NULL
AND messages.created_at > '2010-10-20 08:50:00'

Hint: You should add a database index on messages.created_at.

Similar tools

There are two other gems/plugins doing a similar job:

Unfortunately, both of them have a lack of performance, because they calculate the unread records doing a find(:all), which should be avoided for a large amount of records. This gem is based on a timestamp algorithm and therefore it's very fast.

Copyright (c) 2010,2012 Georg Ledermann, released under the MIT license

About

Ruby gem to manage read/unread status of ActiveRecord objects - and it's fast.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages