我试图运行以下代码:
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
块参数的访问权限?如果没有,我还可以动态访问块参数吗?
如何使用send
或其等价物来访问Ruby中的块参数?
答案 0 :(得分:0)
如果您告诉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