Ruby on rails Rails中的RESTAPI帮助
我正试图通过GEM使用我们的会计软件包(FreeAgentCentral)和他们的API发布一些信息Ruby on rails Rails中的RESTAPI帮助,ruby-on-rails,api,rest,Ruby On Rails,Api,Rest,我正试图通过GEM使用我们的会计软件包(FreeAgentCentral)和他们的API发布一些信息 http://github.com/aaronrussell/freeagent_api/ 我有以下代码来让它工作(假设): Kase控制器 def create @kase = Kase.new(params[:kase]) @company = Company.find(params[:kase][:company_id]) @kase = @company.kas
http://github.com/aaronrussell/freeagent_api/
我有以下代码来让它工作(假设):
Kase控制器
def create
@kase = Kase.new(params[:kase])
@company = Company.find(params[:kase][:company_id])
@kase = @company.kases.create!(params[:kase])
respond_to do |format|
if @kase.save
UserMailer.deliver_makeakase("dropbox@12808311.macandco.highrisehq.com", "Highrise", @kase)
@kase.create_freeagent_project(current_user)
#flash[:notice] = 'Case was successfully created.'
flash[:notice] = fading_flash_message("Case was successfully created & sent to Highrise.", 5)
format.html { redirect_to(@kase) }
format.xml { render :xml => @kase, :status => :created, :location => @kase }
else
format.html { render :action => "new" }
format.xml { render :xml => @kase.errors, :status => :unprocessable_entity }
end
end
end
为了节省您的时间,重要的部分是:
@kase.create_freeagent_project(current_user)
Kase型号
# FreeAgent API Project Create
# Required attribues
# :contact_id
# :name
# :payment_term_in_days
# :billing_basis # must be 1, 7, 7.5, or 8
# :budget_units # must be Hours, Days, or Monetary
# :status # must be Active or Completed
def create_freeagent_project(current_user)
p = Freeagent::Project.create(
:contact_id => 0,
:name => "#{jobno} - #{highrisesubject}",
:payment_terms_in_days => 5,
:billing_basis => 1,
:budget_units => 'Hours',
:status => 'Active'
)
user = Freeagent::User.find_by_email(current_user.email)
Freeagent::Timeslip.create(
:project_id => p.id,
:user_id => user.id,
:hours => 1,
:new_task => 'Setup',
:dated_on => Time.now
)
end
lib/freeagent\u api.rb
require 'rubygems'
gem 'activeresource', '< 3.0.0.beta1'
require 'active_resource'
module Freeagent
class << self
def authenticate(options)
Base.authenticate(options)
end
end
class Error < StandardError; end
class Base < ActiveResource::Base
def self.authenticate(options)
self.site = "https://#{options[:domain]}"
self.user = options[:username]
self.password = options[:password]
end
end
# Company
class Company
def self.invoice_timeline
InvoiceTimeline.find :all, :from => '/company/invoice_timeline.xml'
end
def self.tax_timeline
TaxTimeline.find :all, :from => '/company/tax_timeline.xml'
end
end
class InvoiceTimeline < Base
self.prefix = '/company/'
end
class TaxTimeline < Base
self.prefix = '/company/'
end
# Contacts
class Contact < Base
end
# Projects
class Project < Base
def invoices
Invoice.find :all, :from => "/projects/#{id}/invoices.xml"
end
def timeslips
Timeslip.find :all, :from => "/projects/#{id}/timeslips.xml"
end
end
# Tasks - Complete
class Task < Base
self.prefix = '/projects/:project_id/'
end
# Invoices - Complete
class Invoice < Base
def mark_as_draft
connection.put("/invoices/#{id}/mark_as_draft.xml", encode, self.class.headers).tap do |response|
load_attributes_from_response(response)
end
end
def mark_as_sent
connection.put("/invoices/#{id}/mark_as_sent.xml", encode, self.class.headers).tap do |response|
load_attributes_from_response(response)
end
end
def mark_as_cancelled
connection.put("/invoices/#{id}/mark_as_cancelled.xml", encode, self.class.headers).tap do |response|
load_attributes_from_response(response)
end
end
end
# Invoice items - Complete
class InvoiceItem < Base
self.prefix = '/invoices/:invoice_id/'
end
# Timeslips
class Timeslip < Base
def self.find(*arguments)
scope = arguments.slice!(0)
options = arguments.slice!(0) || {}
if options[:params] && options[:params][:from] && options[:params][:to]
options[:params][:view] = options[:params][:from]+'_'+options[:params][:to]
options[:params].delete(:from)
options[:params].delete(:to)
end
case scope
when :all then find_every(options)
when :first then find_every(options).first
when :last then find_every(options).last
when :one then find_one(options)
else find_single(scope, options)
end
end
end
# Users
class User < Base
self.prefix = '/company/'
def self.find_by_email(email)
users = User.find :all
users.each do |u|
u.email == email ? (return u) : next
end
raise Error, "No user matches that email!"
end
end
end
Freeagent.authenticate({
:domain => 'XXXXX.freeagentcentral.com',
:username => 'XXXX@XXXXXXX.co.uk',
:password => 'XXXXXX'
})
在尝试创建新案例并将详细信息发送给FreeAgent时,上述操作会导致以下错误:
ActiveResource::ResourceNotFound in KasesController#create
Failed with 404 Not Found
及
如果有人能解释这个问题,我们将不胜感激
谢谢
丹尼你怎么称呼他?对于普通的restful创建操作,它可能是来自表单或其他内容的POST,但404通常是从失败的GET操作中呈现的,其中ActiveRecord find无法找到具有特定id的记录。我的最佳猜测是,您正在使用GET调用create,并且
user = Freeagent::User.find_by_email(current_user.email)
根本无法找到带有该电子邮件的用户,因此引发ResourceNotFound异常
此外,这段代码让我感到困惑:
@kase = Kase.new(params[:kase])
@company = Company.find(params[:kase][:company_id])
@kase = @company.kases.create!(params[:kase])
respond_to do |format|
if @kase.save
你为什么在这里两次创建@kase,一次是用kase.new,一次是用kase.create?另外,请注意该行:
if @kase.save
@company.kases.create!(params[:kase])
将始终计算为true,因为行:
if @kase.save
@company.kases.create!(params[:kase])
如果它为false,则会引发异常,这是另一种说法@kase.save是多余的,因为create!已经保持了Kase的新记录了
编辑:我认为你的意思是:
# this line can go @kase = Kase.new(params[:kase])
@company = Company.find(params[:kase][:company_id])
@kase = @company.kases.build(params[:kase])
编辑:您可能需要这样的新操作:
def new
@kase = Kase.new # no params here
end
“新”erb模板将有一个表单_,用于以下内容:
<% form_for @kase do |k| %>
默认情况下,该表单将把表单中的参数发布到create操作,假设您在路由中设置了类似resources:kase的内容。这应该让你开始。像你正在做的那样遵循标准教程,事情应该会变得更简单 我已双重/三重检查当前用户的电子邮件地址是否与freeagent的电子邮件地址匹配。ResourceNotFound异常是否还有其他原因?我需要看看你关于kase create的第二条评论,我认为你是对的!谢谢,丹尼,这是我能看到的唯一一条可能找不到的线。可能是某些空格符导致查找失败?在find_by_电子邮件之后添加一些输出,以确保您找到了用户。然后查看要验证的服务器输出。此外,使用GET创建新资源被认为是错误的restful形式。你可以考虑把它改为POST。GET不仅使意外创建新记录变得容易,而且404在创建新记录的上下文中没有意义。我目前正在寻找一些关于这方面的教程,因为我已经设法将自己与GET混淆,而POST-API总是让我混淆!谢谢你的帮助!如果您在使用“资源”约定声明路由时以标准方式使用new/create操作,Rails将使其变得非常简单。带有新模型的表单在默认情况下将使用POST等。遵循Rails的标准教程,您就可以了。