我有一些代码正在通过一组Rails Active Record模型,并根据2D数组中的相关值设置属性。
我基本上在美国国家的表格中设置美国州的缩写代码,该表格以前只存储全名。正在使用状态名称库来导出缩写,它包含一个2D数组,每个子数组都有一个全名和一个缩写(即[['New York', 'NY']['Pennsylvania', 'PA'][etc]]
)。我将数据库中每条记录的状态名称与此Array中的每个全文名称进行比较,然后在匹配时获取相应的兄弟Array单元格。
此代码工作正常,并产生正确的结果,但它看起来很邋and,如果不阅读很多行就不容易理解:
# For the following code, StatesWithNames is an Active Record model, which is
# having a new column :code added to its table.
# Sates::USA represents a 2D Array as: [['StateName', 'NY']], and is used to
# populate the codes for StatesWithNames.
# A comparison is made between StatesWithNames.name and the text name found in
# States::USA, and if there is a match, the abbreviation from States::USA is
# used
if StatesWithNames.any?
StatesWithNames.all.each do |named_state|
if named_state.code.blank?
States::USA.each do |s|
if s[0] == named_state.name
named_state.update_column(:code, s[1])
break
end
end
end
end
end
用这种逻辑表达赋值的最Ruby方式是什么?我尝试了几个不同的过程/块,但达到了更复杂的表达式或不正确的结果。是否有更简单的方法可以用更少的行和/或if-end
条件表达它?
答案 0 :(得分:2)
是的,有一些if
和支票,不需要。
因为它是Rails,即使它没有在问题的标签中说明,你可能想要使用find_each
,这是迭代AR集合的最有效方式之一:
StatesWithNames.find_each do |named_state|
next unless named_state.code.blank?
States::USA.each do |s|
named_state.update_column(:code, s[1]) if s[0] == named_state.name
end
end
另请注意,update_column
绕过任何验证,如果您希望保持对象有效,请坚持update!
。
最后一件事 - 将它全部包装在transaction中,所以如果一直出现任何问题 - 它会回滚任何更改。
StatesWithNames.transaction do
StatesWithNames.find_each do |named_state|
next unless named_state.code.blank?
States::USA.each do |s|
named_state.update!(:code, s[1]) if s[0] == named_state.name
end
end
end
答案 1 :(得分:1)
您可以为此使用不同的数据结构。
使用现有的2D数组,您可以在其上调用to_h
以获得Hash
其中
a = [['California', 'CA'], ['Oregon', 'OR']].to_h
=> { 'California' => 'CA', 'Oregon' => 'OR' }
然后在你的代码中你可以做
state_hash = States::USA.to_h
if StatesWithNames.any?
StatesWithNames.all.each do |named_state|
if named_state.code.blank?
abbreviation = state_hash[named_state.name]
if !abbreviation.nil?
named_state.update_column(:code, abbreviation)
end
end
end
end
答案 2 :(得分:0)
您要做的第一件事是将查找从数组数组转换为哈希。
state_hash = States::USA.to_h
if StatesWithNames.any?
StatesWithNames.all.select{|state| state.code.blank?}.each do |named_state|
named_state.update_column(:code, state_hash[named_state.name]) if state_hash[named_state.name]
end
end