【问题标题】:Access Local variable in another method Ruby在另一种方法Ruby中访问局部变量
【发布时间】:2014-09-14 07:14:17
【问题描述】:

我希望了解如何访问方法 A 中设置的变量,然后在方法 B 中使用该变量,以及重用同一部分代码然后只更改查询的干净方法

require 'google/api_client'

module GoogleAnalytics
 class Analytic

 SERVICE_ACCOUNT_EMAIL_ADDRESS = ENV['SERVICE_ACCOUNT_EMAIL_ADDRESS']
 PATH_TO_KEY_FILE              = ENV['PATH_TO_KEY_FILE']
 PROFILE                       = ENV['ANALYTICS_PROFILE_ID']

def google_analytics_api

client  = Google::APIClient.new(
  application_name: "Example Application",
  application_version: "1.0")

client.authorization = Signet::OAuth2::Client.new(
  :token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
  :audience             => 'https://accounts.google.com/o/oauth2/token',
  :scope                => 'https://www.googleapis.com/auth/analytics.readonly',
  :issuer               => SERVICE_ACCOUNT_EMAIL_ADDRESS,
  :signing_key          => Google::APIClient::KeyUtils.load_from_pkcs12(PATH_TO_KEY_FILE, 'notasecret')).tap { |auth| auth.fetch_access_token! }

  api_method = client.discovered_api('analytics','v3').data.ga.get


  # make queries
  result = client.execute(:api_method => api_method, :parameters => {
  'ids'        => PROFILE,
  'start-date' => Date.new(2014,1,1).to_s,
  'end-date'   => Date.today.to_s,
  'dimensions' => 'ga:pagePath',
  'metrics'    => 'ga:pageviews',
  'filters'    => 'ga:pagePath==/'
 })
  end
 end
end

因此,如果我运行 google_analytics_api 方法,我会得到一组返回的结果,这些结果分配给变量 result

如果我想要另外 2 个单独的方法来返回不同的结果集怎么办,那么 新用户和跳出率,这将是改变请求参数的两个单独的调用,不是吗?我需要重复整个方法吗?

有没有办法对此进行重构,以便授权调用可以包含在其 on 方法中,而我所更改的只是分配给结果的请求参数?

像这样的

def api_call
  logic to make request
end

def new_users
  api_call
   # make queries
  result = client.execute(:api_method => api_method, :parameters => {
  'ids'        => PROFILE,
  'start-date' => Date.new(2014,1,1).to_s,
  'end-date'   => Date.today.to_s,
  'dimensions' => 'ga:pagePath',
  'metrics'    => 'ga:newUsers',
  'filters'    => 'ga:pagePath==/'
 })


end

虽然其中一个问题是局部变量 clientresult 在 new_users 方法中可用,但可以将它们更改为什么?带有@的实例变量?还是带有@@ 的类变量?

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-4 methods google-api


    【解决方案1】:

    通过 Skype 交谈,我认为有几件事值得关注


    初始化

    目前,您每次要使用该模块时都在使用google_analytics_api 方法。这是完全低效的,也是您现在遇到此问题的部分原因。相反,我会创建一个init 方法,每次您initialize the object 时都会触发该方法(并将GoogleAnalytics 变成一个自己的类):

    #lib/google_analytics.rb
    Class GoogleAnalytics
       def initialize
           ... google_analytics_api method here
       end
    end
    

    这将允许您将当前模块视为真正的 Ruby 对象 - 像这样:

    @analytics = GoogleAnalytics.new #-> fires initialize method
    

    这将使您能够调用对象(这将从 API 中提取数据),然后针对您拥有的不同用例相应地拆分该数据。


    实例方法

    这让我很好地理解了实例方法

    您所指的是,实际上Alex P 所指的是instance 方法的概念。这兼作对象的属性,但本质上允许您在方法的实例上调用一个功能。

    所以在亚历克斯的例子中,你有:

    def new_users
      get_result('ga:newUsers')
    end
    

    这只是调用你类的instance 方法:

    GoogleAnalytics::Analytic.new_users
    

    这将创建Analytic 类的实例,然后调用new_users 方法(应该是class method)。然后,此方法将允许您在新初始化的对象上调用 instance 方法,因此 get_result 方法调用

    --

    我的建议是在对象初始化之后使用instance methods,让您可以访问google_analytics_api定义的数据

    例如:

    #app/controllers/analyics_controller.rb
    Class AnalyticsController < ApplicationController
       def index
           @analytics = GoogleAnalytics.new
           @new_users = @analytics.new_users
       end
    end
    
    #lib/google_analytics.rb
    Class GoogleAnalytics
       def initialize
           ... google_analytics_api method here
       end
    
       def new_users
          return [new_users_data]
       end
    end
    

    对此的一个警告是这是否可以在没有模块的情况下工作。我认为应该,但它对我来说未经测试

    【讨论】:

      【解决方案2】:

      你的直觉很好——你don't want to repeat yourself,并且有更好的方法来构建这段代码。但与其共享变量,您应该考虑松散连接的小块。编写能做好一件事的方法,并将它们组合在一起。例如,我们可以编写一个 get_client 方法,它只返回一个 client 以供其他方法使用:

      protected
      def get_client
        client  = Google::APIClient.new(
          application_name: "Example Application",
          application_version: "1.0")
      
        client.authorization = Signet::OAuth2::Client.new(
          :token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
          :audience             => 'https://accounts.google.com/o/oauth2/token',
          :scope                => 'https://www.googleapis.com/auth/analytics.readonly',
          :issuer               => SERVICE_ACCOUNT_EMAIL_ADDRESS,
          :signing_key          => Google::APIClient::KeyUtils.load_from_pkcs12(PATH_TO_KEY_FILE, 'notasecret')).tap { |auth| auth.fetch_access_token! }
        client
      end
      

      它是protected,因为外部代码——在你的Analytic 类之外的东西——不应该直接使用它。他们应该使用我们为他们提供的方法。


      您还可以提供从 API 获取结果的辅助方法。我不熟悉查询 API,但看起来是您的 metrics 值发生了变化。所以也许是这样的:

      protected
      def get_result(metrics)
        client = self.get_client
        api_method = client.discovered_api('analytics','v3').data.ga.get
      
        result = client.execute(:api_method => api_method, :parameters => {
          'ids'        => PROFILE,
          'start-date' => Date.new(2014,1,1).to_s,
          'end-date'   => Date.today.to_s,
          'dimensions' => 'ga:pagePath',
          'metrics'    => metrics,
          'filters'    => 'ga:pagePath==/'
         })
        result
      end
      

      现在您可以编写外部类可以使用的简单方法:

      def new_users
        get_result('ga:newUsers')
      end
      
      def total_visits
        get_result('ga:pageViews')
      end
      

      如果可以,请尝试从这些方法返回简单数据。也许total_visits 会返回get_result('ga:pageViews')['totalsForAllResults']['ga:pageviews']。课堂外的代码不必了解 GA 数据格式即可使用它。这称为encapsulation

      【讨论】:

      • 这是一个很好的答案,解释得很好,虽然我不确定的一件事是 get_result 中的调用.....client = self.get_client...这是在做什么?我只在模型类中使用过 self
      • 它只是调用get_client 方法,它返回一个client 供该方法使用。您也可以将该行写为client = get_clientclient = get_client()
      • 非常感谢,当您可以从答案中学到很多东西时,总是很棒
      猜你喜欢
      • 1970-01-01
      • 2020-02-20
      • 2019-07-31
      • 1970-01-01
      • 1970-01-01
      • 2016-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多