【问题标题】:Returns undefined method 'each' for nil:NilClass?返回 nil:NilClass 的未定义方法“每个”?
【发布时间】:2012-07-06 03:00:49
【问题描述】:

这是我在视图中的代码:show.html.erb

<ul>
<% @bullets.each do |r| %>
    <li><%= r.content %></li>
<% end %>
</ul>

这是我在控制器中的代码:users_controller.rb

if cookies[:bullets].nil?
  @bullets = Bullet.all.shuffle.first(4)
  cookies[:bullets] = @bullets.collect(&:id)
else
 @bullets = []
 cookies[:bullets].each do |id|
   @bullets << Bullet.find(id)
 end
end

这将为 nil:NilClass 返回未定义的方法 'each'

<% @bullets.each do |r| %>

我想知道它为什么这样做,以及如何修复它以从名为“bullets”的数据库 (sqlite3) 表中发布四个随机固定的项目符号内容(列是内容)。

编辑:这是整个控制器:

class StudentsController < ApplicationController
    #GET /
    def index
      @students = Student.all 

      respond_to do |format|
        format.html # index.html.erb
        format.json { render json: @students }
        end  
    end 

    #GET /new
    def new 
      @student = Student.new
    end 

    #POST
    def create
      @student = Student.new(params[:student])
          if @student.save
        render :file => 'app/views/success'
      else 
        render :file => 'app/views/students/fail'
      end  
        end

    #GET /students/{:id}
    def show 
       @student = Student.find_by_url(params[:id])

           respond_to do |format|
         format.html # show.html.erb
         format.json { render json: @student } 
           end  
    end

    #BULLETS Randomizing /students/new.html.erb
    if cookies[:bullets].nil?
      @bullets = Bullet.all.shuffle.first(4)
      cookies[:bullets] = @bullets.collect(&:id)
    else
     @bullets = []
     cookies[:bullets].each do |id|
       @bullets << Bullet.find(id)
     end
    end

    #GET /students/1/edit
    def edit 
        @student = Student.find_by_url(params[:id])
    end 

    def update
      @student = Student.find_by_url(params[:id])
      respond_to do |format|
        if @student.update_attributes(params[:student])
          format.html { redirect_to @student, notice: 'Student was successfully updated.'}  
        else 
          format.html { render action: "edit" } 
          format.json { render json: @student.errors, status: :unprocessable_entity } 
        end 
        end 
    end 

    #DELETE
    def destroy 
    @student = Student.find_by_url(params[:id])
    @student.destroy

        respond_to do |format|
         format.html { redirect_to students_url }
         format.json { head :no_content }
        end
    end
end 

编辑#2:像这样?

#GET /students/{:id}
    def show 
       @student = Student.find_by_url(params[:id])

        #BULLETS Randomizing /students/show.html.erb
    if cookies[:bullets].nil?
      @bullets = Bullet.all.shuffle.first(4)
      cookies[:bullets] = @bullets.collect(&:id)
    else
     @bullets = []
     cookies[:bullets].each do |id|
       @bullets << Bullet.find(id)
     end
    end

           respond_to do |format|
         format.html # show.html.erb
         format.json { render json: @student } 
           end  
    end

【问题讨论】:

  • 您确定bullets 表不为空?
  • 即使表是空的,Array#first 在接收到整数参数时也会返回一个空数组(不是 nil),并且他显式地将 @bullets 初始化为 @ 的另一个分支中的一个数组987654329@ 声明。您的控制器操作或视图中是否还有其他可以发布的内容?
  • 是在你的表演动作中获取子弹的代码吗?还是用另一种方法?如果是这样,请确保它被调用.. 显式地从 show 操作或使用 before_filter
  • 是的,它不在表演范围内
  • 将该代码块移动到显示操作中

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


【解决方案1】:

看起来应该是:

#GET /students/{:id}
def show 

   @student = Student.find_by_url(params[:id])

   #BULLETS Randomizing /students/new.html.erb
   if cookies[:bullets].nil?
     @bullets = Bullet.all.shuffle.first(4)
     cookies[:bullets] = @bullets.collect(&:id)
   else
     # simpler to use an 'in list' for only 4 id's
     Bullet.where("id in (?)", cookies[:bullets])
   end

   respond_to do |format|
     format.html # show.html.erb
     format.json { render json: @student } 
   end  
end

请注意,我将您在 cookies 数组上的循环转换为带有“in list”的单个语句——这应该会简化为查找生成的 sql。

虽然,这段代码应该被推入模型是有争议的:

class Bullet < ActiveRecord::Base

  NUM_USER_BULLETS = 4
  # fetch a random set of 
  def self.user_bullets
    Bullet.all.shuffle.first(NUM_USER_BULLETS)
  end
end

或类似的东西。那么你的控制器就更简单了:

#GET /students/{:id}
def show 

   @student = Student.find_by_url(params[:id])

   #BULLETS Randomizing /students/new.html.erb
   if cookies[:bullets].nil?
     @bullets = Bullet.user_bullets
     cookies[:bullets] = @bullets.collect(&:id)
   else
     # simpler to use an 'in list' for only 4 id's
     Bullet.where("id in (?)", cookies[:bullets])
   end

   respond_to do |format|
     format.html # show.html.erb
     format.json { render json: @student } 
   end  
end

将代码迁移到您的模型中后,您的控制器就更简单了。

【讨论】:

  • 还有“id in (?)”。它需要一些东西来代替'吗?'
  • 语法where("id in (?)", cookies[:bullets])基本上意味着用变量cookies[:bullets]替换实际查询中的?
  • 哦,好的,谢谢。请问为什么我对这个问题的第二次编辑第一次有效,但第二次无效(刷新后)?
  • 抱歉 - 我上面的代码有错误。我已经修好了。它应该是Bullet.where("id in (?)", cookies[:bullets])
  • 糟糕!嗯,它发生了。我很高兴能帮上忙。如果您觉得它有帮助,我将不胜感激打勾/接受!
【解决方案2】:
class StudentsController < ApplicationController
   before_filter :get_bullets, :only => [:show]


  def show

  end

  ... 


  protected

  def get_bullets
  #BULLETS Randomizing /students/new.html.erb
    if cookies[:bullets].nil?
      @bullets = Bullet.all.shuffle.first(4)
      cookies[:bullets] = @bullets.collect(&:id)
    else
     @bullets = []
     cookies[:bullets].each do |id|
       @bullets << Bullet.find(id)
     end
    end

  end



end

【讨论】:

    【解决方案3】:

    我建议将您的“随机项目符号”代码重构为 before_filter 以用于 show 操作并在数据库中执行随机化,这将比加载整个表并在 Ruby 中执行随机化更快:

    class UsersController < ApplicationController
      before_filter :assign_bullets, :only => :show
    
      # ...
    
    private
    
      def assign_bullets
        if cookies[:bullets]
          @bullets = cookies[:bullets].map { |id| Bullet.find(id) }
        else
          @bullets = Bullet.order('RANDOM()').limit(4)
          cookies[:bullets] = @bullets.map(&:id)
        end
      end
    end
    

    【讨论】:

    • 小心使用RANDOM()——它的格式可以是特定于数据库的。此外,如果表变大,它会减慢速度。请参阅此处了解更多信息:stackoverflow.com/questions/2752231/…
    • 感谢@KevinBedell。该线程绝对值得一读。在确定解决方案之前,OP 应该根据他的数据对这些不同的方法进行基准测试。
    • 肯定会这样做。谢谢布兰丹。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-27
    相关资源
    最近更新 更多