【问题标题】:Ruby/Rails: create a custom block/yield for http requests to avoid repetitionRuby/Rails:为 http 请求创建自定义块/yield 以避免重复
【发布时间】:2021-08-02 18:10:11
【问题描述】:

我想避免在我的代码中复制/粘贴过多的 http 请求,因此我尝试创建以下内容:

post "#{URL}/api/v1/notify" do
  header 'Content-Type', 'application/json'
  header 'Authorization', "Bearer 123456"

  success do
    # what to do in case of success
  end

  error do |e|
    # what to do in case of error
  end
end

但到目前为止,我无法创建所需的 post 方法

def post(url, &block)
  puts "post"
 
  url = URI("#{URL}/api/v1/notify")
  http = Net::HTTP.new(url.host, url.port)
  http.use_ssl = url.instance_of?(URI::HTTPS)

  request = Net::HTTP::Post.new(url) # or GET
  request['Content-Type'] = #header content type
  request['Authorization'] = #header bearer
  response = http.request(request)

 response.success? ? success : failure
end

def success(&block)
  puts "success"
  yield
end

def error(&block)
  puts "error"
  yield
end

该方法应该替换在各处多次使用的以下代码:

url = URI("#{URL}/api/v1/notify")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = url.instance_of?(URI::HTTPS)

request = Net::HTTP::Post.new(url) # or GET
request['Content-Type'] = 'application/json'
request['Authorization'] = "Bearer 123456"
response = http.request(request)

if response.code == '200'
  #success
else
  #failure
end

【问题讨论】:

    标签: ruby-on-rails ruby block yield


    【解决方案1】:

    您可以围绕此构建自己的 DSL:

    class Client
      def self.post(&block)
        dsl = Dsl.new
        dsl.instance_eval(&block)
    
        # build request with data from dsl calls
        # and execute request
        puts "Making a request to #{dsl.url} with headers #{dsl.headers}"
        response = "response" # this would be your http response
        if rand > 0.5 # response.success?
          dsl.on_success.call(response) if dsl.on_success
        else
          dsl.on_error.call(response) if dsl.on_error
        end
      end
    
    end
    
    class Dsl
      def initialize
        @headers = {}
      end
    
      def url(*values)
        return @url if values.length == 0
    
        @url = values[0]
      end
    
      def headers
        @headers.freeze
      end
    
      def header(*values)
        return @headers[values.first] if values.length == 1
    
        @headers[values[0]] = values[1]
      end
    
      def on_success(&block)
        return @on_success if !block
    
        @on_success = block
      end
    
      def on_error(&block)
        return @on_error if !block
    
        @on_error = block
      end
    end
    
    
    
    Client.post do |client|
      url "http://somewhere"
      header "Kwazy", "Cupcakes"
      on_success do |response|
        puts "got #{response} which is a success"
      end
    
      on_error do |response|
        puts "gor #{response} which is an error"
      end
    end
    

    显然,如果您通过可变参数长度调用 getter/setter 的区别有点特殊,也可以通过使用真实的 setter 名称(url=,...)或使用不同的 getter 名称(@ 987654324@)

    有些特殊的部分是instance_eval(block)。它允许更改self,以便post 块内的方法的接收者不是Client,而是Dsl 实例。

    这可能会导致麻烦,并使调试更加困难。所以你也可以

    yield(dsl),然后将 dsl 作为参数传递给块。

    Client.post do |dsl|
      dsl.url "http://somewhere"
      #...
    end
    

    更新:

    Stefans 的提议听起来也不错。我认为他的意思是这样的(或查看他在 cmets 中的链接):

    class DslData
      attr_accessor :url
    end
    
    
    class Dsl
      attr_reader :dsl_data
      def initialize
        @dsl_data = DslData.new
      end 
    
      def url(value)
        dsl_data.url = value
      end
    end
    
    class Client
      def self.post
        dsl = Dsl.new
        dsl.instance_eval(&block)
        puts "Url: #{dsl.dsl_data.url}"
      end
    end
    

    【讨论】:

    • 您可以通过使用两个类来避免组合的 getter / setter 逻辑:DslDataattr_accessor :header, :on_success, :on_errorDsl 作为包装器,仅证明 DSL setter,例如def header(key, value) ; @data.headers[key] = value ; end.
    • @Stefan 你能举个例子吗?谢谢。
    • @Yassine 像这样:gist.github.com/sos4nt/ea681c2bc254b78e531877dd5287c8a5 - 请注意 post 仅与 DslData 一起使用,Dsl 类仅用作块评估的临时上下文。 (它甚至没有分配给变量)
    猜你喜欢
    • 2016-01-26
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 2017-03-11
    • 1970-01-01
    • 1970-01-01
    • 2019-10-31
    相关资源
    最近更新 更多