rails / activeresource

Connects business objects and REST web services
MIT License
1.33k stars 360 forks source link

ActiveResource find calls active record init #249

Closed Cremz closed 7 years ago

Cremz commented 7 years ago

I have a simple ActiveResource class. When i do .all it gets results from api. when i do find by an id it fails with error

ArgumentError: wrong number of arguments (given 2, expected 0..1)

which i discovered is triggered here: activerecord-5.1.0/lib/active_record/core.rb:330 This only happens in production mode, in development it is fine. I don't have any other stacktrace, no clue how to debug. Why would an ActiveResource model trigger init for active record and only on production? it happens both on my dev machine when i start the server, in console as well as on the deployment server.
i already opened a question on stack: http://stackoverflow.com/questions/43992844/active-resource-find-doesnt-work-in-production

geetfun commented 7 years ago

I'm experiencing the same issue. Similarly, it doesn't show up in development but only in production.

Not sure how to even test for this.

The backtrace doesn't show a call to ActiveRecord as @Cremz mentioned, however.

Strangely, the master branch didn't cause any of this issue until recently. Not sure if it's related to this commit: c38f18c

UPDATE: Reverting the c38f18c commit didn't help for me.

The relevant backtrace:

screen shot 2017-05-27 at 4 10 14 pm

UPDATE: It appears I was able to fix this.

The problem is encountered when the AR source returns data that has more than 1 level deep of nested data. For whatever reason, AR::Base#find_or_create_resource_for is unable to instantiate it properly.

The workaround is to pre-define these nested resources in a separate file (eg. in a file in Rails initializer directory).

rafaelfranca commented 7 years ago

Can you please provide a sample application that reproduces the error?

ooeyuna commented 7 years ago

I have occur this issue too, it casue by class name conflict.

9154ce1d-5468-4f15-b47f-7c4e34a7c80b

normally, it should create new ActiveResource 'Container'. but it found 'Container' model, and use wrong class to initialize object.

arturtr commented 7 years ago

I found that self.include_root_in_json = true is reason by this error in my case

If switched it off, I cann't to create resource because it require root element.

Can we use root only for create?

arturtr commented 7 years ago

Switch format to ActiveResource::Formats::XmlFormat solve the issue in my case

arturtr commented 7 years ago

But in this case I missed collection attributes like total_count

I tried to write activeresource wrapper for http://www.redmine.org/projects/redmine/wiki/Rest_Issues

arturtr commented 7 years ago

Version from master branch fixes issue with JSON with root

arturtr commented 7 years ago

@geetfun advice helps me to solve tis problem

The problem is encountered when the AR source returns data that has more than 1 level deep of nested data. For whatever reason, AR::Base#find_or_create_resource_for is unable to instantiate it properly.

The workaround is to pre-define these nested resources in a separate file

I solve it in this manner

class Redmine::API::CRM::Issue < Redmine::API::CRM::Base
  class IssueCollection < ActiveResource::Collection
    attr_reader :limit, :offset, :total_count

    def initialize(parsed = {})
      @elements = parsed['issues']
      @total_count = parsed['total_count']
      @offset = parsed['offset']
      @limit = parsed['limit']
    end

    def total_pages
      total_count / limit + 1
    end

    def current_page
      offset / limit + 1
    end
  end

  self.collection_parser = IssueCollection

  class Project < Redmine::API::Base; end
  class Tracker < Redmine::API::Base; end
  class Status < Redmine::API::Base; end
  class Priority < Redmine::API::Base; end
  class Author < Redmine::API::Base; end
  class AssignedTo < Redmine::API::Base; end
end

class Redmine::API::Base < ActiveResource::Base
  self.site = APP_CONFIG['redmine_url']

  def self.api_key
    Rails.application.secrets.redmine_api_key
  end

  self.headers['X-Redmine-API-Key'] = api_key
end

Also I removed self.include_root_in_json = true from Base class and place it in resources for POST requests.

rails-bot[bot] commented 7 years ago

This issue has been automatically marked as stale because it has not been commented on for at least three months. The resources of the Rails team are limited, and so we are asking for your help.

If it is an issue and you can still reproduce this error on the master branch, please reply with all of the information you have about it in order to keep the issue open.

If it is a pull request and you are still interested on having it merged please make sure it can be merged clearly.

Thank you for all your contributions.

alistairholt commented 5 years ago

I'm still experiencing this issue.

Cremz commented 5 years ago

It happens when the resource you are trying to access has a more complex structure (objects as values). But it doesn't happen all the time, I have an application running perfectly normal when loading resources with objects 3-4 levels deep. But i recently created a new app that uses the same api and I do get that error.

Cremz commented 5 years ago

I bumped into this issue again this evening. Here's what happens if you have a model called Writer which has_many :books and also the model Book defined in your activeresource application, if your Writer json returns an array of books, those books can only have keys and values (strings, integers, boolean) for example: writer.json: { id: 1, books: [ { id: 1, name: "book", details: { some_key: "some_value" } } ] } this will break. active resources sees that Book is defined as an association, and when it tries to parse the details (Hash) it will break.

ivanbrennan commented 5 years ago

Could the reason this crops up in production and not in development be due to Rails Autoloading and Reloading Constants?

By default, Rails eager loads the application files when it boots in production mode, so most of the autoloading going on in development does not happen.

I ran into a similar issue in an app that used ActiveRecord for a vendor model and ActiveResource for a delivery model that has a vendor attribute. In development, if the vendor model has not yet been loaded, you can fetch a delivery and deserialize it, including the vendor attribute. If, however, the vendor model has been loaded already, attempting to fetch a delivery leads to the error described in this issue.

cschmeichel commented 4 years ago

@ivanbrennan I'm experiencing the same issue. Did you find a workaround?

In your case, doing something like:

Vendor.connection
Delivery.find(1)

should fail

ivanbrennan commented 4 years ago

@cschmeichel Unfortunately, no. I ended up removing ActiveResource from the project and handling the network calls directly, using RestClient.

FilisLiu commented 4 months ago

In my case, placing ActiveResource models in the same directory (app/models) as ActiveRecord was the reason.

I solved it by defining the model within a module to create a distinct namespace such as Api::Model.find