【问题标题】:undefined method `name' for ["Yes", true]:Array["Yes", true]:Array 的未定义方法“名称”
【发布时间】:2012-11-22 21:21:47
【问题描述】:

我实际上不知道 Array ["Yes",true] 来自哪里。我有两个这样的模型:

GeneralExam has_many topic_questions

TopicQuestion belongs to general_exam, belongs_to topic

在 TopicQuestion 中,我有列:general_exam_id、topic_id、number_question,用于存储一般考试中每个主题的编号问题。

我为创建新的普通考试构建了一个嵌套表单,在表单上我构建了一个动态选择,当用户从下拉列表中选择一门课程时,我还有其他下拉列表来显示用户选择的课程主题。

这是我用于动态选择的 javascript 代码:

<% content_for :head do %>
  <script type="text/javascript">
    $(document).ready(function() {
      $('#general_exam_course_id').change(function () {
        $.ajax({
          type: "POST",
          url: "<%= update_topics_general_exams_path %>",
          data: { course_id: $('#general_exam_course_id').val() },
          dataType: "script"
        });
      });
    </script>
<% end %>

#general_exam_course_id 是选择课程下拉列表的IDupdate_topics_general_exams_path 是我在普通考试控制器中的update 操作的路由,这是我的update 操作:

  def update_topics
    @course = Course.find(params[:course_id])
    @topics = @course.topics
  end

我还有一个update_topics.js.erb

$('div#topic_questions select').html("<%= j options_from_collection_for_select(@topics, 'id', 'name') %>");

div#topic_questions 中的下拉列表将从update_topics 操作(我认为是这样)获得@topics 值并显示它。当我创建新的普通考试时,没关系。但是当我按下Edit 链接时,它会显示一个错误,我不知道它为什么以及它来自哪里:

NoMethodError in General_exams#edit
undefined method `name' for ["Yes", true]:Array

Extracted source (around line #3):

1: <div class="row">
2:  <div class="span6"><%= remove_child_link "Remove below topic", f %></div><br><br>
3:  <div class="span3"><%= f.association :topic, collection: @topics, label_method: :name, value_method: :id, prompt: "Choose a topic", label: false %></div>
4:  <%= f.input :number_question, placeholder: 'Number of questions', label: false, style: 'display: inline' %>
5: </div>

我的edit 操作只有:@general_exam = GeneralExam.find(params[:id])。我不知道为什么topic 普通考试的关联字段显示一个 Array ["Yes", true]。我没有,在什么地方都没有定义,为什么我编辑通用考试时会出现?

更新

如果我删除 label_method: :name, value_method: :id

<%= f.association :topic, collection: @topics, label_method: :name, value_method: :id, prompt: "Choose a topic", label: false %>

页面没有错误,但下拉列表在选择中具有值Yes, No,而不是我为考试创建的主题名称。表单可以获取每个主题的题数,但是不能获取主题的名称。

当我创建时:

当我编辑时:

我在config/locales/simple_form.en.yml

en:
  simple_form:
    "yes": 'Yes'
    "no": 'No'

这是个问题吗?

更新:不要在新操作中传递@topics,但它仍然存在于新页面上当尚未选择课程时

我的新动作:

  def new
    @general_exam = GeneralExam.new
    5.times { @general_exam.topic_questions.build }
    #@topics = Topic.all
  end

在我上面的提取源中,我有以下新代码,也可以编辑(使用相同的形式):

<%= f.association :topic, collection: @topics, label_method: :name, value_method: :id, prompt: "Choose a topic", label: false %>

所以我没有通过@topics,但是当我转到新页面时,主题的下拉列表仍然显示Yes, No 值。

【问题讨论】:

  • 如果你在 rails 控制台输入结果是什么: course = Course.find.first 然后 puts course.topics ?
  • @QumaraotBurgas 你的意思是course = Course.first?我运行它,然后puts course.topics,它返回:#&lt;Topic:0xb952954&gt; #&lt;Topic:0xbb0d9b0&gt; =&gt; nil
  • 我有一种感觉,你的模型Topic没有返回一个带有方法'name'的实例对象,而是返回一个数组['Yes',true]。尝试像这样迭代控制台上的 course.topics 集合: course.topics.each do |c| (new line) puts c.name (new line) end 。或者: course.topics.each {|c|把 c.name}
  • @QumaraotBurgas 它当然返回主题名称:Integrated Management Basic Management... 。还有一件奇怪的事情,在我的新操作中,我没有@topics 变量,但是当我转到新页面时,主题的下拉列表仍然显示是,否。我认为它必须出错,因为我没有通过@topics 在我的新操作中,但不是。
  • 对于布尔值,使用复选框。

标签: ruby-on-rails ruby-on-rails-3


【解决方案1】:

好的,我们的cmets类聊天时间结束了:)(系统建议移动到聊天室)。解决方案似乎是在 simple_form 的关联中内联传递集合:

<%= f.association :topic, collection: @topics, label_method: :name, value_method: :id, prompt: "Choose a topic", label: false %>

变成:

<%= f.association :topic, collection: Topic.limit(1), prompt: "Choose a topic", label: false %>

我认为它现在可以工作。

【讨论】:

  • 我用过&lt;%= f.association :topic, collection: Topic.limit(1), prompt: "Choose a topic", label: false %&gt;。但它有一些小问题,例如当我提交并忘记填写某些字段时,表单有错误,再次呈现新页面,下拉列表没有保留选定的主题。但是,你帮我解决了问题:)
  • 如果您有兴趣:Railscast on the topic.
  • 这是我的应用程序中的第二个嵌套表单,在我构建问答嵌套表单之前,它工作正常,但是第二个有一些问题,虽然实现方式是相同的:(但是,我认为我将使用客户端验证,因此当字段为空白时用户无法提交表单,因此它不会再次呈现页面并丢失选择的主题:D
【解决方案2】:

通过将查询分配给@topics 并将其传递给您的视图,您的想法是正确的......但是,您将其置于错误的操作中,而不是将它们传递给正确的视图:

def update_topics
  @course = Course.find(params[:course_id])
  @topics = @course.topics
end

-

你应该做什么:

您的更新操作没有update view,因此,您必须放置以下两行:

@course = Course.find(params[:course_id])
@topics = @course.topics

在您的 new 操作和您的 edit 操作中

然后你可以继续使用你原来的 simple_form 代码,它是/原来是正确的:

<%= f.association :topic, collection: @topics, 
                  label_method: :name, value_method: :id, 
                  prompt: "Choose a topic", label: false 
%>

或者,您可以跳过控制器中的@topics,然后在视图中简单地添加以下内容:

视图

<%= f.association :topic, collection: Topics.all, 
                  label_method: :name, value_method: :id, 
                  prompt: "Choose a topic", label: false 
%>

编辑视图

<%= f.association :topic, collection: Course.find(params[:course_id]).topics, 
                  label_method: :name, value_method: :id, 
                  prompt: "Choose a topic", label: false 
%>

注意区别:

  • 我认为在您的new 视图中,您希望用户看到所有可能的主题。
  • 在您的 edit 视图中,您只是希望他们看到本课程的主题,对吗?

-

为什么会这样:

  1. 由于您之前没有传递任何集合,因此没有“名称”方法/列供 simple_form 用作下拉列表中的标签/显示值,因此您收到有关 Array ["Yes",true]

  2. 如果/当您删除 label_method: :name, value_method: :id, 选项时,您可能会在下拉列表中看到与预期行一样多的选项,但您会看到主题对象列表而不是课程主题名称列表 (像这样):

    #<Topic::xxxx>
    #<Topic::xxxx>
    ...
    #<Topic::xxxx>
    
  3. 而且,当您不提供集合时,您只会获得 2 个是/否值,这是您找到的配置文件 (config/locales/simple_form.en.yml) 的 simple_form 默认值。

  4. 所以,你现在可能已经猜到了,这就是你最终使用的原因......

    <%= f.association :topic, collection: 
                      Topic.limit(1), 
                      prompt: "Choose a topic", 
                      label: false 
    %>
    

    ...一种“有效”的解决方法——因为它*did* 执行了一个正确的查询并将其提供给 simple_form,但它只将结果限制为 *first* 表中的主题(没有任何排序/排序)

至少,这是我学到/经历的。 HTH!

【讨论】:

    猜你喜欢
    • 2020-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-16
    • 1970-01-01
    相关资源
    最近更新 更多