我有一个关于在Ruby on Rails项目中从控制器访问自定义类的问题。
我正在关注这个tutorial关于将Google Calendar API与我的Rails应用程序集成,本节的一部分是创建GoogleCalendarWrapper
。我在lib/google_cal_wrapper.rb
创建了这个文件,但是我收到错误:
uninitialized constant EventsController::GoogleCalWrapper
以下是events_controller
def index
if user_signed_in?
@event = current_user.posts.build
@calendar = GoogleCalWrapper.new(current_user)
# response = @client.execute(api_method: @service.calendar_list.list)
# calendars = JSON.parse(response.body)
# puts(calendars)
# @places = Classroom.all.map { |x| x.name }
else
@event = Event.new
end
end
-
#lib/google_cal_wrapper.rb
class GoogleCalWrapper
def initialize(current_user)
configure_client(current_user)
end
def configure_client(current_user)
@client = Google::APIClient.new
@client.authorization.access_token = current_user.token
@client.authorization.refresh_token = current_user.refresh_token
puts @client.authorization.refresh_token
@client.authorization.client_id = ENV['GOOGLE_KEY']
@client.authorization.client_secret = ENV['GOOGLE_SECRET']
@client.authorization.refresh!
@service = @client.discovered_api('calendar', 'v3')
end
end
- 一些额外信息:
`
#omniauth_callbacks_controller.rb
def google_oauth2
@user = User.from_omniauth(request.env["omniauth.auth"])
if @user.persisted?
sign_in_and_redirect @user
else
session["devise.google_data"] = request.env["omniauth.auth"].except("extra")
redirect_to root_path
end
end
#user.rb
def self.from_omniauth(auth)
user = where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.email = auth.info.email
user.first_name = auth.info.first_name
user.last_name = auth.info.last_name
user.avatar = auth.info.image # assuming the user model has an image
end
user.token = auth.credentials.token
user.refresh_token = auth.credentials.refresh_token
if user.valid?
puts "#{user} saved"
else
puts user.errors.full_messages
end
return user
end
答案 0 :(得分:1)
我并不特别喜欢这个班级的Wrapper
这个名字,但是,嘿,这不是重点。
如果我是你,我会在wrappers
下放一个app
文件夹,然后将google_cal_wrapper.rb
放在该文件夹中。所以你最终得到:
app
|- assets
|- controllers
|- ...
|- wrappers
|- google_cal_wrapper.rb
这样它应该自动加载并在控制器中可用,只需GoogleCalWrapper
。
BTW,在我使用google-api-client
(以及其他api客户端)的项目中,我将这些事称为services
,我的目录结构看起来像(自然地,替换app_name
}和AppName
以及我用于当前应用的实际名称):
app
|- assets
|- controllers
|- ...
|- services
| |- app_name
| | |- service_base.rb
| |- google
| | |- calendar
| | | |- list_service.rb
| | |- calendar_service.rb
| | |- client_service.rb
| | |- service_base.rb
| |- quickbooks
| | |- consumer_service.rb
| | |- service_base.rb
| |- ...
|- ...
我的课程看起来像:
class AppName::ServiceBase
attr_accessor *%w(
args
).freeze
# allows you to call Google::Service.call(current_user: current_user)
# without having to do Google::Service.new(current_user: current_user)
# which I prefer.
class << self
def call(args={})
new(args).call
end
end # Class Methods
#==================================================================================
# Instance Methods
#==================================================================================
def initialize(args={})
@args = args
assign_args
end
private
# creates an attr_accessor for each k,v pair in args. So,
# for instance, when called like
# Google::Service.call(current_user: current_user),
# the new service instance will have a method called
# 'current_user' that returns the current_user
def assign_args
args.each do |k,v|
class_eval do
attr_accessor k
end
send("#{k}=",v)
end
end
end
Google类的基类:
class Google::ServiceBase < AppName::ServiceBase
private
def client
@client ||= Google::ClientService.call(current_user: current_user)
end
def calendar_service
@calendar_service ||= Google::CalendarService.call(current_user: current_user)
end
end
配置calendar_service
的类class Google::CalendarService < Google::ServiceBase
#==================================================================================
# Instance Methods
#==================================================================================
def call
client.discovered_api('calendar', 'v3')
end
end
配置Google客户端的类
class Google::ClientService < Google::ServiceBase
delegate *%w(
token
refresh_token
), to: :current_user
#==================================================================================
# Instance Methods
#==================================================================================
def call
[
:token,
:refresh_token,
:client_id
:client_secret
].each do |client_attribute|
client.authorization.send("#{client_attribute}=", send(client_attribute))
end
client.authorization.refresh!
client
end
private
def client
@client ||= Google::APIClient.new
end
def client_id
ENV['GOOGLE_CLIENT_ID']
end
def client_secret
ENV['GOOGLE_CLIENT_SECRET']
end
end
抓住calendars_list
的课程class Google::Calendar::ListService < Google::ServiceBase
#==================================================================================
# Instance Methods
#==================================================================================
def call
# do some stuff like you have commented out in your controller
# like (naturally, insert code that actually works):
calendar_service.calendar_list.list
end
end
所以你可以在你的controller
中做点什么:
def index
if user_signed_in?
@event = current_user.posts.build
@calendar_list = Google::Calendar::ListService.call(current_user: current_user)
else
@event = Event.new
end
end
现在,您的控制器无需了解JSON.parse
或response
或.execute
或Google::Calendar::ListService.call(current_user: current_user)
以外的任何内容。