Coder Social home page Coder Social logo

mongoid_userstamp's Introduction

Mongoid::Userstamp

⚠️ Looking for maintainer ⚠️

I do not use MongoDB for my work so I am looking for a developer who wants to take care of this project. Please contact me at issues.

Mongoid::Userstamp adds stamp columns for created by and updated by information within Rails applications using Mongoid ORM.

Version Support

Mongoid::Userstamp is tested on the following versions:

  • Ruby 2.0+
  • Rails 3.2, 4.x
  • Mongoid 3.1, 4.x, 5.x

Install

  gem 'mongoid_userstamp'

Usage

Mongoid::Userstamp does the following:

  • Defines Mongoid belongs_to relations to the user class for created_by and updated_by on each class where Mongoid::Userstamp is included
  • Automatically tracks the current user via a before_filter (see Rails Integration below)
  • Sets the created_by and updated_by values in before_save and before_update callbacks respectively on the target models.
  • Adds methods to the user class to check for the current user.
  # Default config (optional unless you want to customize the values)
  Mongoid::Userstamp.config do |c|
    c.user_reader = :current_user
    c.created_name = :created_by
    c.updated_name = :updated_by
  end

  # Example model class
  class Product
    include Mongoid::Document
    include Mongoid::Userstamp

    # optional class-level config override
    # mongoid_userstamp user_model: 'MyUser',
    #                   created_name: :creator,
    #                   updated_name: :updater,
  end
 
  # Example user class
  class MyUser
    include Mongoid::Document
    include Mongoid::Userstamp::User

    # optional class-level config override
    # mongoid_userstamp_user reader: :current_my_user
  end

  # Create instance
  p = Product.create

  # Creator ObjectID   |   Updater ObjectID
  p.created_by_id      |   p.updated_by_id
  # => BSON::ObjectId('4f7c719f476da850ba000039')

  # Creator instance   |   Updater instance
  p.created_by         |   p.updated_by
  # => <User _id: 4f7c719f476da850ba000039>

  # Set creator/updater manually (usually not required)
  p.created_by = MyUser.where(name: 'Will Smith')
  p.updated_by = MyUser.where(name: 'DJ Jazzy Jeff')

Preservation of Manually-set Values

Mongoid::Userstamp will not overwrite manually set values in the creator and updater fields. Specifically:

  • The creator is only set during the creation of new models (before_create callback). Mongoid::Userstamp will not overwrite the creator field if it already contains a value (i.e. was manually set.)
  • The updater is set each time the model is saved (before_create callback), which includes the initial creation. Mongoid::Userstamp will not overwrite the updater field if it been modified since the last save, as per Mongoid's built-in "dirty tracking" feature.

Rails Integration

Popular Rails authentication frameworks such as Devise and Sorcery make a current_user method available in your Controllers. Mongoid::Userstamp will automatically use this to set its user reference in a before_filter on each request. (You can set an alternative method name via the user_reader config.)

Gotcha: If you have special controller actions which change/switch the current user to a new user, you will need to set User.current = new_user after the switch occurs.

Thread Safety

Mongoid::Userstamp stores all-related user variables in Thread.current. If the RequestStore gem is installed, Mongoid::Userstamp will automatically store variables in the RequestStore.store instead. RequestStore is recommended for threaded web servers like Thin or Puma.

Advanced Usage: Scoped Execution

It is possible to execute a block of code within the context of a given user as follows:

User.current = staff
User.current          #=> staff

User.do_as(admin) do
  my_model.save!
  User.current        #=> admin
end

User.current          #=> staff

Advanced Usage: Multiple User Classes

Most Rails apps use a single user model. However, Mongoid::Userstamp supports using multiple user models at once, and will track a separate current_user for each class.

Please note that each model may subscribe to only one user type for its userstamps, set via the :user_model option.

  class Admin
    include Mongoid::Document
    include Mongoid::Userstamp::User

    mongoid_userstamp_user reader: :current_admin
  end

  class Customer
    include Mongoid::Document
    include Mongoid::Userstamp::User

    mongoid_userstamp_user reader: :current_customer
  end

  class Album
    include Mongoid::Document
    include Mongoid::Userstamp

    mongoid_userstamp user_model: 'Customer'
  end

  class Label
    include Mongoid::Document
    include Mongoid::Userstamp

    mongoid_userstamp user_model: 'Admin'
  end

  # Set current user for each type
  Admin.current = Admin.where(name: 'Biz Markie')
  Customer.current = Customer.where(name: 'Sir Mix-A-Lot')

  # In your Controller action
  album = Album.new('Baby Got Back Single')
  album.save!
  album.created_by.name   #=> 'Sir Mix-A-Lot'

  label = Label.new('Cold Chillin Records')
  label.save!
  label.created_by.name   #=> 'Biz Markie'

Contributing

Fork -> Patch -> Spec -> Push -> Pull Request

Please use Ruby 1.9.3 hash syntax, as Mongoid 3 requires Ruby >= 1.9.3

Authors

Copyright

Copyright (c) 2012-2013 Thomas Boerger Programmierung http://www.tbpro.de

Licensed under the MIT License (MIT). Refer to LICENSE for details.

mongoid_userstamp's People

Contributors

bharat311 avatar hiasinho avatar javierav avatar johnnyshields avatar mohakjuneja avatar tacomanator 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

Watchers

 avatar  avatar  avatar  avatar

mongoid_userstamp's Issues

Rails 4 compatibility

I have run all the tests for this gem for Rails 4/Mongoid 4 and they all seem to be passing, does this gem support Rials 4/Mongoid 4? If not what needs to be updated?

Why does user_model have to be defined in every model?

Reading through the docs on the Readme, it specifies that if your user model is something other than 'User' to define it using: mongoid_userstamp user_model: 'Admin'

However, it appears that even if I used a default 'User' model, I must still specify my mongoid_userstamp user_model: in every model that I want user stamped. I'm confused why this is necessary, It seems like duplication, can you help me understand? You even have it defined as so in your specs.

screen shot 2014-10-05 at 10 24 00 am

New Feature: Multiple user model support

@TBPRO I'd like to add support for multiple user models with user stamp. My Rails app has grown in complexity and I'm now using multiple Rails engines with 3 different user classes (internal admins, merchants, and customers)

  1. Mongoid::Userstamp::User must be included into each User model; let's delete the Railtie including routine.
  2. Instead of storing user at Thread['user'], we store at
    Thread["mongoid_userstamp/#{user.class.name.underscore}"]
  3. For now, the config options (user_reader, created_column, created_accessor, updated_column, etc.) will apply globally regardless of user model. This will limit us to one user model per user-stamped model. We can change this in the future if needed.

Here's a worked example:

class MyNamespace::CustomerUser
  include Mongoid::Userstamp::User
end

class AdminUser
  include Mongoid::Userstamp::User  
end

Mongoid::Userstamp.config do |c|
  # config.user_model will now mean the "default user_model", if not specifed otherwise 
  # in the model which has the stamp.
  c.user_model = 'my_namespace/customer_user'  
end

class Product
  include Mongoid::Userstamp

  mongoid_userstamp user_model: 'admin_user'
end

class Purchase
  include Mongoid::Userstamp  

  # mongoid_userstamp macro NOT specified, so user is assumed to be default, 
  # i.e. MyNamespace::CustomerUser
end

CustomerUser.current_user  #=> returns current CustomerUser, stored at
                           # Thread['mongoid_userstamp/my_namespace/customer_user']

AdminUser.current_user     #=> returns current AdminUser, stored at
                           # Thread['mongoid_userstamp/admin_user']

Lastly, an unrelated note: I've switched us from Jeweler to gem-release. The .gemspec is no longer auto-generated (which is a good thing)

User class not used by default?

From the below commit it appears that the User class is no longer used by default.
14d4b18

Please confirm this is intended as the documentation may need to be updated as it reflects the following on the readme.

screen shot 2014-10-05 at 10 12 07 am

Manual changes to :updated_by not persisting.

For some reason in rspec when trying to manually change :updated_by the changes are persisting. This works fine in development environment or even in the test console, only when running rspec it doesn't work. I cannot pin point what is causing the problem. Any ideas?

@track = @syllabus.history_tracks.last
@track.update_attributes(:created_by => @user.id)
@track.created_by.should == @user.id
@track.update_attributes(:updated_by => @user.id)
@track.updated_by.should == @user.id #=> fail

Configuration is broken

In commit a4baa8b you forgot this line:

      def configure(&block)
        @configuration = Mongoid::Userstamp::Config.new(&block)
      end

Ability to do configuration is now broken... d'oh! Can you please re-add this and maybe make some unit tests for configuration so it doesn't break again?

Default User model is not working unless you add mongoid_userstamp_user call

I think this might be related with the other 2 issues you have open in this gem, but I had a long debugging session till I found out that unless you explicitly add the mongoid_userstamp_user call on the model where you want to use the userstamps, the gem won't be applied to the model if you just use:
include Mongoid::Userstamp
as the readme implies in the first example.

I'm using the gem in combination with https://github.com/aq1018/mongoid-history . I'm using the following gemset (short version):

gem 'rails', '4.1.8'
# Mongoid
gem 'mongoid', github: 'mongoid/mongoid'
gem 'mongoid_slug', github: 'digitalplaywright/mongoid-slug'
gem 'mongoid-history'
gem 'mongoid_userstamp'

# Users & Policies
gem 'devise', '~> 3.4.0'
gem 'devise-encryptable', '~> 0.2.0'  
gem 'devise_invitable', github: 'scambra/devise_invitable'
gem 'devise-scrypt'
gem 'pundit'
gem 'enumerize'
......

Using Ruby 2.1.4

My models (reduced version) are as follows:

#The model used for HistoryTracker gem
class HistoryTracker
   include Mongoid::History::Tracker
   include Mongoid::Userstamp

   mongoid_userstamp #Gem won't work unless I add this line explicitly
end

class User
  include Mongoid::Document
  include Mongoid::Userstamp::User
  include Mongoid::Attributes::Dynamic
  include Mongoid::Timestamps
  extend Enumerize

  has_and_belongs_to_many :accounts

  devise :invitable, :encryptable, :database_authenticatable, :registerable, :lockable,
     :recoverable, :confirmable, :rememberable, :trackable, :validatable, :timeoutable

end

class Model1
  include Mongoid::Document
  include Mongoid::Attributes::Dynamic
  include Mongoid::Timestamps
  include Mongoid::History::Trackable

  belongs_to :account

  track_history track_create: true
end

class Account
  include Mongoid::Document
  include Mongoid::Attributes::Dynamic
  include Mongoid::Timestamps
   include Mongoid::History::Trackable
  include Mongoid::Slug

  has_and_belongs_to_many :users

  track_history on: [:filing_frequency, :status] #log account changes

end

I think the issue is with the default call to mongoid_userstamp, which for some reason doesn't happen as expected.

Use standard Mongoid relations to represent users

@tboerger currently Mongoid Userstamp allows user to define field names / accessors for the users like so:

  c.created_column   = :c_by
  c.created_accessor = :created_by

I think it is much cleaner if we just use standard Mongoid belongs_to relations. For example:

  c.created_relation = :created_by

This would yield created_by_id to access the ID, and created_by to access the user model (i.e. just like any other Mongoid relation) and will reduce the amount of code we have.

Among other reasons for this, I'm thinking of making polymorphic relations possible, i.e. multiple possible userstamp classes referenced by one relation, which can be done natively in Mongoid. http://mongoid.org/en/mongoid/docs/relations.html#common

What do you think?

Compatibility with Mongoid 5

Hi there! I'm using mongoid 5. The gem is not compatible with it. Is anyone actively maintaining this gem or should we look for alternatives?

Who wants to take the project?

Since I'm not using any mongodb anymore I would like to give this gem away. If @johnnyshields wants to take it I'm totally fine. Otherwise maybe somebody from the community wants to take the ownership?

Userstamp is not added when userstamp was not explicitly called

I have this test:

RSpec.describe Product do
  it "chech bug" do
    class User
      include Mongoid::Document
      include Mongoid::Userstamp::User
    end

    class Product
      include Mongoid::Document
      include Mongoid::Userstamp
    end

    p = Product.create
    expect(p.created_by).to be eq(nil)
  end
end

This show this error:

  1) Product chech bug
     Failure/Error: p.created_by

     NoMethodError:
       undefined method `created_by' for #<Product _id: 572c8a3f8675c36e39000001, >

The problem that I can see is that this code:

module Mongoid
module Userstamp
  class Railtie < Rails::Railtie
    config.to_prepare do
      Mongoid::Userstamp.model_classes.each do |model_class|
        unless model_class.included_modules.include?(Mongoid::Userstamp::Model)
          model_class.send(:include, Mongoid::Userstamp::Model)
        end
      end
    end

Is executed before Mongoid::Userstamp is included in class:

module Mongoid
  module Userstamp
    extend ActiveSupport::Concern
    included do
      Mongoid::Userstamp.add_model_class(self)
    end
    ...

Then Mongoid::Userstamp.model_classes is equal to []

It is a bug?

No user populated (created/updated_by are nil)

May not be understanding the proper setup, but...

I would like to record the creator in a Comment model. Including gem 'mongoid_userstamp' in Gemfile and modified model:

class Comment
  include Mongoid::Document
  include Mongoid::Timestamps
  include Mongoid::Userstamp
  field :content, :type => String
  validates :content, :presence => true
  embedded_in :post, :inverse_of => :comments 
end

Did not add a config file (assuming defaults used automatically). When I create a comment, the created_by field is nil:

1.9.2-p318 :005 > Post.last.comments.last
 => #<Comment _id: 4fa8403c9326af47bb00000b, _type: nil, created_at: 2012-05-07 21:35:56 UTC, updated_at: 2012-05-07 21:35:56 UTC, updated_by: nil, created_by: nil, content: "aaa">

Using devise for authentication. User model is called User and a current_user method exists. Devise 2.0.4 and Rails 3.2.3.

Shortened fields name

Hello, I have written a small extension to your gem, in order to shorten the created_by/update_by fields in mongodb, and to keep the original method. (like the short module in mongoid).

Sadly, i have an error : undefined method `bson_dump' for #User:0x007fda7a9dae48, when i try to save an object in the database.
I can save the user associated to the object : event.created_by.save! , but not the object itself (event.save! fails with the bson_dump error )
If you can help me on that, i would be very happy.

Here is my code:

module Mongoid
module Userstamp
# Remove the column name, and replaces it by a shortened name, but keeps the old field name as an alias
    module Short
        extend ActiveSupport::Concern
        included do
                _column_created_by = "#{Mongoid::Userstamp.configuration.created_column.to_s}".to_sym
                _column_updated_by = "#{Mongoid::Userstamp.configuration.updated_column.to_s}".to_sym
                fields.delete(_column_created_by)
                fields.delete(_column_updated_by)
                #clean that
                field :c_by, type: Object, as: Mongoid::Userstamp.configuration.created_column
                field :u_by, type: Object, as: Mongoid::Userstamp.configuration.updated_column
        end
    end
end

Thanks you,

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.