Rails simple_form_for报undefined method `map' for Contact错误
报错修复:
undefined method 'map' for #<Contact:0x000000013aa76b48> 错误根因
map是Ruby可枚举类型(数组、ActiveRecord关系集合等)的实例方法,报错说明你调用.map的@contacts变量是单个Contact模型实例,不是可遍历的集合对象。
代码问题定位
- 控制器
new动作赋值错误:@contacts = Contact.new生成的是单个空Contact对象,不是联系人集合,访问/new路径渲染表单时必然触发该错误 - 视图ERB标签语法错误:
f.association、f.submit代码块使用了<% %>执行标签,没有加=号,代码会执行但不会渲染DOM元素,下拉框和提交按钮不会显示在页面上 - 业务逻辑漏洞:
create动作用HistContact.find做新建逻辑,find方法是按主键查询已有记录,完全不符合新建场景;自定义的contactID权限过滤方法从未被调用,没有做当前用户的数据范围限制 - 视图语法错误:表格的fecha表头标签未闭合,存在HTML语法问题
修复方案
1. 修正控制器代码
class HistContactController < ApplicationController before_action :authenticate_user! def index @histcontacts = HistContact.all @histcontact = HistContact.new # 调用权限过滤方法取当前用户可见的联系人集合 @contacts = contactID(current_user) end def new @histcontact = HistContact.new # 修复:赋值为联系人集合,不是单条new对象 @contacts = contactID(current_user) end def create # 修复:新建记录用new方法,simple_form提交的参数默认嵌套在模型名key下 @histcontact = HistContact.new(contact_id: params[:hist_contact][:contact_id]) if @histcontact.save redirect_to hist_contact_index_path, notice: "查询成功" else @contacts = contactID(current_user) render :index end end private def contactID(current_user) client = Client.find_by(user_id: current_user.id) # 兼容当前用户无关联客户的场景,避免空值报错 return Contact.none if client.blank? Contact.where(client_id: client.id) end end
2. 修正视图代码
<h1>HistContact#index</h1> <p>Find me in app/views/hist_contact/index.html.erb</p> <%= simple_form_for @histcontact, url: hist_contact_index_path do |f| %> <%# 补全ERB输出标签的等号,用pluck替代map减少内存占用 %> <%= f.association :contact, collection: @contacts.pluck(:name, :id), prompt: "请选择联系人" %> <%= f.submit "buscar" %> <% end %> <table id="client_table" class="table table-striped table-sm"> <thead> <tr> <th>Id</th> <th>fecha</th> </tr> </thead> <tbody> <% @histcontacts.each do |c|%> <tr> <td><%= c.id %></td> <td><%= c.created_at %></td> </tr> <% end %> </tbody> </table>
优化提示
- 集合取指定字段做下拉选项时,优先用
pluck(:字段1, :字段2)替代手写map,pluck会直接生成查询指定字段的SQL,不会把全量记录实例化成模型对象,性能更好 - Simple Form的
association辅助方法默认会自动加载关联模型的集合,只要给Contact模型定义to_s方法返回name字段值,甚至可以不用手动传collection参数,直接写<%= f.association :contact %>就能生成符合要求的下拉框
内容的提问来源于stack exchange,提问作者Juan Pablo Grover Pinto
相关产品推荐
相关产品推荐

