hound 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dbbb90e55615005651013a007a49add63ba47920
4
- data.tar.gz: 6b477231c8ac9307b8e6b6a8a6aa0a3a0a66044c
3
+ metadata.gz: 17ce6502740de85ef5dcb728028205418d81af11
4
+ data.tar.gz: 142481253159ae0d10042948213a469f4cc763e6
5
5
  SHA512:
6
- metadata.gz: cc5d8f271aabddb48373cfcee959c9e3d0848c1f018719cb9dc3bc96d250b56d701e15ef939f7b06df9bf0a6f87fe3d695ea30e14231d66356e674b6568dd04c
7
- data.tar.gz: 635412aa1c93cacef0b7ba2d687682b2827619da9a00b0e4f27f21b19c18166287a0ffa12b64b59ba0cb97c5c5aedafec695b65922def8860058b9f514caee97
6
+ metadata.gz: a4d5e99ef5d62b26d0a88cb67a773438e1fe311ab11f49a06b3b50a5b427e1fdb2e2652268f58b34671467f5cbd3f453a1a91666564fc919fdf374861a1791d9
7
+ data.tar.gz: 05c6ce2f13cccce70557a3cc855bb57e3f5a3c7ea5894e4db90d83dc0d4c0887b420ed4cebd25601bdb6a3feba78ea71588a4873355d69d2c20da1b760becafd
@@ -1,9 +1,17 @@
1
1
  language: ruby
2
- before_script: 'cd test/dummy && bundle exec rake db:migrate'
2
+
3
3
  rvm:
4
- - 1.9.2
5
4
  - 1.9.3
6
- notifications:
7
- email:
8
- on_success: change
9
- on_failure: always
5
+
6
+ env:
7
+ - DB=sqlite
8
+ - DB=mysql
9
+ - DB=postgresql
10
+
11
+ before_script:
12
+ - rake app:db:create
13
+ - rake app:db:migrate
14
+ - rake app:db:test:prepare
15
+
16
+ after_script:
17
+ - rake app:db:rollback
@@ -0,0 +1,21 @@
1
+ ## v0.3.0 - March 14, 2013
2
+
3
+ * Implement `hound_user` and polymorphic user association (#3).
4
+ * Hook into user model and add `has_many :actions`.
5
+ * Ensure Hound does not raise an exception if a user class does not exist.
6
+
7
+ ## v0.2.0 - March 10, 2013
8
+
9
+ * Support tracking changes made to hounded models.
10
+
11
+ ## v0.1.0 - March 8, 2013
12
+
13
+ * Support limiting actions.
14
+ * Added `hound_action` helper to controllers.
15
+ * Support for a custom User class.
16
+ * Support travis CI.
17
+ * Lower Rails dependency version.
18
+
19
+ ## v0.0.1 - March 7, 2013
20
+
21
+ * Initial Release of Hound. Support tracking actions made to models.
data/Gemfile CHANGED
@@ -15,3 +15,8 @@ gem "jquery-rails"
15
15
 
16
16
  # To use debugger
17
17
  # gem 'debugger'
18
+ group :development, :test do
19
+ gem 'sqlite3'
20
+ gem 'mysql2'
21
+ gem 'pg'
22
+ end
data/README.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Hound
2
2
 
3
+ [![Build Status](https://travis-ci.org/injekt/hound.png?branch=master)](https://travis-ci.org/injekt/hound)
4
+
5
+ Hound is designed to track activity on models. It'll track your usual
6
+ `create` `update` and `destroy` actions as well as custom activity.
7
+
8
+ At [Allur](https://www.allur.com) or more specifically the
9
+ [Spark CRM](http://allurspark.com) we've built, we use Hound for implementing
10
+ activity tabs on our popular models. These activity tabs display
11
+ the last x amount of actions taken out upon these models. We have a lot
12
+ of custom associations so we can't simply track the `update` to models.
13
+ With Hound we can build custom actions on the fly.
14
+
15
+ If you need something similar, Hound could be a good fit.
16
+
3
17
  ## Installation
4
18
 
5
19
  Add Hound to your `Gemfile` and run `bundle install`:
@@ -58,13 +72,22 @@ end
58
72
  ```
59
73
 
60
74
  For this to work successfully you must tell Hound about your user class
61
- (note that this value defaults to 'User' already).
75
+ using the `hound_user` method. The `user` association on the `Hound::Action`
76
+ class is polymorphic, so you can use `hound_user` in more than one class.
62
77
 
63
78
  ```ruby
64
- Hound.config.user_class = 'CustomUser'
65
- Hound.config.user_class = AdminUser # String or constant
79
+ class User
80
+ hound_user
81
+ end
82
+
83
+ class Admin
84
+ hound_user
85
+ end
66
86
  ```
67
87
 
88
+ Now `hound_user` can return either an instance of `User` or an instance of
89
+ `Admin`.
90
+
68
91
  You can also disable Hound on a model instance basis:
69
92
 
70
93
  ```ruby
@@ -75,7 +98,7 @@ article.save
75
98
  article.actions #=> []
76
99
  ```
77
100
 
78
- ## Changes
101
+ ## Tracking Changes
79
102
 
80
103
  Hound also tracks the changes made when updating your hounded records. You
81
104
  can access the change updates through the `changeset` attribute:
@@ -87,6 +110,55 @@ article.actions.last.changeset
87
110
  #=> {"title" => ["Hello, World!", "Salut, World!"]}
88
111
  ```
89
112
 
113
+ ## Displaying model activity
114
+
115
+ Because Hound hooks into your existing user model as well as any models
116
+ you tell it to track, you can display activity from either side. In fact,
117
+ your user object doesn't even need to belong to the object you're tracking.
118
+
119
+ ```ruby
120
+ current_user.name #=> "Lee"
121
+ article = Article.create! title: 'Hello, World!'
122
+
123
+ article.actions.each do |action|
124
+ puts "#{action.user.name} #{action + 'ed'} the " \
125
+ "#{action.actionable_type} #{action.actionable.title}"
126
+ end
127
+
128
+ current_user.actions.each do |action|
129
+ puts "#{action.user.name} #{action + 'ed'} the " \
130
+ "#{action.actionable_type} #{action.actionable.title}"
131
+ end
132
+ ```
133
+
134
+ Both of the above snippets will print the same thing:
135
+
136
+ ```
137
+ Lee created the Article Hello, World!
138
+ ```
139
+
140
+ ## Console
141
+
142
+ Hound implements a storage facility on the current thread for storing
143
+ the id of the current user. This is how we make it available to the model
144
+ data without sending it via the controller itself. This means when
145
+ creating records via the console, there will be no `current_user` available.
146
+
147
+ ```ruby
148
+ >> Article.create! title: 'Foo'
149
+ >> _.actions.last.user
150
+ => nil
151
+ ```
152
+
153
+ You can solve this by setting `Hound.store[:current_user_id]`:
154
+
155
+ ```ruby
156
+ >> Hound.store[:current_user_id] = User.create!(name: 'Lee').id
157
+ >> Article.create! title: 'Foo'
158
+ >> _.actions.last.user.name
159
+ => "Lee"
160
+ ```
161
+
90
162
  ## Cleaning Up
91
163
 
92
164
  With all this action creating we're doing, your database is bound to start
@@ -114,6 +186,20 @@ will not only create a new action, it will check and destroy any actions
114
186
  outside of this limit. This requires an extra call to the database, so if
115
187
  that could be an issue, using a rake task might be a better idea.
116
188
 
189
+ ## But we already have Paper Trail?
190
+
191
+ Yes, and Paper Trail is awesome. Hound is not designed to replace it. They
192
+ do different things. Hound is designed to track activity (in the form of
193
+ actions) on a model. Paper Trail does the same thing but it stores snapshots
194
+ of your model at certain times (when they change). Hound is not just for
195
+ tracking changes to your model, but you can attach custom activity to it, too.
196
+
197
+ * Do I want custom actions and activity attached to my models? Use Hound.
198
+ * Do I need to restore my model to an earlier time? Use Paper Trail.
199
+
200
+ At [Allur](https://www.allur.com) we use them both for different things,
201
+ and they work great.
202
+
117
203
  ## TODO
118
204
 
119
205
  * Implement action grouping
data/Rakefile CHANGED
@@ -21,6 +21,8 @@ RDoc::Task.new(:rdoc) do |rdoc|
21
21
  end
22
22
 
23
23
  Bundler::GemHelper.install_tasks
24
+ APP_RAKEFILE = File.expand_path('../test/dummy/Rakefile', __FILE__)
25
+ load 'rails/tasks/engine.rake'
24
26
 
25
27
  require 'rake/testtask'
26
28
 
@@ -5,14 +5,17 @@ class CreateHoundActions < ActiveRecord::Migration
5
5
  t.string :actionable_type, null: false
6
6
  t.integer :actionable_id, null: false
7
7
  t.integer :user_id
8
+ t.string :user_type
8
9
  t.datetime :created_at
9
10
  t.text :changeset
10
11
  end
11
12
  add_index :hound_actions, [:actionable_type, :actionable_id]
13
+ add_index :hound_actions, [:user_type, :user_id]
12
14
  end
13
15
 
14
16
  def self.down
15
17
  remove_index :hound_actions, [:actionable_type, :actionable_id]
18
+ remove_index :hound_actions, [:user_type, :user_id]
16
19
  drop_table :hound_actions
17
20
  end
18
21
  end
@@ -1,9 +1,13 @@
1
1
  module Hound
2
2
  class Action < ActiveRecord::Base
3
3
  self.table_name = 'hound_actions'
4
- attr_accessible :action, :actionable_id, :actionable_type, :user_id, :changeset
4
+
5
+ attr_accessible :action, :actionable_id, :actionable_type,
6
+ :user_id, :user_type, :changeset
7
+
5
8
  belongs_to :actionable, polymorphic: true
6
- belongs_to :user, class_name: Hound.config.user_class
9
+ belongs_to :user, polymorphic: true
10
+
7
11
  serialize :changeset, Hash
8
12
 
9
13
  scope :created, -> { where(action: 'create') }
@@ -7,21 +7,13 @@ module Hound
7
7
  # An Array of actions Hound should track.
8
8
  attr_accessor :actions
9
9
 
10
- # The String used to represent a User class (defaults to 'User').
11
- attr_reader :user_class
12
-
13
10
  # Limit actions on a global basis.
14
11
  attr_accessor :limit
15
12
 
16
13
  def initialize
17
14
  @actions = %w'create update destroy'
18
- @user_class = 'User'
19
15
  @limit = nil
20
16
  end
21
17
 
22
- def user_class=(klassname)
23
- @user_class = klassname.to_s
24
- end
25
-
26
18
  end
27
19
  end
@@ -19,14 +19,20 @@ module Hound
19
19
  hound_user.try(:id)
20
20
  end
21
21
 
22
+ def hound_user_type
23
+ hound_user.class.base_class.name if hound_user
24
+ end
25
+
22
26
  private
23
27
 
24
28
  def hound_action(object, action = params[:action])
25
- object.actions.create(action: action, user_id: hound_user_id)
29
+ object.actions.create(action: action,
30
+ user_id: hound_user_id, user_type: hound_user_type)
26
31
  end
27
32
 
28
33
  def set_hound_user
29
34
  Hound.store[:current_user_id] = hound_user_id
35
+ Hound.store[:current_user_type] = hound_user_type
30
36
  end
31
37
 
32
38
  end
@@ -9,13 +9,15 @@ module Hound
9
9
 
10
10
  # Tell Hound to track this models actions.
11
11
  #
12
- # options - a Hash of configuration options.
12
+ # options - a Hash of configuration options (default: {}).
13
+ # :limit - An Integer limit to restrict the maximum actions
14
+ # stored (optional, default: nil (no limit)).
15
+ # :actions - An Array of actions to track.
16
+ # (default: [:create, :update, :destroy])
13
17
  def hound(options = {})
14
18
  send :include, InstanceMethods
15
19
 
16
- has_many :actions,
17
- as: 'actionable',
18
- class_name: 'Hound::Action'
20
+ has_many :actions, as: :actionable, class_name: 'Hound::Action'
19
21
 
20
22
  options[:actions] ||= Hound.config.actions
21
23
  options[:actions] = Array(options[:actions]).map(&:to_s)
@@ -26,9 +28,13 @@ module Hound
26
28
  attr_accessor :hound
27
29
 
28
30
  # Add action hooks
29
- after_create :hound_create if options[:actions].include?('create')
30
- before_update :hound_update if options[:actions].include?('update')
31
- after_destroy :hound_destroy if options[:actions].include?('destroy')
31
+ after_create :hound_create, if: :hound? if options[:actions].include?('create')
32
+ before_update :hound_update, if: :hound? if options[:actions].include?('update')
33
+ after_destroy :hound_destroy, if: :hound? if options[:actions].include?('destroy')
34
+ end
35
+
36
+ def hound_user(options = {})
37
+ has_many :actions, as: :user, class_name: 'Hound::Action'
32
38
  end
33
39
  end
34
40
 
@@ -47,33 +53,36 @@ module Hound
47
53
  private
48
54
 
49
55
  def hound_create
50
- return unless hound?
51
- attributes = default_attributes.merge(action: 'create')
52
- actions.create! attributes
53
- enforce_limit
56
+ create_action(action: 'create')
54
57
  end
55
58
 
56
59
  def hound_update
57
- return unless hound?
58
- attributes = default_attributes.merge(action: 'update')
59
- attributes.merge!(changeset: changes)
60
- actions.create! attributes
61
- enforce_limit
60
+ create_action(action: 'update')
62
61
  end
63
62
 
64
63
  def hound_destroy
65
- return unless hound?
66
- attributes = default_attributes.merge(action: 'destroy')
67
- attributes.merge!(
68
- actionable_id: self.id,
69
- actionable_type: self.class.base_class.name)
70
- Hound::Action.create(attributes)
64
+ create_action({action: 'destroy'}, false)
65
+ end
66
+
67
+ def create_action(attributes, scoped = true)
68
+ attributes = default_attributes.merge(attributes)
69
+ if scoped
70
+ actions.create!(attributes)
71
+ else
72
+ # unscoped actions should still always save the associated data
73
+ Hound.actions.create(attributes.merge({
74
+ actionable_id: self.id,
75
+ actionable_type: self.class.base_class.name
76
+ }))
77
+ end
71
78
  enforce_limit
72
79
  end
73
80
 
74
81
  def default_attributes
75
82
  {
76
- user_id: Hound.store[:current_user_id]
83
+ user_id: Hound.store[:current_user_id],
84
+ user_type: Hound.store[:current_user_type],
85
+ changeset: changes
77
86
  }
78
87
  end
79
88
 
@@ -1,3 +1,3 @@
1
1
  module Hound
2
- VERSION = '0.2.0'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -4,11 +4,4 @@ class TestUserClass; end
4
4
 
5
5
  class ConfigTest < ActiveSupport::TestCase
6
6
 
7
- test 'user_class' do
8
- assert_equal 'User', Hound.config.user_class
9
-
10
- Hound.config.user_class = TestUserClass
11
- assert_equal 'TestUserClass', Hound.config.user_class
12
- end
13
-
14
7
  end
@@ -1,3 +1,4 @@
1
1
  class User < ActiveRecord::Base
2
2
  attr_accessible :name
3
+ hound_user
3
4
  end
@@ -5,13 +5,17 @@ class CreateHoundActions < ActiveRecord::Migration
5
5
  t.string :actionable_type, null: false
6
6
  t.integer :actionable_id, null: false
7
7
  t.integer :user_id
8
+ t.string :user_type
8
9
  t.datetime :created_at
10
+ t.text :changeset
9
11
  end
10
12
  add_index :hound_actions, [:actionable_type, :actionable_id]
13
+ add_index :hound_actions, [:user_type, :user_id]
11
14
  end
12
15
 
13
16
  def self.down
14
17
  remove_index :hound_actions, [:actionable_type, :actionable_id]
18
+ remove_index :hound_actions, [:user_type, :user_id]
15
19
  drop_table :hound_actions
16
20
  end
17
21
  end
@@ -11,7 +11,7 @@
11
11
  #
12
12
  # It's strongly recommended to check this file into your version control system.
13
13
 
14
- ActiveRecord::Schema.define(:version => 20130310103454) do
14
+ ActiveRecord::Schema.define(:version => 20130314120938) do
15
15
 
16
16
  create_table "articles", :force => true do |t|
17
17
  t.string "title"
@@ -25,11 +25,13 @@ ActiveRecord::Schema.define(:version => 20130310103454) do
25
25
  t.string "actionable_type", :null => false
26
26
  t.integer "actionable_id", :null => false
27
27
  t.integer "user_id"
28
+ t.string "user_type"
28
29
  t.datetime "created_at"
29
30
  t.text "changeset"
30
31
  end
31
32
 
32
33
  add_index "hound_actions", ["actionable_type", "actionable_id"], :name => "index_hound_actions_on_actionable_type_and_actionable_id"
34
+ add_index "hound_actions", ["user_type", "user_id"], :name => "index_hound_actions_on_user_type_and_user_id"
33
35
 
34
36
  create_table "posts", :force => true do |t|
35
37
  t.text "text"
@@ -36,4 +36,14 @@ class HoundTest < ActiveSupport::TestCase
36
36
  end
37
37
  assert_equal 3, @post.actions.size
38
38
  end
39
+
40
+ test 'user has many actions' do
41
+ user = User.create! name: 'Lee'
42
+ assert user.respond_to?(:actions)
43
+ article = Article.create! title: 'Hello, World!'
44
+ action = article.actions.last
45
+ action.user = user
46
+ assert action.save
47
+ assert_equal article.actions, user.actions
48
+ end
39
49
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hound
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lee Jarvis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-03-10 00:00:00.000000000 Z
11
+ date: 2013-03-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -47,6 +47,7 @@ extra_rdoc_files: []
47
47
  files:
48
48
  - .gitignore
49
49
  - .travis.yml
50
+ - CHANGELOG.md
50
51
  - Gemfile
51
52
  - LICENSE
52
53
  - README.md
@@ -98,8 +99,7 @@ files:
98
99
  - test/dummy/db/migrate/20130307165752_create_users.rb
99
100
  - test/dummy/db/migrate/20130307165837_create_articles.rb
100
101
  - test/dummy/db/migrate/20130307183451_create_posts.rb
101
- - test/dummy/db/migrate/20130308110847_create_hound_actions.rb
102
- - test/dummy/db/migrate/20130310103454_add_changeset_to_hound_actions.rb
102
+ - test/dummy/db/migrate/20130314120938_create_hound_actions.rb
103
103
  - test/dummy/db/schema.rb
104
104
  - test/dummy/lib/assets/.gitkeep
105
105
  - test/dummy/log/.gitkeep
@@ -139,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
139
  version: '0'
140
140
  requirements: []
141
141
  rubyforge_project:
142
- rubygems_version: 2.0.0
142
+ rubygems_version: 2.0.3
143
143
  signing_key:
144
144
  specification_version: 4
145
145
  summary: Trace changes to your models
@@ -180,8 +180,7 @@ test_files:
180
180
  - test/dummy/db/migrate/20130307165752_create_users.rb
181
181
  - test/dummy/db/migrate/20130307165837_create_articles.rb
182
182
  - test/dummy/db/migrate/20130307183451_create_posts.rb
183
- - test/dummy/db/migrate/20130308110847_create_hound_actions.rb
184
- - test/dummy/db/migrate/20130310103454_add_changeset_to_hound_actions.rb
183
+ - test/dummy/db/migrate/20130314120938_create_hound_actions.rb
185
184
  - test/dummy/db/schema.rb
186
185
  - test/dummy/lib/assets/.gitkeep
187
186
  - test/dummy/log/.gitkeep
@@ -1,5 +0,0 @@
1
- class AddChangesetToHoundActions < ActiveRecord::Migration
2
- def change
3
- add_column :hound_actions, :changeset, :text
4
- end
5
- end