resource_full 0.7.8 → 0.7.9

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,16 +1,14 @@
1
- = ResourceFull 0.7.5
1
+ = ResourceFull
2
2
 
3
- * http://github.com/bguthrie/resource_full/
4
-
5
- == DESCRIPTION
6
-
7
- ResourceFull integrates with ActionController to provide a comprehensive
8
- RESTful resource modeling and querying framework. It provides parameter
3
+ ResourceFull provides a fully-compliant ActiveResource server implementation
4
+ built on ActionController. Additionally, it provides RESTful parameter
9
5
  queryability, paging, sorting, separation of controller concerns, multiple
10
6
  formats (HTML, XML, JSON), CRUD access permissions, and API metadata
11
7
  surrounding the resource itself. It's opinionated but is intended to provide
12
8
  you with as much as possible without limiting your ability to customize its
13
- behavior.
9
+ behavior. Unless overridden, it uses Rails' default to_xml and to_json methods
10
+ to provide object serialization, which ActiveResource expects but many REST
11
+ clients will not.
14
12
 
15
13
  == GOALS
16
14
 
@@ -78,7 +76,7 @@ add +map.api+ to your +routes.rb+ file.
78
76
 
79
77
  (The MIT License)
80
78
 
81
- Copyright (c) 2009 Brian Guthrie
79
+ Copyright (c) 2010 Brian Guthrie
82
80
 
83
81
  Permission is hereby granted, free of charge, to any person obtaining
84
82
  a copy of this software and associated documentation files (the
data/lib/resource_full.rb CHANGED
@@ -22,6 +22,6 @@ require File.dirname(__FILE__) + '/resource_full/version'
22
22
  require File.dirname(__FILE__) + '/resource_full/base'
23
23
 
24
24
  # REST API
25
- require File.dirname(__FILE__) + '/resource_full/models/resourced_route.rb'
25
+ require File.dirname(__FILE__) + '/resource_full/models/resourced_route'
26
26
  require File.dirname(__FILE__) + '/resource_full/controllers/resources_controller'
27
27
  require File.dirname(__FILE__) + '/resource_full/controllers/routes_controller'
@@ -253,15 +253,18 @@ module ResourceFull
253
253
  # Indicates that the resource should be queryable with the given parameters, which will be pulled from
254
254
  # the params hash on an index or count call. Accepts the following options:
255
255
  #
256
+ # * :scope => (scope) : Use a scope. The value of this parameter may be a symbol (named scope), lambda, or hash.
257
+ # Most other parameter options build scopes internally.
256
258
  # * :fuzzy => true : Use a LIKE query instead of =.
257
259
  # * :columns / :column => ... : Override the default column, or provide a list of columns to query for this value.
258
260
  # * :from => :join_name : Indicate that this value should be queried by joining on another model. Should use
259
261
  # a valid relationship from this controller's exposed model (e.g., :account if belongs_to :account is specified.)
260
262
  # * :resource_identifier => true : Try to look up the resource controller for this value and honor its
261
263
  # specified resource identifier. Useful for nesting relationships.
262
- # * :allow_nils => true : Indicates that a nil value for a parameter should be taken to literally indicate
264
+ # * :allow_nil => true : Indicates that a nil value for a parameter should be taken to literally indicate
263
265
  # that null values should be returned. This may be changed in the future to expect the literal string 'null'
264
266
  # or some other reasonable standin.
267
+ # * :default => (value) : Default to this value if the parameter is not physically present in the request.
265
268
  #
266
269
  # Examples:
267
270
  #
@@ -283,6 +286,12 @@ module ResourceFull
283
286
  end
284
287
  end
285
288
 
289
+ def filter_with_scope(scope=nil, &block_scope)
290
+ raise ArgumentError, "must provide a scope name, standard scope definition, or block scope" unless (scope || block_scope)
291
+ # TODO These should not require the use of dummy parameter names.
292
+ queryable_with "__unused__", :default => true, :scope => scope || block_scope
293
+ end
294
+
286
295
  # :nodoc:
287
296
  def clear_queryable_params!
288
297
  @queryable_params = []
@@ -8,10 +8,18 @@ module ResourceFull
8
8
  controller.rescue_from Exception, :with => :handle_generic_exception_with_correct_response_format
9
9
  end
10
10
 
11
+ # Override this method to provide custom error handling for the errors generated by
12
+ # your model object.
13
+ def http_error_code_for(errors)
14
+ if errors.any? { |message| message.include? CONFLICT_MESSAGE }
15
+ :conflict
16
+ else :unprocessable_entity end
17
+ end
18
+
11
19
  private
12
20
 
13
21
  CONFLICT_MESSAGE = if defined?(ActiveRecord::Errors)
14
- if ([Rails::VERSION::MAJOR, Rails::VERSION::MINOR] <=> [2,1]) >= 0 # if the rails version is 2.1 or greater...Í
22
+ if ActiveRecord::VERSION::STRING >= '2.1.0' && defined?(I18n)
15
23
  (I18n.translate 'activerecord.errors.messages')[:taken]
16
24
  else
17
25
  ActiveRecord::Errors.default_error_messages[:taken]
@@ -20,12 +28,6 @@ module ResourceFull
20
28
  "has already been taken"
21
29
  end
22
30
 
23
- def status_for(errors)
24
- if errors.any? { |message| message.include? CONFLICT_MESSAGE }
25
- :conflict
26
- else :unprocessable_entity end
27
- end
28
-
29
31
  def handle_generic_exception_with_correct_response_format(exception)
30
32
  if request.format.xml?
31
33
  if defined?(ExceptionNotifiable) && defined?(ExceptionNotifier) && self.is_a?(ExceptionNotifiable) && !(consider_all_requests_local || local_request?)
@@ -59,12 +59,12 @@ module ResourceFull
59
59
  def create_json
60
60
  self.model_object = transactional_create_model_object
61
61
  if model_object.errors.empty?
62
- render :json => model_object.to_json(create_json_options), :status => :created, :location => send("#{model_name}_url", model_object.id)
62
+ render :json => model_object.to_json(create_json_options), :status => :created, :location => send("#{model_name}_url", model_object.id, :format => :json)
63
63
  else
64
64
  json_data = model_object.attributes
65
65
  json_data[:errors] = {:list => model_object.errors,
66
66
  :full_messages => model_object.errors.full_messages}
67
- render :json => {json_class_name(model_object) => json_data}.to_json, :status => status_for(model_object.errors)
67
+ render :json => {json_class_name(model_object) => json_data}.to_json, :status => http_error_code_for(model_object.errors)
68
68
  end
69
69
  rescue => e
70
70
  handle_generic_error_in_json(e)
@@ -88,7 +88,7 @@ module ResourceFull
88
88
  json_data = model_object.attributes
89
89
  json_data[:errors] = {:list => model_object.errors,
90
90
  :full_messages => model_object.errors.full_messages}
91
- render :json => {json_class_name(model_object) => json_data}.to_json, :status => status_for(model_object.errors)
91
+ render :json => {json_class_name(model_object) => json_data}.to_json, :status => http_error_code_for(model_object.errors)
92
92
  end
93
93
  rescue ActiveRecord::RecordNotFound => e
94
94
  render :json => e.to_json, :status => :not_found
@@ -53,9 +53,9 @@ module ResourceFull
53
53
  def create_xml
54
54
  self.model_object = transactional_create_model_object
55
55
  if model_object.errors.empty?
56
- render :xml => model_object.to_xml({:root => model_name}.merge(create_xml_options)), :status => :created, :location => send("#{model_name}_url", model_object.id)
56
+ render :xml => model_object.to_xml({:root => model_name}.merge(create_xml_options)), :status => :created, :location => send("#{model_name}_url", model_object.id, :format => :xml)
57
57
  else
58
- render :xml => model_object.errors.to_xml, :status => status_for(model_object.errors)
58
+ render :xml => model_object.errors.to_xml, :status => http_error_code_for(model_object.errors)
59
59
  end
60
60
  rescue => e
61
61
  handle_generic_error_in_xml(e)
@@ -76,7 +76,7 @@ module ResourceFull
76
76
  if model_object.errors.empty?
77
77
  render :xml => model_object.to_xml({:root => model_name}.merge(update_xml_options))
78
78
  else
79
- render :xml => model_object.errors.to_xml, :status => status_for(model_object.errors)
79
+ render :xml => model_object.errors.to_xml, :status => http_error_code_for(model_object.errors)
80
80
  end
81
81
  rescue ActiveRecord::RecordNotFound => e
82
82
  render :xml => e.to_xml, :status => :not_found
@@ -101,6 +101,7 @@ module ResourceFull
101
101
 
102
102
  private
103
103
  def handle_generic_error_in_xml(exception)
104
+ logger.error exception
104
105
  render :xml => exception, :status => :internal_server_error
105
106
  end
106
107
  end
@@ -2,7 +2,7 @@ module ResourceFull #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 7
5
- TINY = 8
5
+ TINY = 9
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -459,4 +459,56 @@ describe "ResourceFull::Query", :type => :controller do
459
459
  end
460
460
  end
461
461
 
462
+ describe "filter_with_scope" do
463
+ controller_name "resource_full_mock_users"
464
+
465
+ # def self.filter_with_scope(scope)
466
+ # queryable_with :__unused__, :default => true, :scope => scope
467
+ # end
468
+
469
+ it "should automatically apply the given named scope to the generated query" do
470
+ ResourceFullMockUsersController.filter_with_scope :rich
471
+ ResourceFullMockUser.named_scope :rich, :conditions => [ "income >= 50000" ]
472
+
473
+ bob = ResourceFullMockUser.create! :income => 30000
474
+ alice = ResourceFullMockUser.create! :income => 50000
475
+ snoop_dogg = ResourceFullMockUser.create! :income => 1034831909138
476
+
477
+ get :index
478
+ assigns(:resource_full_mock_users).should_not include(bob)
479
+ assigns(:resource_full_mock_users).should include(alice, snoop_dogg)
480
+ end
481
+
482
+ it "should automatically apply the given hash scope to the generated query" do
483
+ ResourceFullMockUsersController.filter_with_scope :conditions => [ "income >= 50000" ]
484
+
485
+ bob = ResourceFullMockUser.create! :income => 30000
486
+ alice = ResourceFullMockUser.create! :income => 50000
487
+ snoop_dogg = ResourceFullMockUser.create! :income => 1034831909138
488
+
489
+ get :index
490
+ assigns(:resource_full_mock_users).should_not include(bob)
491
+ assigns(:resource_full_mock_users).should include(alice, snoop_dogg)
492
+ end
493
+
494
+ it "should automatically apply the given block as the lambda for a scope" do
495
+ ResourceFullMockUsersController.filter_with_scope do
496
+ { :conditions => [ "birthdate > ?", 2.days.ago ] }
497
+ end
498
+
499
+ bob = ResourceFullMockUser.create! :birthdate => 1.day.ago
500
+ alice = ResourceFullMockUser.create! :birthdate => 3.days.ago
501
+ snoop_dogg = ResourceFullMockUser.create! :birthdate => Date.parse("1971-10-20")
502
+
503
+ get :index
504
+ assigns(:resource_full_mock_users).should include(bob)
505
+ assigns(:resource_full_mock_users).should_not include(alice, snoop_dogg)
506
+ end
507
+
508
+ it "should raise an ArgumentError if neither an argument scope nor a block scope is provided" do
509
+ lambda do
510
+ ResourceFullMockUsersController.filter_with_scope
511
+ end.should raise_error(ArgumentError)
512
+ end
513
+ end
462
514
  end
@@ -158,7 +158,7 @@ describe "ResourceFull::Render::JSON", :type => :controller do
158
158
  it "creates a new model object and places the location of the new object in the Location header" do
159
159
  put :create, :resource_full_mock_user => {}, :format => 'json'
160
160
 
161
- response.headers['Location'].should == resource_full_mock_user_url(ResourceFullMockUser.find(:first))
161
+ response.headers['Location'].should == resource_full_mock_user_url(ResourceFullMockUser.find(:first), :format => :json)
162
162
  end
163
163
 
164
164
  it "renders appropriate errors if a model validation fails" do
@@ -51,7 +51,7 @@ describe "ResourceFull::Render::XML" , :type => :controller do
51
51
  it "creates a new model object and places the location of the new object in the Location header" do
52
52
  put :create, :resource_full_namespaced_mock_record => {}, :format => 'xml'
53
53
 
54
- response.headers['Location'].should == resource_full_namespaced_mock_record_url(ResourceFullSpec::ResourceFullNamespacedMockRecord.find(:first))
54
+ response.headers['Location'].should == resource_full_namespaced_mock_record_url(ResourceFullSpec::ResourceFullNamespacedMockRecord.find(:first), :format => :xml)
55
55
  end
56
56
  end
57
57
 
@@ -118,7 +118,7 @@ describe "ResourceFull::Render::XML" , :type => :controller do
118
118
  it "creates a new model object and places the location of the new object in the Location header" do
119
119
  put :create, :resource_full_namespaced_mock_record => {}, :format => 'xml'
120
120
 
121
- response.headers['Location'].should == resource_full_namespaced_mock_record_url(ResourceFullSpec::ResourceFullNamespacedMockRecord.find(:first))
121
+ response.headers['Location'].should == resource_full_namespaced_mock_record_url(ResourceFullSpec::ResourceFullNamespacedMockRecord.find(:first), :format => :xml)
122
122
  end
123
123
  end
124
124
 
@@ -269,7 +269,7 @@ describe "ResourceFull::Render::XML" , :type => :controller do
269
269
  it "creates a new model object and places the location of the new object in the Location header" do
270
270
  put :create, :resource_full_mock_user => {}, :format => 'xml'
271
271
 
272
- response.headers['Location'].should == resource_full_mock_user_url(ResourceFullMockUser.find(:first))
272
+ response.headers['Location'].should == resource_full_mock_user_url(ResourceFullMockUser.find(:first), :format => :xml)
273
273
  end
274
274
 
275
275
  it "renders appropriate errors if a model validation fails" do
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 7
8
- - 8
9
- version: 0.7.8
8
+ - 9
9
+ version: 0.7.9
10
10
  platform: ruby
11
11
  authors:
12
12
  - Brian Guthrie
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-04-20 00:00:00 +05:30
17
+ date: 2010-05-05 00:00:00 +05:30
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency