【问题标题】:Embedded Ruby: Array.each "No method" error嵌入式 Ruby:Array.each “无方法”错误
【发布时间】:2016-02-29 03:19:46
【问题描述】:

在我的助手中,我从数据库中生成一个哈希。哈希包含每个州的键,其值包含城市数组。每个城市条目本身就是一个数组,带有名称和 ID。

例如(此代码只是一个说明):

myHash[key => MD, value=>[ ['Annapolis',1],['Potomac',2] ] ]

这是产生哈希的实际代码:

def get_city_hash
  stateHash = Hash.new
  City.all.each do |c|
    if !stateHash.include? c.stateab
      stateHash[c.stateab] = Array.new
    end
    stateHash[c.stateab] << [c.name, c.id]
  end
end

问题是当我尝试在 javascript 中创建一个对应的关联数组时,似乎我的每个城市的 Array 对象都没有 .each 方法(为了减少混乱,去掉了中间的代码)

  var city_array = [
  <% get_city_hash.each do |key, value|%>
    <%value.each do |v|%>
    <%end%>
 <%end%>

对于此代码,我在包含 value.each 的行上收到此错误:

nil:NilClass 的未定义方法 `each'

我在帮助程序中的状态数组上测试了一个 .each,它运行良好。我得到 NilClass 的这种格式有什么变化?

【问题讨论】:

  • 您能否确认 get_city_hash 确实返回 stateHash(看起来应该返回,但您可以在 City.all 循环结束后添加一个额外的 stateHash 以确保绝对确定!)跨度>

标签: javascript ruby-on-rails arrays ruby


【解决方案1】:

你有两个问题。

问题 #1

您的get_city_hash 方法不返回cityHash,它返回each 的结果,这将是您调用它的Enumerable(即City.all 的结果)。这不是哈希,所以当你调用 each 时,只有一个参数被传递到块中,第二个参数 c 始终是 nil

除此之外,该方法还有很大的改进空间。首先,不用if !stateHash.include? 业务,只需给你的Hash 一个默认值:

def get_city_hash
  state_hash = Hash.new {|h,k| h[k] = [] }

  City.select(:id, :stateab, :name).all.each do |c|
    state_hash[c.stateab] << [c.name, c.id]
  end

  state_hash
end

我还添加了select,因为您永远不应该从数据库中检索您不会使用的列。

但我们可以使用each_with_object 进行更多清理:

def get_city_hash
  city_hash = Hash.new {|h,k| h[k] = [] }

  City.select(:id, :stateab, :name).all
    .each_with_object(Hash.new([])) do |city, city_hash|
      city_hash[city.stateab] << city.values_at(:name, :id)
    end
end

或者我们可以这样做,这可能有点过于“聪明”,但我仍然很偏爱。

def get_city_hash
  City.all.pluck(:stateab, :name, :id)
    .group_by(&:shift)
end

问题 #2

在您看来,您正在尝试生成 JavaScript 代码,这绝不是一个好主意。您应该始终让 Rails 为您生成有效的 JSON:

var cities = <%= raw get_city_hash.to_json %>;

【讨论】:

  • 对于问题 #2,我非常倾向于使用 gon 将东西从 Rails 控制器传递到视图中的 javascript。
  • 哇,非常感谢。但是您能否为第一个问题的后两个解决方案提供更多解释?结构对我来说有点陌生,几周前刚开始使用 Rails,很高兴扩大我的武器库。
  • 我尝试了您的一些解决方案。我很感激你的回答,但也许你忽略了我在 city_hash 方法中将值插入到数组中,所以我需要一个 if 语句来检查一个是否已经存在。我尝试了您发布的代码,但没有成功。此外,to_json 建议在我的 javascript 中给了我一些奇怪的 ruby​​ 乱码。有没有可能你遗漏了一部分代码?
  • 我已编辑我的答案以正确使用默认过程(Hash.new {|h,k| h[k] = [] } 而不是Hash.new([]))。如果没有看到它,我无法诊断出“奇怪的 Ruby 乱码”。您可能必须使用raw 方法来防止Rails 转义JSON。我已经编辑了我的答案以包括这一点。
【解决方案2】:

我认为,您定义了一个名为“get_city_hash”的辅助方法,并在视图中调用了“get_city_array”。将“get_city_array”改为“get_city_hash”

【讨论】:

  • 对不起,这是问题中的错字。我会解决的。
【解决方案3】:

你可以试试:

 <% get_city_hash.each do |key, value|%>
    <% unless value.blank? %>
     <%value.each do |v|%>

     <%end%>
    <% end%>
 <%end%>

或者您可以尝试使用 compact get_city_hash.compact.each 从哈希 value 中删除 nil

rails 4.1 compact 阅读:http://api.rubyonrails.org/classes/Hash.html#method-i-compact

     <% get_city_hash.compact.each do |key, value|%>
     <%value.each do |v|%>

     <%end%>
   <%end%>

【讨论】:

    【解决方案4】:

    这教会了我们依赖 Ruby 超级简洁的公式的教训...

    我的辅助方法返回了一些索引值,而不是我创建的实际哈希值!

    【讨论】:

    • 查看我的答案以获得解释。这与 Ruby 的简洁性无关,而是 Enumerable#each 返回其被调用者这一事实。
    猜你喜欢
    • 1970-01-01
    • 2017-09-27
    • 1970-01-01
    • 1970-01-01
    • 2021-11-11
    • 2012-02-11
    • 1970-01-01
    • 2019-06-19
    • 2020-10-09
    相关资源
    最近更新 更多