如何使此方法更有效?

时间:2014-09-23 03:53:57

标签: ruby-on-rails ruby

我已经编写了一个帮助方法,可以将街道地址中的城市转换为相应的FIPS Place代码:

def place_fips
    place_fips = 'PLACE:' + Place.where(statename: @address.state, placeshort: @address.city ).first.placefp
end

我现在想要使用" place_fips"在其他几种获取城市人口统计数据的方法中:

def city_pop_tot
    str = @census.where({ fields: 'P0030001', level: place_fips })[0]["P0030001"].to_i
end

我目前有大约七种city_pop_foo方法(每种种类一种 - 例如city_pop_whitecity_pop_blackcity_pop_asian等。

所有的工作都很好,但响应时间过长,因为每次遇到place_fips方法之一时它都会运行city_pop_foo查询。有没有办法定义place_fips一次,并在后续方法中使用它而不是每次都从数据库中取出它?

此外,我怀疑还有一种方法 - 而不是使用多个def city_pop_foo方法 - 干掉这段代码并只定义def city_pop一次,然后传入将改变{{1}的参数在P00####查询中(所以我可以在我的观看中写出@census.where<%= city_pop(white) %><%= city_pop(black) %>等内容。我在这里走在正确的轨道上吗?这可能是什么样的?

1 个答案:

答案 0 :(得分:0)

这方面的一个方法是记忆。请考虑以下示例:

class Greeter
  def greet
    puts greeting
  end

  def greeting
    compute_greeting
  end

  private

  def compute_greeting
    sleep 3 # heavy lifting
    "Hello, world!"
  end
end

greeter = Greeter.new
greeter.greet          # takes ~3 seconds
greeter.greet          # takes ~3 seconds as well
greeter.greet          # takes ~3 seconds as well

现在要解决这个问题,你可以使用一个名为方法的实例变量和||=的条件赋值,它只会设置变量nil,否则返回保存的版本:

class Greeter
  def greet
    puts greeting
  end

  def greeting
    @greeting ||= compute_greeting
  end

  private

  def compute_greeting
    sleep 3 # heavy lifting
    "Hello, world!"
  end
end

greeter = Greeter.new
greeter.greet          # takes ~3 seconds
greeter.greet          # runs instantly
greeter.greet          # runs instantly

当然,如果缓存的内容以任何方式依赖于对象的状态,则需要在状态发生变化时进行内务处理。以下代码被破坏,例如:

class PersonalGreeter
  attr_accessor :name

  def initialize(name)
    @name = name
  end

  def greet
    puts greeting
  end

  def greeting
    @greeting ||= compute_greeting
  end

  private

  def compute_greeting
    sleep 3 # heavy lifting
    "Hello, #{name}!"
  end
end

greeter = PersonalGreeter.new('Sergio Hernandez')
greeter.greet # Hello, Sergio Hernandez!
greeter.name = 'Zaphod Beeblebrox'
greeter.greet # Hello, Sergio Hernandez!

因此,只要名称发生变化,您就需要清除缓存/记忆的问候语:

class PersonalGreeter
  attr_reader :name

  def initialize(name)
    @name = name
  end

  def name=(new_name)
    @greeting = nil
    @name = new_name
  end

  def greet
    puts greeting
  end

  def greeting
    @greeting ||= compute_greeting
  end

  private

  def compute_greeting
    sleep 3 # heavy lifting
    "Hello, #{name}!"
  end
end

greeter = PersonalGreeter.new('Sergio Hernandez')
greeter.greet # Hello, Sergio Hernandez!
greeter.name = 'Zaphod Beeblebrox'
greeter.greet # Hello, Zaphod Beeblebrox!

这只是一个简单的例子,已经相当复杂。正如您可以想象的那样,这很快就会失控,因此请务必谨慎使用备忘录,只能在有实际利益的地方使用。