Ruby on Rails:未初始化的常量

时间:2018-05-03 14:11:50

标签: ruby-on-rails

我有一个关于在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

1 个答案:

答案 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.parseresponse.executeGoogle::Calendar::ListService.call(current_user: current_user)以外的任何内容。