Giter Site home page Giter Site logo

activeresource's Introduction

Active Resource

Active Resource (ARes) connects business objects and Representational State Transfer (REST) web services. It implements object-relational mapping for REST web services to provide transparent proxying capabilities between a client (Active Resource) and a RESTful service (which is provided by Simply RESTful routing in ActionController::Resources).

Philosophy

Active Resource attempts to provide a coherent wrapper object-relational mapping for REST web services. It follows the same philosophy as Active Record, in that one of its prime aims is to reduce the amount of code needed to map to these resources. This is made possible by relying on a number of code- and protocol-based conventions that make it easy for Active Resource to infer complex relations and structures. These conventions are outlined in detail in the documentation for ActiveResource::Base.

Overview

Model classes are mapped to remote REST resources by Active Resource much the same way Active Record maps model classes to database tables. When a request is made to a remote resource, a REST JSON request is generated, transmitted, and the result received and serialized into a usable Ruby object.

Download and installation

The latest version of Active Resource can be installed with RubyGems:

gem install activeresource

Or added to a Gemfile:

gem 'activeresource'

Source code can be downloaded on GitHub

Configuration and Usage

Putting Active Resource to use is very similar to Active Record. It's as simple as creating a model class that inherits from ActiveResource::Base and providing a site class variable to it:

class Person < ActiveResource::Base
  self.site = "http://api.people.com:3000"
end

Now the Person class is REST enabled and can invoke REST services very similarly to how Active Record invokes life cycle methods that operate against a persistent store.

# Find a person with id = 1
tyler = Person.find(1)
Person.exists?(1)  # => true

As you can see, the methods are quite similar to Active Record's methods for dealing with database records. But rather than dealing directly with a database record, you're dealing with HTTP resources (which may or may not be database records).

Connection settings (site, headers, user, password, bearer_token, proxy) and the connections themselves are store in thread-local variables to make them thread-safe, so you can also set these dynamically, even in a multi-threaded environment, for instance:

ActiveResource::Base.site = api_site_for(request)

Authentication

Active Resource supports the token based authentication provided by Rails through the ActionController::HttpAuthentication::Token class using custom headers.

class Person < ActiveResource::Base
  self.headers['Authorization'] = 'Token token="abcd"'
end

You can also set any specific HTTP header using the same way. As mentioned above, headers are thread-safe, so you can set headers dynamically, even in a multi-threaded environment:

ActiveResource::Base.headers['Authorization'] = current_session_api_token

Active Resource supports 2 options for HTTP authentication today.

  1. Basic
class Person < ActiveResource::Base
  self.user = '[email protected]'
  self.password = '123'
end
# username: [email protected] password: 123
  1. Bearer Token
class Person < ActiveResource::Base
  self.auth_type = :bearer
  self.bearer_token = 'my-token123'
end
# Bearer my-token123

Protocol

Active Resource is built on a standard JSON or XML format for requesting and submitting resources over HTTP. It mirrors the RESTful routing built into Action Controller but will also work with any other REST service that properly implements the protocol. REST uses HTTP, but unlike "typical" web applications, it makes use of all the verbs available in the HTTP specification:

  • GET requests are used for finding and retrieving resources.
  • POST requests are used to create new resources.
  • PUT requests are used to update existing resources.
  • DELETE requests are used to delete resources.

For more information on how this protocol works with Active Resource, see the ActiveResource::Base documentation; for more general information on REST web services, see the article here.

Find

Find requests use the GET method and expect the JSON form of whatever resource/resources is/are being requested. So, for a request for a single element, the JSON of that item is expected in response:

# Expects a response of
#
# {"id":1,"first":"Tyler","last":"Durden"}
#
# for GET http://api.people.com:3000/people/1.json
#
tyler = Person.find(1)

The JSON document that is received is used to build a new object of type Person, with each JSON element becoming an attribute on the object.

tyler.is_a? Person  # => true
tyler.last  # => 'Durden'

Any complex element (one that contains other elements) becomes its own object:

# With this response:
# {"id":1,"first":"Tyler","address":{"street":"Paper St.","state":"CA"}}
#
# for GET http://api.people.com:3000/people/1.json
#
tyler = Person.find(1)
tyler.address  # => <Person::Address::xxxxx>
tyler.address.street  # => 'Paper St.'

Collections can also be requested in a similar fashion

# Expects a response of
#
# [
#   {"id":1,"first":"Tyler","last":"Durden"},
#   {"id":2,"first":"Tony","last":"Stark",}
# ]
#
# for GET http://api.people.com:3000/people.json
#
people = Person.all
people.first  # => <Person::xxx 'first' => 'Tyler' ...>
people.last  # => <Person::xxx 'first' => 'Tony' ...>

Create

Creating a new resource submits the JSON form of the resource as the body of the request and expects a 'Location' header in the response with the RESTful URL location of the newly created resource. The id of the newly created resource is parsed out of the Location response header and automatically set as the id of the ARes object.

# {"first":"Tyler","last":"Durden"}
#
# is submitted as the body on
#
# if include_root_in_json is not set or set to false => {"first":"Tyler"}
# if include_root_in_json is set to true => {"person":{"first":"Tyler"}}
#
# POST http://api.people.com:3000/people.json
#
# when save is called on a new Person object.  An empty response is
# is expected with a 'Location' header value:
#
# Response (201): Location: http://api.people.com:3000/people/2
#
tyler = Person.new(:first => 'Tyler')
tyler.new?  # => true
tyler.save  # => true
tyler.new?  # => false
tyler.id    # => 2

Update

'save' is also used to update an existing resource and follows the same protocol as creating a resource with the exception that no response headers are needed -- just an empty response when the update on the server side was successful.

# {"first":"Tyler"}
#
# is submitted as the body on
#
# if include_root_in_json is not set or set to false => {"first":"Tyler"}
# if include_root_in_json is set to true => {"person":{"first":"Tyler"}}
#
# PUT http://api.people.com:3000/people/1.json
#
# when save is called on an existing Person object.  An empty response is
# is expected with code (204)
#
tyler = Person.find(1)
tyler.first # => 'Tyler'
tyler.first = 'Tyson'
tyler.save  # => true

Delete

Destruction of a resource can be invoked as a class and instance method of the resource.

# A request is made to
#
# DELETE http://api.people.com:3000/people/1.json
#
# for both of these forms.  An empty response with
# is expected with response code (200)
#
tyler = Person.find(1)
tyler.destroy  # => true
tyler.exists?  # => false
Person.delete(2)  # => true
Person.exists?(2) # => false

Associations

Relationships between resources can be declared using the standard association syntax that should be familiar to anyone who uses Active Record. For example, using the class definition below:

class Post < ActiveResource::Base
  self.site = "http://blog.io"
  has_many :comments
end

post = Post.find(1)      # issues GET http://blog.io/posts/1.json
comments = post.comments # issues GET http://blog.io/comments.json?post_id=1

In this case, the Comment model would have to be implemented as Active Resource, too.

If you control the server, you may wish to include nested resources thus avoiding a second network request. Given the resource above, if the response includes comments in the response, they will be automatically loaded into the Active Resource object. The server-side model can be adjusted as follows to include comments in the response.

class Post < ActiveRecord::Base
  has_many :comments

  def as_json(options)
    super.merge(:include=>[:comments])
  end
end

Logging

Active Resource instruments the event request.active_resource when doing a request to the remote service. You can subscribe to it by doing:

ActiveSupport::Notifications.subscribe('request.active_resource')  do |name, start, finish, id, payload|

The payload is a Hash with the following keys:

  • method as a Symbol
  • request_uri as a String
  • result as an Net::HTTPResponse

License

Active Resource is released under the MIT license:

Contributing to Active Resource

Active Resource is work of many contributors. You're encouraged to submit pull requests, propose features and discuss issues.

See CONTRIBUTING.

Support

Full API documentation is available at

Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here:

You can find more usage information in the ActiveResource::Base documentation.

activeresource's People

Contributors

amatsuda avatar arunagw avatar byroot avatar carlosantoniodasilva avatar denzel-morris avatar dhh avatar frodsan avatar fxn avatar gmcgibbon avatar gramos avatar guilleiguaran avatar jeremy avatar josevalim avatar josh avatar joshk avatar lifo avatar meanphil avatar mikel avatar mikeyhew avatar miloops avatar packagethief avatar rafaelfranca avatar sfaxon avatar sikachu avatar smartinez87 avatar spastorino avatar sweed avatar technoweenie avatar tenderlove avatar vijaydev 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  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  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  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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

activeresource's Issues

Add missing after_initialize callback

ActiveRecord provides an after_initialize callback, but ARes does not. Is there a reason why there is no after_initialize call back?

My intent is to use the call back to transform my Ares instance's attributes. E.g. Convert a unit of measurement. This behaviour doesn't seem to fit as a collection_parser as it wouldn't convert units when 1 resource is loaded.

Would you consider a pull request with the addition of an after initialize callback?

Path allowed on site attribute?

If site attribute is set to something like http://foo.com:8080/bar, the /bar segment is excluded on requests.
Is the prefix attribute expected to be used instead? If so, in cases where the path is a constant value (e.g.: /api), wouldn't it make more sense to be included in the site URL itself?

ActiveResource::Base.delete should send headers

Quoting @ehlertij :

Is this intentional or an oversight?

It looks like every other place in ActiveResource::Base that we're making a request through the connection the headers are being sent.

Ex:
def destroy connection.delete(element_path, self.class.headers) end
vs
def delete(id, options = {}) connection.delete(element_path(id, options)) end

I verified that this is still the case in the master branch. @ehlertij also provided a fix (Rails pull request #2480)

ActiveResource::Collection Responding to .empty?

I am not sure if this is an oversight or something I am doing wrong, but when upgrading my ActiveResource with Rails 4 I've had to modify all references to .empty? from ActiveResource::Collection objects. I noticed that it does respond to .any? It would seem like we would want that method defined so the collection more closely resembles array collections.

active_model_serializers

When using ActiveResource with ActiveModel::Serializer, we include

ActiveModel::SerializerSupport

which provides

 alias :read_attribute_for_serialization :send

However, this does not seem to work for ActiveResource, as the original method is still called. A possible workaround:

  1. Require ActiveResource before ActiveModel::Serializer in Gemfile
  2. Manually add the alias to the AR models.

Current activeresource gem is not compatible with Rails 4.0.0

The following error occurs with a new vanilla Rails 4.0 application when you add the activeresource gem to the bundle:

Bundler could not find compatible versions for gem "activesupport":
  In Gemfile:
    activeresource (>= 0) ruby depends on
      activesupport (= 2.0.1) ruby

    rails (= 4.0.0) ruby depends on
      activesupport (4.0.0)

Load throws inescapable error on object with one key that has same name

When I expect a response like the following from find:

tab_capabilities: {
    tab_type: "standard",
    extension: {
        extension_type: "post_open",
        url: {
            url: "https://www.freeformtext.com"
        }
    }
},

https://github.com/rails/activeresource/blob/master/lib/active_resource/base.rb#L1339 throws an error because in base.rb in the load method because https://github.com/rails/activeresource/blob/master/lib/active_resource/base.rb#L1333 will set remove_root to true for the url object and then remove the url key, which causes a
NoMethodError (undefined method 'each' for "https://www.freeformtext.com":String)
I realize that the api I'm consuming is poorly made, but is it the right choice to assume this should always remove the root? Shouldn't that be a choice made by the user in their own code as opposed to something decided by activeresource?

Defining Classes

I am working on upgrading my ActiveResource and integration with the latest Basecamp API. The association stuff looks great, but I noticed a problem where the class has to be defined before it is referenced in an association. Here is an example of what I mean.

class BasecampNext
  class Todolist < Resource
  end

  class Project < Resource
    has_many :todolists, class_name: 'basecamp_next/todolist'
  end
end

If I define the BasecampNext::Todolist class before the BasecampNext::Project class, everything works fine. If I definite it after, I get the following error when the file is loaded:

NameError: uninitialized constant BasecampNext::Todolist

This would create problems then if I tried to define a belongs_to :project association on BasecampNext::Todolist. I could define them all first and then define the associations, but I don't think that was intended.

ActiveResource::Base + ActiveModel::Serializer in rails3 vs. rails4

Hi guys,

I hope the title isn't somehow misleading, if so say and I will change it for you :)

but I am standing in front of quiet a problem now...
I got rails 3.2.14 app from my coworkers and they asked me to migrate it to 4.0.0, so i did and hence the activeresource is gem now I added

gem 'activeresource', require: 'activeresource'

and all went well, app is behaving normally, except this case:
we got company model as activeresource model and it is getting this data from service running on rails 4.0.0, which returns nicely formatted data of company (did through action_model_serializers in the service app), but all data and I does not want to show it all to user, but internally in app I need all those...
so of course in the main app I got company data as activeresource model, and here I got another serializer to serialize my output and after that I return nice json (I forgot to mention, that the main app is REST API)
this works nicely with rails 3.2.14 (just the main app, the service was on rails 4.0.0 for a long time) and if I get bundle list in rails 3.2.14 i see the gem version used

* activeresource (3.2.14)

but then after updating to rails 4.0.0, i got the answer from the service the same way, but this time the serializer is completely ignored in the main app and returns my data without any warning or error in the format I got from the service, which is painfully wrong :(

have you guys had problems like this or is this wanted behaviour, I have to say that I have no clue what to do with it now... :(

I am sorry if I gave you bad description, if needed I will try to make demo apps for this case

every answer will be highly appreciated, thx :)

UPDATE:

so to prove my point here, I got myself setup two apps as the ones I was describing
first one is the service (just provides /companies for the main_app)
pretty simple to get it running, just:

$ bundle install
$ rake db:migrate
$ rake db:seed
$ rails s -p 3010

this one is backed by DB, so you have to migrate that and i got my main app setup to looks for it on port 3010, so thats for the rails s

and then there is the main_app which got two branches, one is using rails 3.2.14 (branch rails3) and the other one is using rails 4.0.0 (branch rails4)
so you can switch accordingly and now to get it running, just :

$ bundle install
$rails s

and you got it going on version of rails you deserve, and my point here is that the rails4 one completly ignores serializer in main_app and returns data in other format than before...

but those app rely on the format of data and it is a big big problem now...
ex. rails3 output, which is the deserved one looks like this:

{
  companies: [
    {
      name: "HelloWorld s.r.o",
      tax_number: "CZ3423432490035"
    },
    {
      name: "MyExample a.s.",
      tax_number: "CZ342378979435"
    },
    {
      name: "HelloWorld s.r.o",
      tax_number: "CZ34353324345"
    },
    {
      name: "HelloWorld s.r.o",
      tax_number: "CZ342354654435"
    }
  ]
}

but when you switch to rails4 you got this:

[
  {
    id: 1,
    name: "HelloWorld s.r.o",
    tax_number: "CZ3423432490035",
    address: "Brno, Jostova 21, 60200"
  },
  {
    id: 2,
    name: "MyExample a.s.",
    tax_number: "CZ342378979435",
    address: "Brno, Jostova 22, 60200"
  },
  {
    id: 3,
    name: "HelloWorld s.r.o",
    tax_number: "CZ34353324345",
    address: "Brno, Jostova 23, 60200"
  },
  {
    id: 4,
    name: "HelloWorld s.r.o",
    tax_number: "CZ342354654435",
    address: "Brno, Jostova 24, 60200"
  }
]

which throws the whole app into confusion :)

I hope you know what I am talking about now and will help me to solve the issue
As I look at it, it may be the rails mistake, I am not sure, please say if its just some configuration I overlooked or something, thx for your time guys :)

Validation yield 'No Method' Error

If I set up a model with validation on attribute email and then perform a update_attributes with hash { first_name: 'test', last_name: 'test'},

it will yield a No Method for 'email' error, instead of a validation error.

ActiveResource find() return nil using :params

Hi

I am trying to retrieve a single resource from a REST api app using ActiveResource. The code is like this:

Page.find(:one, :params => {:draft => false, title => "blah"}) => nil # But the entry doest exists in page table

The combination of draft and title is unique in the Pages table btw. I have tried different solution using :conditions instead of :params but still. Has anyone seen similar problem?

Digest Auth doesn't work properly

The normal way is: client asks server, server responds, client do some crypto things and responds to the server.

If I use digest auth the first thing is that the client sends a www-authenticate header without getting the server response before.
This ends in a 400 .
I'd try to use ActiveResource in junction with the shopware REST API.
I think the problem lays somewhere in connection.rb/authorisation_header.
Instead of if auth_type == :digest it should maybe be if auth_type == :digest && @response_auth_header
But it doesn't work properly ... I got 400 too.

Can't run test suite

bundle exec rake throws a RuntimeError:

mocha-0.12.6/lib/mocha/integration/mini_test.rb:56:in `<class:TestCase>': No Mocha monkey-patch for MiniTest version (RuntimeError)

Using:

  • Mocha 0.12.6
  • Ruby 1.9.3-p194
  • HEAD activeresource
  • Minitest 4.0.0

Do we really need format extension in element path?

By default, in the Base class, the methods *_path return a path with the format extension (.json, .xml).
I work in some projects that communicate by HTTP sending a lot of json between them.

However in some cases we have callback urls and other types where we don't need (or cannot) pass the format in path.
So I need to define a flag like "include_root_in_json", making it configurable.

If you agree at all, I can send a PR with that changes.

Issue in decoding when the API response has a single key

I have a singular resource 'User' on my API side and the GET /user call returns:

{
  hobbies: ["music", "tennis"]
}

Now, on my other project I have a ActiveResource Singleton object defined:

class User < ActiveResource::Base
  include ActiveResource::Singleton

  self.site = "some url"
end

Now, when I try to find the user:

User.find
ArgumentError: expected an attributes Hash, got ["music", "tennis"]
...

PS: I am sure the same problem will exist with XML format as well.

I have narrowed down the problem to the 'decode' method at active_resource/formats/json_format.rb

I have monkey-patched the 'decode' method to:

def decode(json)
  ActiveSupport::JSON.decode(json)
end

and it works.

I wanted to find out if this really a bug or some mistake on my part.

client-cert ssl doesn't pass through activeresource

I have the following code in my application:

class Foo < ActiveResource::Base
  c = MyLibrary.client # (this is a Net::HTTP object)
  self.site = "https://#{c.address}/1.0/internal/"
  self.include_format_in_path = false

  self.ssl_options = {
    cert:        c.cert,
    key:         c.key,
    ca_file:     c.ca_file,
    verify_mode: c.verify_mode
  }
end

In a rails console, I get the following:

Loading development environment (Rails 4.0.0.beta1)
2.0.0p0 :001 > c = MyLibrary.client
 => #<Net::HTTP someserver.tamird.local:50005 open=false>
2.0.0p0 :002 > c.class
 => Net::HTTP < Net::Protocol
2.0.0p0 :004 > c.get('/1.0/internal/foos/1').body
 => "{\"created_at\":\"2013-03-04T00:15:48Z\","user_id\":\"5\",\"description\":\"Diagnostic\"}"
2.0.0p0 :005 > Foo.find(1)
ActiveResource::UnauthorizedAccess: Failed.  Response code = 401.  Response message = Unauthorized.
    from /Users/tamird/.rvm/gems/ruby-2.0.0-p0/bundler/gems/activeresource-d16cb85d96b3/lib/active_resource/connection.rb:140:in `handle_response'
    from /Users/tamird/.rvm/gems/ruby-2.0.0-p0/bundler/gems/activeresource-d16cb85d96b3/lib/active_resource/connection.rb:123:in `request'
    from /Users/tamird/.rvm/gems/ruby-2.0.0-p0/bundler/gems/activeresource-d16cb85d96b3/lib/active_resource/connection.rb:82:in `block in get'
    from /Users/tamird/.rvm/gems/ruby-2.0.0-p0/bundler/gems/activeresource-d16cb85d96b3/lib/active_resource/connection.rb:216:in `with_auth'
    from /Users/tamird/.rvm/gems/ruby-2.0.0-p0/bundler/gems/activeresource-d16cb85d96b3/lib/active_resource/connection.rb:82:in `get'
    from /Users/tamird/.rvm/gems/ruby-2.0.0-p0/bundler/gems/activeresource-d16cb85d96b3/lib/active_resource/base.rb:990:in `find_single'
    from /Users/tamird/.rvm/gems/ruby-2.0.0-p0/bundler/gems/activeresource-d16cb85d96b3/lib/active_resource/base.rb:877:in `find'
    from (irb):5
    from /Users/tamird/.rvm/gems/ruby-2.0.0-p0/bundler/gems/rails-7a872e9d84be/railties/lib/rails/commands/console.rb:90:in `start'
    from /Users/tamird/.rvm/gems/ruby-2.0.0-p0/bundler/gems/rails-7a872e9d84be/railties/lib/rails/commands/console.rb:9:in `start'
    from /Users/tamird/.rvm/gems/ruby-2.0.0-p0/bundler/gems/rails-7a872e9d84be/railties/lib/rails/commands.rb:66:in `<top (required)>'
    from bin/rails:4:in `require'
    from bin/rails:4:in `<main>'

I've checked the logs on the receiver app side and the x-ssl-client-cert header never makes it there.

I've put debug statements all over the activeresource code and the ssl options appear to be there right up to the call to get, yet it does not work.

I'm on edge rails and edge activeresource.

ActiveResource::Base uses options[:params]

Comment.all(post_id: 12)
calls

find(*arguments)

that calls

find_every(options)

that assumes the options to have [:params] at

prefix_options, query_options = split_options(options[:params])

Checking step by step, the initial call Comment.all(post_id: 12) ends up with options[:params]) == nil
which doesn't seem to be correct.

Support for :foreign_key

With ActiveRecord I can specify a :foreign_key association, however any attempt to modify the site url with a non default convention returns a prefix not set error. How can I specify an alternate field to use to access a nested resource.

For example:

class Account < ActiveResource::Base
  has_many :followers  # how do I instruct to use clientId instead of account_id
end

class Follower < ActiveResource::Base
  self.prefix = "/accounts/:clientId/"
  belongs_to :account
end

ActiveResource and serialize combination: inconsistent results

I have a User ActiveRecord model and a Page ActiveResource. I'm using "serialize" in the User model to cache some pages related to every user. It usually works nicely, but I have detected errors when the Page class hasn't been accessed yet. An example in console:

User.last.update_attribute(:pages, Page.all)
User.last.pages.class  => Array

I exit the console and start it again

User.last.pages.class  => String # This is the problem, it's not being unserialized correctly
test = Page.new # I load the Page class in a completely independent call
User.last.pages.class  => Array # This returns Array, working again!

I'm not sure if this is an error of ActiveResource, but my guess is that the ActiveResource classes should be loaded when the application starts. What do you think?

Resource URL encoding

ActiveResource does not support UTF-8 models, because the resource URL is not escaped before the request.

class Árbol < ActiveResource::Base
  self.site = 'http://localhost:3000'
end

Árbol.all

Produces URI::InvalidURIError: bad URI(is not URI?).

4.0.0beta

Please add the 4.0.0.beta gem so I can start using active resource with rails 4 without having to use the git master branch.

thanks

ActiveResource expectations for form of error message? How to coerce non-standard error into that form?

I am accessing the Zendesk v2 API with ActiveResource. Today I tried to update via PUT a resource where I used a name that already existed. This returned HTTP 422 and the following JSON:

-> "{"error":"RecordInvalid","description":"Record validation errors","details":{"name":[{"description":"Name has already been taken"}]}}"

--or--

{
    "error"; "RecordInvalid",
    "description": "Record validation errors",
    "details": {
        "name": [ 
            { "description": "Name has already been taken" }
        ]
    }
}

This resulted in the following exception:

I, [2014-01-10T13:48:07.866954 #3813]  INFO -- : PUT 
    https://support.asperasoft.com:443/api/v2/organizations/20151598.json
I, [2014-01-10T13:48:07.867280 #3813]  INFO -- : --> 
    422 Unprocessable Entity 133 (517.5ms)
DEPRECATION WARNING: Returning errors as a hash without a 
    root "errors" key is deprecated. 
    (called from update_org at ./update_zen_orgs_from_sfdc.rb:289)
/usr/local/rvm/gems/ruby-1.9.3-p484/gems/activeresource-4.0.0/lib/active_resource/validations.rb:37:in `block in from_hash': 
    undefined method `each' for "RecordInvalid":String (NoMethodError)
        from /usr/local/rvm/gems/ruby-1.9.3-p484/gems/activeresource-4.0.0/lib/active_resource/validations.rb:36:in `each'
        from /usr/local/rvm/gems/ruby-1.9.3-p484/gems/activeresource-4.0.0/lib/active_resource/validations.rb:36:in `from_hash'
        from /usr/local/rvm/gems/ruby-1.9.3-p484/gems/activeresource-4.0.0/lib/active_resource/validations.rb:67:in `from_json'
        from /usr/local/rvm/gems/ruby-1.9.3-p484/gems/activeresource-4.0.0/lib/active_resource/validations.rb:138:in `load_remote_errors'
        from /usr/local/rvm/gems/ruby-1.9.3-p484/gems/activeresource-4.0.0/lib/active_resource/validations.rb:126:in `rescue in save_with_validation'
        from /usr/local/rvm/gems/ruby-1.9.3-p484/gems/activeresource-4.0.0/lib/active_resource/validations.rb:109:in `save_with_validation'
        from /usr/local/rvm/gems/ruby-1.9.3-p484/gems/activeresource-4.0.0/lib/active_resource/observing.rb:21:in `save_with_notifications'
        from ./update_zen_orgs_from_sfdc.rb:289:in `update_org'
        from ./update_zen_orgs_from_sfdc.rb:511:in `block in <main>'
        from ./update_zen_orgs_from_sfdc.rb:301:in `each'
        from ./update_zen_orgs_from_sfdc.rb:301:in `<main>'

Two questions about this;

  1. Looks like AactiveResource is looking for error infgor to be a hash with a root "errors" key. What exactly is the expected format for the error info and where is this documented?
  2. Is there a way with ActiveResource where I can coerce this non-standard error JSON into something that AR would be happy with?

Thanks in advance for any help here...

Issue parsing certain keys

find_or_create_resource_for dies when trying to parse the name :"4500/tcp". Which gets converted to "4500::Tcp" before being passed into self.class.const_defined?; Yielding to NameError: wrong constant name 4500

I am mostly sure its an issue with parsing a number to key.

What to do about undocumented magical semantics?

This is a bit of a meta-issue. First, consider this commit:

2c90ddb4

Note in particular the change to Formats.decode where it now always strips off the outer layer from any single-item hash that's passed in. There is no explanation or justification for this, it appears to simply be done as an easy way to make the JSON version of the original XML tests pass. This type of functionality has existed elsewhere, but usually with some kind of sanity check on the name, but now we face a situation where returning {:success => true} from a POST or PUT blows up without recourse.

This was done over a year ago and as far as I can find, no one has complained about it yet, which I assume is because no one is running this code yet because the published activeresource gem is still coming from rails/activeresource.

It does however break my code pretty hard, and I'm trying to figure out what to do. At this point I'm leaning towards reverting some of this stuff in my own branch because I have no idea what the intent or vision for activeresource is. It seems like most people have moved on from activeresource, but we're in bed pretty deep with it since we've been using it since 2007 and we have multiple Rails apps running in an SOA over ActiveResource.

Rather than going off in my own direction, I think anyone using activeresource could gain from some kind of shared vision, but discussion has fizzled out, the dedicated google group never got off the ground, and I'm hard pressed to find anyone who cares. Is there anyone with the interest to actually work on formalizing activeresources magic behavior and documenting it out?

Inconsistent ActiveResource::Base.build behavior: expects overriding attributes, instead takes prefix options

The Problem

The documentation says:

attributes - A hash that overrides the default values from the server.

But both the code (line 768 of base.rb)

def build(attributes = {})
  attrs = self.format.decode(connection.get("#{new_element_path(attributes)}", headers).body)
  self.new(attrs)
end

and the tests (line 669 of base_test.rb), say otherwise

def test_build_without_attributes_for_prefix_call
  ActiveResource::HttpMock.respond_to do |mock|
    mock.get "/people/1/addresses/new.json", {}, StreetAddress.new.to_json
  end
  assert_raise(ActiveResource::InvalidRequestError) { StreetAddress.build }
end
def test_build_with_attributes_for_prefix_call
  ActiveResource::HttpMock.respond_to do |mock|
    mock.get "/people/1/addresses/new.json", {}, StreetAddress.new.to_json
  end
  assert_nothing_raised { StreetAddress.build(person_id: 1) }
end

Attributes is passed to new_element_path which uses them as prefix options not as attributes to override the defaults provided.

Possible Solutions

  • Correct the behavior of build and use the attributes passed for a query parameter list instead of prefix options
  • Create a new method called initialize that takes attributes used to override the defaults and update the documentation for build

These are the two most viable solutions to me. There are others that just don't seem as great. Personally, I'm a fan of option 2.

I'd like to get some input before I modify the code, tests, and submit a pull request. Any suggestions?

associations don't work

class User < ActiveResource::Base
   has_many :posts
end
User.all do |u| u.posts end

Throws:

undefined method `posts' for #<User:0x007fa86a4d0ac0>

3.2.13: Ruby 2.0 incompatibility

Ruby 2.0 is missing Enumerable#collect!.

This seems to be fixed for ActiveResource 4. But my project uses 3.2.13.

So I tried to fork and make changes. But where is version 3.2.13 tagged?

Adding support for Authorization Token

Allow to use Rest API secured using the Authorization: Token token="" HTTP header provided for example by the Rails' authenticate_or_request_with_http_token method.

Sorry if I can't find the pull request button.

OK, so I can't get into google to post into the groups so I put it here.

I want to make a framework that lets me use oauth2 as a backend, and active model/activeresource as a front end, and my idea was that active resource like active record should have drivers for different types of protocols, and a resources.yml file similar to databases.yml. I've noticed trying to get activeresource to do anything beyond a very specific type of REST request is like pulling teeth.

  1. What do you guys think?
  2. The plan is to fork activeresource, modify the code and deploy the fork in my company's site, which will be tested. If you guys don't think its a good idea for activeresource to go this route... I understand, but it seems like this gem is dying. And I think opening it up to oauth2, rest, soap, etc would breathe life into this gem.
  3. If I totatally missed the big neon sign telling of rails 4's awesome new thing that replaces this... let me know. I did try to scour through the blogs, mailing-lists, irc to find something... and couldn't.

Setting OAUTH2 Headers

With previous versions of ActiveResource, the OAUTH2 headers could be set like this:

  class Resource < ActiveResource::Base
  end

  class MyClass1 < Resource
  end

  class MyClass2 < Resource
  end

The headers could then be set:

Resource.headers['authorization'] = 'Bearer ' + my_oauth2_token

My problem with the latest ActiveResource is I can change the Resource.headers and each class will inherit correctly, until I try to set the headers to something else. If I update Resource.headers['authorization'], the other classes (MyClass1, MyClass2)) will still have the old token. Does that make sense?

Is there a way to have conditional prefix?

I'm curious if there is a way to make 'smart' prefix (or manually write some conditions) to get rid of ActiveResource::MissingPrefixParam exception.

class Post < ActiveResource::Base
  self.site = 'http://localhost/api'

  has_many :comments
end
class Comment < ActiveResource::Base
  self.site = 'http://localhost/api'
  self.prefix = '/posts/:post_id/'

  belongs_to :post
end
Post.find(1).comments # ok. uses /posts/1/comments
Comment.find(1) # raises ActiveResource::MissingPrefixParam, should use /comments/1

Documentation examples in JSON

The current documentation is all written against an XML API. The current Rails scaffold generates JSON API's rather than XML.

I would like to update the docs to show ActiveResource consuming JSON API's rather than XML but wanted to make sure this was something that people would want to see merged back in before I got started on it.

The use of :data in a non-configurable API response

activeresource does not seem to be able to accept incoming data with the :data set and used to store information.

We are building a rails app that receives data from another app and the api is giving is

activeresource TypeError: allocator undefined for Data.

We appear to be getting the same problem as the following posting

http://stackoverflow.com/questions/7306004/having-allocator-undefined-for-data-when-saving-with-activeresource

All the current "hacks" seem to patch active resource. Can we not get this active resource :data namespaced?

ActiveResource::Base.headers is not threadsafe

Is there a reason to not use Thread.current to store the headers in a similar way as a lot of other Rails "constants", so we can do per-request headers that contain additional information?

Prevent mapping of nested attributes to Models

Is there any way to prevent ActiveResource from mapping nested attributes in an API response to Models within my application?

ex:

API Response

{

    "eventDate": "2012-09-29T23:00:00.000Z",
    "eventState": "final",
    "sport": {
        "sportName": "Football",
        "sportCode": "m-footbl"
    },
    "type": "SportsEvent",
    "uid": "stats-event-1180289",
}

I have a model called Sport, which seems to be getting mapped to that particular property. I'd like to prevent that from happening, possible?

Has many association sends request to wrong URL

The has many association behaves in stark contrast to its documentation. Given

class Subresource  < ActiveResource::Base
  ...
end

class Resource < ActiveResource::Base
  has_many :subresources
end

I expect the following to happen

Resource.first.subresources
# => /resource/:id/subresources/

But what really happens is

Resource.first.subresources
# => /subresources?resource_id=:id

It'd be easy to change this behavior if it wasn't for how ActiveResource::Base builds paths.

It doesn't do "dumb" prefixes, it only does "smart" ones where it attempts filter the passed in prefix_options based upon the prefixes set on a resource. But the resource doesn't, and should not, have prefixes since this is simply a has_many association and the Subresource has its own endpoints as well.

I don't want to hack this, so I'd like some community input on what others believe is the best path of action?

[Question] Handling attribute conversion through schema definition?

How do we want to handle the conversion of attributes through their schema definition? The known types are:

KNOWN_ATTRIBUTE_TYPES = %w( string text integer float decimal datetime timestamp time date binary boolean )

I understand how to convert: string, integer, float, datetime, time, and date. But how do we want to handle automatic conversion, and what should the types be, for text, decimal, timestamp, binary, and boolean?

I just need some direction, and then I can submit a pull request. Also, if anyone has any direction on how they'd like it to be structured, feel free to weigh in.

As it stands, I would just add a casting class method to ActiveResource::Schema and then utilize that in the method_missing attribute handler of ActiveResource::Base. Seems easy enough.

ActiveResource NameError: wrong constant name with complex xml tag

Hi all,
I'm using ActiveResource to communicate with a "custom" REST application.
My model use the ":from" to customize the url and it receives an xml response.
find(:one, :from => "/XXX/service/Decreto/"+id.to_s+"/caricaDocumento")
The server is a java application that serialize objects using XStream. In the xml I have some tag names with full class name (for example it.mypackage.MyClass).
When ActiveResource parse the xml to create attributes the system go in error with

NameError: wrong constant name it.mypackage.MyClass
from /home/ruby/.rvm/gems/ruby-1.9.3-p194/gems/activeresource-3.2.6/lib/active_resource/base.rb:1428:in const_defined
?'
from /home/ruby/.rvm/gems/ruby-1.9.3-p194/gems/activeresource-3.2.6/lib/active_resource/base.rb:1428:infind_or_creat
e_resource_for'
from /home/ruby/.rvm/gems/ruby-1.9.3-p194/gems/activeresource-3.2.6/lib/active_resource/base.rb:1278:in block in load
'
from /home/ruby/.rvm/gems/ruby-1.9.3-p194/gems/activeresource-3.2.6/lib/active_resource/base.rb:1264:ineach'
from /home/ruby/.rvm/gems/ruby-1.9.3-p194/gems/activeresource-3.2.6/lib/active_resource/base.rb:1264:in load'
from /home/ruby/.rvm/gems/ruby-1.9.3-p194/gems/activeresource-3.2.6/lib/active_resource/base.rb:1006:ininitialize'

The problem in find_or_create_resource_for is caused by const_defined? with a parameter that contains "it.mypackage.MyClass" (with dot)

It can be resolved changing the line
resourcename = name.to_s.camelize
with
resource_name = name.to_s.gsub(/\W+/, '').camelize

or better using an external method that can be overrided

associations should respect nested resources!

I thought this issue was resolved but It isn't. Consider the following:

Club class: has_many :events
Event class: belongs_to :club

Club.first.events surely would be logical to make a request like /clubs/1/events.xml rather than what it does at the moment which is /events.xml?club_id=9

With the routes in the server like:

resources :clubs do
  resources :events
end

I think it's nuts to do it the way it is done currently, wrong direction!

ActiveResource find() not following JSON api

When following the JSON API document, I return my singular resources in an array as described:

 {
   "designs": [
    {
      // individual design
    }
  ]
}

My app talking to the API uses ActiveResource. When I do a find in ActiveRescource

Api::Design.find(10)

I get the following error:

ArgumentError: expected an attributes Hash, got [{"id"=>10, "title"=>" ...

ActiveResource seems to have trouble with return singular resources as an array.
Any thoughts or help on this?

Support for "<<" on associations

I think it would be great to support the "<<" operator on associations since there are many situations where you just want to add an item to an association, today it is only possible to replace all the association items at once.
My first idea was to overwrite the "<<" operator in the ARes association class (is it just an Array?), track all changes made and, in the save method, make a second call to "push" the new items on the association, for instance:

PUT /post/123/comments -d comments[][body]="this is a comment"

Or even add an existent item:

PUT /post/123/comments -d comments[][id]=456

I'm not sure so I was wondering if you have a better solution, maybe I can borrow some ideas from AR. What do you think?

Thanks

Array response with hash which has only one key got an ArgumentError: expected an attributes Hash

Hello,

this response work fine:

[
    {
        "foo" : "foo",
        "title" : "bar"
    },
    {
       "foo" : "foo2",
       "title" : "baz"
    }
 ]

 [#<Theme:0x0000000655d998 @attributes={"foo"=>"foo", "title"=>"bar"}...]

but this one do not work:

[
   {
      "title" : "bar"
   },
   {
      "title" : "baz"
   }
]

I got this:
ArgumentError: expected an attributes Hash, got "bar"
from /home/pio/.rvm/gems/ruby-2.0.0-p247@werweisswas/gems/activeresource-4.0.0/lib/active_resource/base.rb:1328:in load' from /home/pio/.rvm/gems/ruby-2.0.0-p247@werweisswas/gems/activeresource-4.0.0/lib/active_resource/base.rb:1075:ininitialize'
from /home/pio/.rvm/gems/ruby-2.0.0-p247@werweisswas/gems/activeresource-4.0.0/lib/active_resource/base.rb:1002:in new' from /home/pio/.rvm/gems/ruby-2.0.0-p247@werweisswas/gems/activeresource-4.0.0/lib/active_resource/base.rb:1002:ininstantiate_record'
from /home/pio/.rvm/gems/ruby-2.0.0-p247@werweisswas/gems/activeresource-4.0.0/lib/active_resource/base.rb:998:in block in instantiate_collection' from /home/pio/.rvm/gems/ruby-2.0.0-p247@werweisswas/gems/activeresource-4.0.0/lib/active_resource/collection.rb:67:inblock in collect!'
from /home/pio/.rvm/gems/ruby-2.0.0-p247@werweisswas/gems/activeresource-4.0.0/lib/active_resource/collection.rb:7:in each' from /home/pio/.rvm/gems/ruby-2.0.0-p247@werweisswas/gems/activeresource-4.0.0/lib/active_resource/collection.rb:7:ineach'
from /home/pio/.rvm/gems/ruby-2.0.0-p247@werweisswas/gems/activeresource-4.0.0/lib/active_resource/collection.rb:67:in collect!' from /home/pio/.rvm/gems/ruby-2.0.0-p247@werweisswas/gems/activeresource-4.0.0/lib/active_resource/base.rb:998:ininstantiate_collection'
from /home/pio/.rvm/gems/ruby-2.0.0-p247@werweisswas/gems/activeresource-4.0.0/lib/active_resource/base.rb:959:in find_every' from /home/pio/.rvm/gems/ruby-2.0.0-p247@werweisswas/gems/activeresource-4.0.0/lib/active_resource/base.rb:873:infind'
from /home/pio/.rvm/gems/ruby-2.0.0-p247@werweisswas/gems/activeresource-4.0.0/lib/active_resource/base.rb:899:in all' from (irb):28 from /home/pio/.rvm/gems/ruby-2.0.0-p247@werweisswas/gems/railties-4.0.0/lib/rails/commands/console.rb:90:instart'
from /home/pio/.rvm/gems/ruby-2.0.0-p247@werweisswas/gems/railties-4.0.0/lib/rails/commands/console.rb:9:in start' from /home/pio/.rvm/gems/ruby-2.0.0-p247@werweisswas/gems/railties-4.0.0/lib/rails/commands.rb:64:in<top (required)>'
from script/rails:25:in `require'

Dirty Tracking

Hey guys,

I was wondering why dirty tracking is not implemented in activeresource. Is it just a low priority task or vision of gem owners that it shouldn't be there.

I'd like to tackle on this issue anyways, but before I do that I wanted to hear about your position on this.

To outline the Q:
Should dirty tracking be implemented in activeresource ?

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.