benhoskings-hammock 0.3.3 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +24 -4
- data/README.rdoc +59 -39
- data/hammock.gemspec +3 -3
- data/lib/hammock.rb +7 -3
- data/lib/hammock/ajaxinate.rb +4 -2
- data/lib/hammock/canned_scopes.rb +7 -7
- data/lib/hammock/monkey_patches/active_record.rb +1 -1
- data/lib/hammock/restful_actions.rb +1 -8
- data/lib/hammock/restful_rendering.rb +9 -0
- data/lib/hammock/restful_support.rb +1 -1
- data/lib/hammock/scope.rb +2 -2
- metadata +3 -3
data/History.txt
CHANGED
@@ -1,22 +1,42 @@
|
|
1
|
+
== 0.3.5 2009-06-03
|
2
|
+
Converted README back to rdoc, for rubyforge rake tasks.
|
3
|
+
|
4
|
+
|
5
|
+
== 0.3.4 2009-06-03
|
6
|
+
Converted lambda and proc to L.
|
7
|
+
Include exception message on error in Hammock.load_models.
|
8
|
+
Fixed lambda -> L alias, by adding initialize_for_load on hammock init.
|
9
|
+
Added Hammock::Mutex, containing AR::Base#mutex, to run a closure within a column-based mutex.
|
10
|
+
Added Hammock::Aliases, initially with lambda aliased as L.
|
11
|
+
Removed model-loading logging.
|
12
|
+
README formatting updates, converted to Markdown.
|
13
|
+
Updated README to match current code state.
|
14
|
+
Updated the bit about the screencast in the README.
|
15
|
+
|
16
|
+
|
1
17
|
== 0.3.3 2009-05-28
|
2
18
|
On suggest, :limit => 0 means no limit now, as it should.
|
3
19
|
|
4
20
|
|
5
21
|
== 0.3.2 2009-05-28
|
6
|
-
Accidentally pushed 0.3.1 in an unknown state - bumped to 0.3.2 to be safe.
|
7
|
-
|
8
|
-
|
9
|
-
== 0.3.1 2009-05-28
|
10
22
|
Added Hammock.load_models, along with call in draw_with_hammock_route_map_init.
|
11
23
|
Refactored Hammock.included out into load_hammock_components and related methods, and made them all private.
|
12
24
|
Only extract record_attributes from records - not resources too.
|
13
25
|
Fixed http status entry in log_hit.
|
14
26
|
|
15
27
|
|
28
|
+
== 0.3.1 2009-05-26
|
29
|
+
Check for a specific scope for the current action before checking for a default-named scope.
|
30
|
+
Commented ambition query logging.
|
31
|
+
Moved index rendering to restful_rendering.
|
32
|
+
Wrap pending -> success notification within obj null test.
|
33
|
+
|
34
|
+
|
16
35
|
== 0.3.0 2009-05-25
|
17
36
|
Updated ajax_link, ajaxinate and related methods to accept explicit args instead of a splatted list - this makes it a lot easier to handle different amounts of entities.
|
18
37
|
Only do obj replacement in jquery_xhr callback if it's set.
|
19
38
|
|
39
|
+
|
20
40
|
== 0.2.25 2009-05-25
|
21
41
|
Added String#clean_email[!].
|
22
42
|
Moved set_new_or_deleted_before_save callback from controller to model.
|
data/README.rdoc
CHANGED
@@ -14,22 +14,34 @@ Hammock tackles the hard and soft sides of security at once with a scoping secur
|
|
14
14
|
|
15
15
|
Hammock inspects your routes and resources to generate a routing tree for each resource. Parent resources in a nested route are handled transparently at every point - record retrieval, creation, and linking.
|
16
16
|
|
17
|
-
It makes more sense when you see how it works though
|
17
|
+
It makes more sense when you see how it works though. There's a screencast coming soon.
|
18
18
|
|
19
19
|
|
20
20
|
== REQUIREMENTS:
|
21
21
|
|
22
|
-
benhoskings-ambition
|
23
|
-
benhoskings-ambitious-activerecord
|
22
|
+
benhoskings-ambition
|
23
|
+
benhoskings-ambitious-activerecord
|
24
|
+
|
25
|
+
These gems will install automatically as long as you've added the GitHub gem source:
|
26
|
+
|
27
|
+
gem sources -a http://gems.github.com
|
24
28
|
|
25
29
|
|
26
30
|
== INSTALL:
|
27
31
|
|
28
|
-
sudo gem install
|
32
|
+
sudo gem install hammock
|
33
|
+
|
34
|
+
in config/environment.rb:
|
35
|
+
|
36
|
+
Rails::Initializer.run do |config|
|
37
|
+
config.gem 'hammock'
|
38
|
+
...
|
29
39
|
|
30
|
-
|
31
|
-
|
32
|
-
|
40
|
+
in app/controllers/application_controller.rb:
|
41
|
+
|
42
|
+
class ApplicationController
|
43
|
+
include Hammock::RestfulActions
|
44
|
+
...
|
33
45
|
|
34
46
|
|
35
47
|
== LICENSE:
|
@@ -41,59 +53,67 @@ Hammock is licensed under the BSD license, which can be found in full in the LIC
|
|
41
53
|
|
42
54
|
At the moment, you can do this with Hammock:
|
43
55
|
|
44
|
-
|
45
|
-
|
46
|
-
|
56
|
+
class ApplicationController < ActionController::Base
|
57
|
+
include Hammock::RestfulActions
|
58
|
+
end
|
47
59
|
|
48
|
-
|
49
|
-
|
60
|
+
class BeersController < ApplicationController
|
61
|
+
end
|
50
62
|
|
51
|
-
|
52
|
-
|
63
|
+
class Person < ActiveRecord::Base
|
64
|
+
end
|
53
65
|
|
54
|
-
|
55
|
-
|
56
|
-
|
66
|
+
class Beer < ActiveRecord::Base
|
67
|
+
belongs_to :creator, :class_name => 'Person'
|
68
|
+
belongs_to :recipient, :class_name => 'Person'
|
57
69
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
70
|
+
def self.read_scope_for account
|
71
|
+
L{|beer| beer.creator_id == account.id || beer.recipient_id == account.id }
|
72
|
+
end
|
73
|
+
export_scope :read
|
74
|
+
|
75
|
+
# TODO - Duplication, yuck. There's a proper DSL in the pipes.
|
76
|
+
def self.index_scope_for account
|
77
|
+
L{|beer| beer.creator_id == account.id || beer.recipient_id == account.id }
|
78
|
+
end
|
79
|
+
export_scope :index
|
80
|
+
|
81
|
+
creator_scope_for :write
|
66
82
|
end
|
67
|
-
export_scope :write
|
68
|
-
end
|
69
83
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
84
|
+
<% @beers.each do |beer| %>
|
85
|
+
From <%= beer.creator.name %> to <%= beer.recipient.name %>, <%= beer.reason %>, rated <%= beer.rating %>
|
86
|
+
<%= hamlink_to :edit, beer %>
|
87
|
+
<% end %>
|
74
88
|
|
75
|
-
The scope methods above require just one thing -- a context-free
|
89
|
+
The scope methods above require just one thing -- a context-free lambda that takes an ActiveRecord record as its argument, and returns true iff that record is within the scope for the specified account. Hammock uses the method (e.g. Beer.read_scope_for) to define resource and record scopes for the model:
|
76
90
|
|
77
|
-
|
78
|
-
|
91
|
+
Beer.readable_by(account): the set of Beer records whose existence can be known by account
|
92
|
+
Beer#readable_by?(account): returns true if the existence of this Beer instance can be known by account
|
79
93
|
|
80
94
|
You define the logic for read, index and write scopes in Beer.[read,index,write]_scope_for, and the rest just works.
|
81
95
|
|
82
96
|
These scope definitions are exploited extensively, to provide index selection, scoping for record selection, and post-selection object checks.
|
83
97
|
|
84
|
-
- They provide the conditions that should be applied to retrieve the index of each resource.
|
98
|
+
- They provide the conditions that should be applied to retrieve the index of each resource.
|
85
99
|
|
86
|
-
|
100
|
+
The scope is used transperently by Hammock on /beers -> BeersController#index, and is available for use through Beer.indexable_by(account).
|
87
101
|
|
88
|
-
|
102
|
+
- They provide a scope within which records are searched for on single-record actions.
|
103
|
+
|
104
|
+
For example, given the request /beers/5 -> BeersController#show{:id => 5}, Rails would generate the following SQL:
|
105
|
+
|
106
|
+
SELECT * FROM "beers" WHERE (beers."id" = 5) LIMIT 1
|
89
107
|
|
90
108
|
Hammock uses the conditions specified in Beer.read_scope_for to generate (assuming an account_id of 3):
|
91
109
|
|
92
|
-
|
110
|
+
SELECT * FROM "beers" WHERE ((beers.creator_id = 3 OR beers.recipient_id = 3) AND beers."id" = 5) LIMIT 1
|
93
111
|
|
94
112
|
Hammock uses Beer.read_scope_for on #show, and write_scope_for on #edit, #update and #destroy. These scopes can be accessed as above through Beer.readable_by(account) and Beer.writeable_by(account). This eliminates authorization checks from the action, because if the ID of a Beer is provided that the user doesn't have access to it will fall outside the scope and will not be found in the DB at all.
|
95
113
|
|
96
|
-
- They are used to discover credentials for already-queried ActiveRecord objects, without touching the database again.
|
114
|
+
- They are used to discover credentials for already-queried ActiveRecord objects, without touching the database again.
|
115
|
+
|
116
|
+
Just as Beer.readable_by(account) returns the set of Beer records whose existence can be known by account, @beer.readable_by?(account) returns true iff @beer's existence can be known by account. This is employed by hamlink_to.
|
97
117
|
|
98
118
|
These three uses of the scope, plus another as-yet unimplemented bit, provide the entire security model of the application.
|
99
119
|
|
data/hammock.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{hammock}
|
5
|
-
s.version = "0.3.
|
5
|
+
s.version = "0.3.5"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Ben Hoskings"]
|
9
|
-
s.date = %q{2009-
|
9
|
+
s.date = %q{2009-06-03}
|
10
10
|
s.description = %q{Hammock is a Rails plugin that eliminates redundant code in a very RESTful manner. It does this in lots in lots of different places, but in one manner: it encourages specification in place of implementation.
|
11
11
|
|
12
12
|
|
@@ -16,7 +16,7 @@ Hammock tackles the hard and soft sides of security at once with a scoping secur
|
|
16
16
|
|
17
17
|
Hammock inspects your routes and resources to generate a routing tree for each resource. Parent resources in a nested route are handled transparently at every point - record retrieval, creation, and linking.
|
18
18
|
|
19
|
-
It makes more sense when you see how it works though
|
19
|
+
It makes more sense when you see how it works though. There's a screencast coming soon.}
|
20
20
|
s.email = ["ben@hoskings.net"]
|
21
21
|
s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.rdoc", "misc/scaffold.txt"]
|
22
22
|
s.files = ["History.txt", "LICENSE", "Manifest.txt", "README.rdoc", "Rakefile", "hammock.gemspec", "lib/hammock.rb", "lib/hammock/ajaxinate.rb", "lib/hammock/callback.rb", "lib/hammock/callbacks.rb", "lib/hammock/canned_scopes.rb", "lib/hammock/constants.rb", "lib/hammock/controller_attributes.rb", "lib/hammock/export_scope.rb", "lib/hammock/hamlink_to.rb", "lib/hammock/javascript_buffer.rb", "lib/hammock/logging.rb", "lib/hammock/model_attributes.rb", "lib/hammock/model_logging.rb", "lib/hammock/monkey_patches/action_pack.rb", "lib/hammock/monkey_patches/active_record.rb", "lib/hammock/monkey_patches/array.rb", "lib/hammock/monkey_patches/hash.rb", "lib/hammock/monkey_patches/logger.rb", "lib/hammock/monkey_patches/module.rb", "lib/hammock/monkey_patches/numeric.rb", "lib/hammock/monkey_patches/object.rb", "lib/hammock/monkey_patches/route_set.rb", "lib/hammock/monkey_patches/string.rb", "lib/hammock/overrides.rb", "lib/hammock/resource_mapping_hooks.rb", "lib/hammock/resource_retrieval.rb", "lib/hammock/restful_actions.rb", "lib/hammock/restful_rendering.rb", "lib/hammock/restful_support.rb", "lib/hammock/route_drawing_hooks.rb", "lib/hammock/route_for.rb", "lib/hammock/route_node.rb", "lib/hammock/route_step.rb", "lib/hammock/scope.rb", "lib/hammock/suggest.rb", "lib/hammock/utils.rb", "misc/scaffold.txt", "misc/template.rb", "tasks/hammock_tasks.rake", "test/hammock_test.rb"]
|
data/lib/hammock.rb
CHANGED
@@ -4,10 +4,11 @@ require 'ambition'
|
|
4
4
|
require 'ambition/adapters/active_record'
|
5
5
|
|
6
6
|
module Hammock
|
7
|
-
VERSION = '0.3.
|
7
|
+
VERSION = '0.3.5'
|
8
8
|
|
9
9
|
def self.included base # :nodoc:
|
10
10
|
puts "Loading Hammock from #{loaded_from_gem? ? 'gem' : 'plugin'}"
|
11
|
+
initialize_for_load
|
11
12
|
load_hammock_components base
|
12
13
|
end
|
13
14
|
|
@@ -23,9 +24,8 @@ module Hammock
|
|
23
24
|
klass = File.basename(model_file, '.rb').classify
|
24
25
|
begin
|
25
26
|
Object.const_get klass
|
26
|
-
puts "Loaded #{klass} from #{model_file}."
|
27
27
|
rescue
|
28
|
-
puts "Couldn't load #{klass} from #{model_file}."
|
28
|
+
puts "Couldn't load #{klass} from #{model_file}: #{$!}."
|
29
29
|
end
|
30
30
|
}
|
31
31
|
end
|
@@ -33,6 +33,10 @@ module Hammock
|
|
33
33
|
|
34
34
|
private
|
35
35
|
|
36
|
+
def self.initialize_for_load
|
37
|
+
Hammock::Aliases.alias_lambda
|
38
|
+
end
|
39
|
+
|
36
40
|
def self.load_hammock_components base
|
37
41
|
require_hammock_components
|
38
42
|
mixin_hammock_components base
|
data/lib/hammock/ajaxinate.rb
CHANGED
@@ -79,8 +79,10 @@ module Hammock
|
|
79
79
|
),
|
80
80
|
function(response, textStatus) {
|
81
81
|
#{response_action}
|
82
|
-
if (obj)
|
83
|
-
|
82
|
+
if (obj) {
|
83
|
+
obj.children('.spinner').hide();
|
84
|
+
#{"if ('success' == textStatus) obj.children('.success').show().fadeOut(4000);" if opts[:spinner] != :pending}
|
85
|
+
}
|
84
86
|
eval("#{clean_snippet opts[:after]}");
|
85
87
|
}
|
86
88
|
);
|
@@ -89,24 +89,24 @@ module Hammock
|
|
89
89
|
|
90
90
|
def public_scope account = nil
|
91
91
|
if sqlite?
|
92
|
-
|
92
|
+
L{|record| 1 }
|
93
93
|
else
|
94
|
-
|
94
|
+
L{|record| true }
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
98
98
|
def authed_scope account
|
99
99
|
has_account = !account.nil?
|
100
|
-
|
100
|
+
L{|record| has_account }
|
101
101
|
end
|
102
102
|
|
103
103
|
def creator_scope account
|
104
|
-
|
104
|
+
L{|record| record.creator_id == account.id }
|
105
105
|
end
|
106
106
|
|
107
107
|
def partitioned_scope account
|
108
108
|
if account.is_a? self
|
109
|
-
|
109
|
+
L{|record| record.id == account.id }
|
110
110
|
else
|
111
111
|
empty_scope
|
112
112
|
end
|
@@ -114,9 +114,9 @@ module Hammock
|
|
114
114
|
|
115
115
|
def empty_scope account = nil
|
116
116
|
if sqlite?
|
117
|
-
|
117
|
+
L{|record| 0 } # TODO check what this should be
|
118
118
|
else
|
119
|
-
|
119
|
+
L{|record| false }
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
@@ -6,14 +6,7 @@ module Hammock
|
|
6
6
|
#
|
7
7
|
# Lists the current resource's records that are visible within the current index scope, defined by +index_scope+ and +index_scope_for+ on the current model.
|
8
8
|
def index
|
9
|
-
if tasks_for_index
|
10
|
-
respond_to do |format|
|
11
|
-
format.html
|
12
|
-
format.xml { render :xml => @records.kick }
|
13
|
-
format.json { render :json => @records.kick }
|
14
|
-
format.yaml { render :text => @records.kick.to_yaml }
|
15
|
-
end
|
16
|
-
end
|
9
|
+
render_for_index if tasks_for_index
|
17
10
|
end
|
18
11
|
|
19
12
|
# The +new+ action. (GET, safe, idempotent)
|
@@ -28,6 +28,15 @@ module Hammock
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
+
def render_for_index
|
32
|
+
respond_to do |format|
|
33
|
+
format.html
|
34
|
+
format.xml { render :xml => @records.kick }
|
35
|
+
format.json { render :json => @records.kick }
|
36
|
+
format.yaml { render :text => @records.kick.to_yaml }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
31
40
|
def render_for_safe_actions result = true, opts = {}
|
32
41
|
if request.xhr?
|
33
42
|
if params[:attribute]
|
@@ -77,7 +77,7 @@ module Hammock
|
|
77
77
|
elsif record_or_records.is_a? ActiveRecord::Base
|
78
78
|
instance_variable_set "@#{mdl_name}", (@record = record_or_records)
|
79
79
|
elsif record_or_records.is_a? Ambition::Context
|
80
|
-
log "Unkicked query: #{record_or_records.to_hash.inspect}"
|
80
|
+
# log "Unkicked query: #{record_or_records.to_hash.inspect}"
|
81
81
|
instance_variable_set "@#{mdl_name.pluralize}", (@records = record_or_records)
|
82
82
|
elsif record_or_records.is_a? Array
|
83
83
|
instance_variable_set "@#{mdl_name.pluralize}", (@records = record_or_records)
|
data/lib/hammock/scope.rb
CHANGED
@@ -116,10 +116,10 @@ module Hammock
|
|
116
116
|
end
|
117
117
|
|
118
118
|
def account_verb_scope?
|
119
|
-
mdl.has_account_scope? scope_name_for_action
|
119
|
+
mdl.has_account_scope?(action_name) || mdl.has_account_scope?(scope_name_for_action)
|
120
120
|
end
|
121
121
|
def public_verb_scope?
|
122
|
-
mdl.has_public_scope? scope_name_for_action
|
122
|
+
mdl.has_public_scope?(action_name) || mdl.has_public_scope?(scope_name_for_action)
|
123
123
|
end
|
124
124
|
|
125
125
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: benhoskings-hammock
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Hoskings
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-06-03 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -52,7 +52,7 @@ dependencies:
|
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: 1.8.0
|
54
54
|
version:
|
55
|
-
description: "Hammock is a Rails plugin that eliminates redundant code in a very RESTful manner. It does this in lots in lots of different places, but in one manner: it encourages specification in place of implementation. Hammock enforces RESTful resource access by abstracting actions away from the controller in favour of a clean, model-like callback system. Hammock tackles the hard and soft sides of security at once with a scoping security system on your models. Specify who can verb what resources under what conditions once, and everything else - the actual security, link generation, index filtering - just happens. Hammock inspects your routes and resources to generate a routing tree for each resource. Parent resources in a nested route are handled transparently at every point - record retrieval, creation, and linking. It makes more sense when you see how it works though
|
55
|
+
description: "Hammock is a Rails plugin that eliminates redundant code in a very RESTful manner. It does this in lots in lots of different places, but in one manner: it encourages specification in place of implementation. Hammock enforces RESTful resource access by abstracting actions away from the controller in favour of a clean, model-like callback system. Hammock tackles the hard and soft sides of security at once with a scoping security system on your models. Specify who can verb what resources under what conditions once, and everything else - the actual security, link generation, index filtering - just happens. Hammock inspects your routes and resources to generate a routing tree for each resource. Parent resources in a nested route are handled transparently at every point - record retrieval, creation, and linking. It makes more sense when you see how it works though. There's a screencast coming soon."
|
56
56
|
email:
|
57
57
|
- ben@hoskings.net
|
58
58
|
executables: []
|