5

I'm trying to use the Basecamp Classic API (http://developer.37signals.com/basecamp/comments.shtml). The current basecamp-wrapper version was giving me fits, one of the things was because the json responses include pagination output, while the xml ones don't. That was an easy fix, but the problem is the url structure isn't standardized.

The API specifies a few things like so, which lead me to believe it'd be simply separating out the element path and collection paths.

Get recent comments (for a commentable resource)
GET /#{resource}/#{resource_id}/comments.xml

Update comment
PUT /comments/#{id}.xml

I've made several attempts at this and haven't really succeeded. Attempting to handle comments like this is hacky at best, and doesn't actually work because the element_path is different than the collection_path.

class Resource < ActiveResource::Base
  self.site = "https://XXXX.basecamphq.com"
  self.user = "XXXX"
  self.password = "X" # This is just X according to the API, I have also read nil works
  self.format = :xml # json responses include pagination crap

  # Override element path so it isn't nested
  class << self
    def element_path(id, prefix_options={}, query_options={})
      prefix_options, query_options = split_options(prefix_options) if query_options.nil?
      "#{collection_name}/#{URI.parser.escape id.to_s}.#{format.extension}#{query_string(query_options)}"
    end
  end
end

class Project < Resource
end

class Message < Resource

  self.element_name = "post"
  self.prefix = "/projects/:project_id/"
  self.collection_name = "posts"

  def comments
    @comments ||= Comment.all(:params => {:resource => "posts" , :resource_id => id})
  end
end

class Comment < Resource
  self.prefix = "/:resource/:resource_id/"
end

puts m = Message.first(:params => {:project_id => PROJECT_ID})
puts m = Message.find(m.id)
puts m.update_attribute(:title, "name")

This works up until the update_attribute, which is actually getting the proper non-nested url and it's making a PUT request that fails.

Why doesn't this work for update? How do I handle the different parent resources in a better manner?

Any tips would be awesome. :)

excid3
  • 1,658
  • 15
  • 31
  • before answering, I'm curious if something like [remotely](https://github.com/wegowise/remotely) would work for you? – 20man Feb 07 '13 at 02:35
  • Possibly would. This isn't important for me anymore, plus this is now called Basecamp Classic. – excid3 Feb 08 '13 at 14:48

1 Answers1

0

If you try to hack ActiveResource, you're not going to have a good time.

I would not use prefix, and instead I would define methods in the parent resources for getting the child resources, using find(:all, :from => ''). http://api.rubyonrails.org/classes/ActiveResource/Base.html#method-c-find

class Resource < ActiveResource::Base
  self.site = "https://XXXX.basecamphq.com"
  self.user = "XXXX"
  self.password = "X" # This is just X according to the API, I have also read nil works
  self.format = :xml # json responses include pagination crap
end

class Project < Resource
  def messages
    @messages ||= Message.find(:all, :from => "/projects/#{self.id}/posts.xml")
  end
end

class Message < Resource
  self.element_name = "post"

  def comments
    @comments ||= Comment.find(:all, :from => "/posts/#{self.id}/comments.xml")
  end
end

class Comment < Resource
end

The way you use these resources corresponds to the paths that are called.

project  = Project.find(1)               # GET /projects/1.xml
messages = project.messages              # GET /projects/1/posts.xml
message  = message.first
comments = message.comments              # GET /posts/1/comments.xml
comment.update_attribute(:title,'name')  # PUT /comments/1.xml
Benjamin Sullivan
  • 1,466
  • 1
  • 12
  • 15