【问题标题】:How to access block parameters using Object.send如何使用 Object.send 访问块参数
【发布时间】:2016-03-21 21:23:32
【问题描述】:

我正在尝试运行以下代码:

class RentLimit < ActiveRecord::Base
  def self.load_data
    rows = CSV.open("csvs/income_limits_2011_to_2015.csv").read
    rows.shift
    rows.each do |county, yr, date, _50pct_1br, _50pct_2br, _50pct_3br, _50pct_4br, _60pct_1br, _60pct_2br, _60pct_3br, _60pct_4br|
      [50, 60].each do |ami|
        [1, 2, 3, 4].each do |br|
          r = new
          r.county = county
          r.state = "SC"
          r.year = yr
          r.effective_date = Date.parse(date)
          r.pct_ami = ami
          r.br = br
          r.max_rent = self.send("_#{ami}pct_#{br}br".to_sym)
          r.save
        end#of brs
      end# of amis
    end# of rows
  end
end

但在尝试运行时收到此错误消息:

NoMethodError: undefined method `_50pct_1br' for #<Class:0x007fe942ce3b18>

send 方法无法访问范围内的那些块参数。有没有办法让send 访问块参数?如果没有,我还能如何动态访问块参数?

如何在 Ruby 中使用send 或其等效项来访问块参数?

【问题讨论】:

  • 我有点同意反对这个问题的人。整个编码方法都是废话。我最终只使用了 eval()。也投票关闭

标签: ruby csv


【解决方案1】:

如果您告诉CSV.open 您的列名是什么,这会容易得多。看起来您的 CSV 文件可能有一个标题行,您正在使用 rows.shift 跳过它,在这种情况下您不应该跳过它,并使用 headers: true 选项。然后您可以使用row["field_name"] 或在您的情况下使用row["_#{ami}pct_#{br}br"] 按名称访问每个字段:

CSV_PATH = "csvs/income_limits_2011_to_2015.csv"

DEFAULT_STATE = "SC"

def self.load_data
  CSV.open(CSV_PATH, 'r', headers: true) do |csv|
    csv.each do |row|
      max_rent = row["_#{ami}pct_#{br}br"]

      create(
        county: row["county"],
        state: DEFAULT_STATE,
        year: row["yr"],
        effective_date: Date.parse(row["date"]),
        pct_ami: ami,
        br: br,
        max_rent: max_rent,
      )
    end
  end
end

请注意,我使用带有块的CSV.open 来确保文件在读取后关闭,而您的原始代码没有这样做。我还使用了create 而不是new; ... save,因为后者是不必要的冗长。

如果您出于其他原因跳过第一行,或者您想使用标题行以外的字段名称,您可以设置选项return_headers: false, headers: names,其中names 是名称数组,例如:

CSV_HEADERS = %w[
  county yr date _50pct_1br _50pct_2br _50pct_3br _50pct_4br
  _60pct_1br _60pct_2br _60pct_3br _60pct_4br
].freeze

def self.load_data
  CSV.open(CSV_PATH, 'r', return_headers: false, headers: CSV_HEADERS) do |csv|
    # ...
  end
end

最后,由于您的某些属性对于创建的每个对象都是相同的,因此我会将它们移出循环:

def self.load_data
  base_attrs = { state: DEFAULT_STATE, pct_ami: ami, br: br }

  CSV.open(CSV_PATH, 'r', headers: true) do |csv|
    csv.each do |row|
      create(base_attrs.merge(
        county: row["county"],
        year: row["yr"],
        effective_date: row["date"],
        max_rent: row["_#{ami}pct_#{br}br"]
      ))
    end
  end
end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-05
    • 1970-01-01
    • 1970-01-01
    • 2020-05-30
    • 1970-01-01
    相关资源
    最近更新 更多