Permalink
Browse files

Add ActiveRecord integration and specs, docs!

  • Loading branch information...
1 parent 936dc2a commit a27061203953215c3955929573d7f4248b6b78aa @Sutto committed Jun 9, 2012
Showing with 96 additions and 15 deletions.
  1. +16 −1 README.md
  2. +10 −12 Rakefile
  3. +1 −1 lib/rocket_pants/active_record.rb
  4. +55 −0 spec/integration/active_record_spec.rb
  5. +14 −1 spec/support/models.rb
View
@@ -321,7 +321,7 @@ The final type, similar to collection objects but it includes details about the
One of the built in features of RocketPants is the ability to handle rescuing / controlling exceptions and more importantly to handle mapping exceptions to names, messages and error codes.
-This comes in useful when you wish to automatically convert exceptions such as `ActiveRecord::RecordNotFound` to a structured bit of data in the response. Namely, it makes it trivial to generate objects that follow the JSON structure of:
+This comes in useful when you wish to automatically convert exceptions such as `ActiveRecord::RecordNotFound` (Note: This case is handled already) to a structured bit of data in the response. Namely, it makes it trivial to generate objects that follow the JSON structure of:
```json
{
@@ -347,6 +347,8 @@ Out of the box, the following exceptions come pre-registered and setup:
- `:invalid_version` - An invalid API version was specified.
- `:not_implemented` - The specified endpoint is not yet implemented.
- `:not_found` - The given resource could not be found.
+- `:invalid_resource` - The given resource was invalid.
+- `:bad_request` - The given request was not as expected.
Note that error also excepts a Hash of contextual options, many which will be passed through to the Rails I18N subsystem. E.g:
@@ -372,6 +374,19 @@ Will return something similar to:
}
```
+### Build in ActiveRecord Errors
+
+Out of the box, Rocket Pants will automatically map the following to built in errors and rescue them
+as appropriate.
+
+- `ActiveRecord::RecordNotFound` into `RocketPants::NotFound`
+- `ActiveRecord::RecordNotSaved` into `RocketPants::InvalidResource (with no validation messages).`
+- `ActiveRecord::RecordInvalid` into `RocketPants::InvalidResource (with messages in the "messages" key of the JSON).`
+
+For Invalid Resource messages, the response looks roughly akin to:
+
+
+
## Implementing Efficient Validation
One of the core design principles built into RocketPants is simple support for "Efficient Validation" as described in the [Rack::Cache FAQ](http://rtomayko.github.com/rack-cache/faq) - Namely, it adds simple support for object-level caching using etags with fast verification thanks to the `RocketPants::CacheMiddleware` cache middleware.
View
@@ -4,25 +4,23 @@ require 'rspec/core'
require 'rspec/core/rake_task'
require 'bundler/gem_tasks'
-task :default => :spec
-
desc "Run all specs in spec directory (excluding plugin specs)"
RSpec::Core::RakeTask.new(:spec)
+INTEGRATION_LIBS = %w(will_paginate kaminari active_record)
+
namespace :spec do
namespace :integration do
- desc "Run the will_paginate integrate specs"
- RSpec::Core::RakeTask.new(:will_paginate) do |t|
- t.rspec_opts = "--tag integration"
- t.pattern = "./spec/integration/will_paginate_spec.rb"
- end
+ INTEGRATION_LIBS.each do |lib|
+
+ desc "Run the #{lib} integrate specs"
+ RSpec::Core::RakeTask.new(lib.to_sym) do |t|
+ t.rspec_opts = "--tag integration"
+ t.pattern = "./spec/integration/#{lib}_spec.rb"
+ end
- desc "Run the will_paginate integrate specs"
- RSpec::Core::RakeTask.new(:kaminari) do |t|
- t.rspec_opts = "--tag integration"
- t.pattern = "./spec/integration/kaminari_spec.rb"
end
end
@@ -35,4 +33,4 @@ namespace :spec do
end
end
-task :default => ["spec:integration:will_paginate", "spec:integration:kaminari"]
+task :default => ([:spec] + INTEGRATION_LIBS.map { |l| "spec:integration:#{l}" })
@@ -5,7 +5,7 @@ module ActiveRecordIntegration
included do
map_error! ActiveRecord::RecordNotFound, RocketPants::NotFound
- map_error! ActiveRecord::RecordNotSaved, RocketPants::InvalidResource
+ map_error!(ActiveRecord::RecordNotSaved) { RocketPants::InvalidResource.new nil }
map_error! ActiveRecord::RecordInvalid do |exception|
RocketPants::InvalidResource.new exception.record.errors
end
@@ -0,0 +1,55 @@
+require 'spec_helper'
+
+require 'active_record'
+require 'rocket_pants/active_record'
+
+describe RocketPants::Base, 'active record integration', :integration => true, :target => 'active_record' do
+ include ControllerHelpers
+
+ let(:table_manager) { ReversibleData.manager_for(:fish) }
+
+ before :each do
+ table_manager.up!
+ end
+
+ after(:each) { table_manager.down! }
+
+ let(:controller_class) do
+ Class.new(TestController)
+ end
+
+ def action_is(&blk)
+ controller_class.send :define_method, :test_data, &blk
+ end
+
+ it 'should automatically map ActiveRecord::RecordNotFound' do
+ action_is { Fish.find(1000) }
+ get :test_data
+ content['error'].should == 'not_found'
+ end
+
+ it 'should automatically map ActiveRecord::RecordNotSaved' do
+ action_is { raise ActiveRecord::RecordNotSaved }
+ @action_body = lambda { Fish.new.save }
+ get :test_data
+ content['error'].should == 'invalid_resource'
+ content['messages'].should == nil
+ end
+
+ it 'should automatically map ActiveRecord::RecordInvalid' do
+ action_is { Fish.new.save! }
+ get :test_data
+ content['error'].should == 'invalid_resource'
+ messages = content['messages']
+ messages.should be_present
+ messages.keys.should =~ %w(name child_number latin_name)
+ messages.each_pair do |name, value|
+ value.should be_present
+ value.should be_a Array
+ value.should be_all { |v| v.is_a?(String) }
+ expected = (name == 'name' ? 1 : 2)
+ value.length.should == expected
+ end
+ end
+
+end
@@ -3,4 +3,17 @@
ReversibleData.add(:users) do |t|
t.integer :age
-end
+end
+
+fish = ReversibleData.add(:fish) do |t|
+ t.string :name
+ t.string :latin_name
+ t.integer :child_number
+end
+
+fish.define_model do
+ validates :name, :child_number, :presence => true
+ # Yes, I know it's technically not right.
+ validates :latin_name, :length => {:minimum => 5}, :format => /\A(\w+) (\w+)\Z/
+ validates :child_number, :numericality => true
+end

0 comments on commit a270612

Please sign in to comment.