下面我在一个名为Movie的模型中创建了一个类方法,它应该返回一个数组:
def self.all_ratings
Array['G','PG','PG-13','R','NC-17']
end
在我的电影控制器中,我使用以下实例变量访问它:
@all_ratings = Movie.all_ratings
但是,当我在索引视图中使用它时,我收到以下错误:
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.each
我相信我正在正确地创建数组,但我可能错了。有关这些错误发生的任何建议吗?
以下是使用@all_ratings的视图:
%h1 All Movies
= form_tag movies_path, :method => :get do
Include:
- @all_ratings.each do |rating|
= rating
= check_box_tag "ratings[#{rating}]"
= submit_tag 'Refresh'
以下是我将@all_ratings实现到控制器
的方法class MoviesController < ApplicationController
@all_ratings = Movie.all_ratings
答案 0 :(得分:5)
初始化实例变量的代码需要在实例方法中。
(否则范围是类,而不是实例。)
class MoviesController < ApplicationController
def index # Or wherever
@all_ratings = Movie.all_ratings
end
end
如果您需要使用多种方法中的值,则可以使用before_filter
。
Ruby与Java之类的语言不同。在Java中,实例变量是在实例方法之外定义的,并且在每个实例方法中都可用,无论它们初始化的值是什么。
在Ruby中,有两种(主要)方法来处理实例变量:使用像attr_accessor
这样的方法来创建访问器方法,或者在实例方法中初始化它们,如上所示。
初始化实例变量后,其值可从任何其他实例方法使用。例如,在您的评论中,您提到使用ratings
方法初始化它。除非明确调用ratings
,否则@all_ratings
将不进行初始化。换句话说,如果您向GET
发出index
请求,ratings
方法将不被调用,而@all_ratings
仍将是nil
{1}}。
如果您从ratings
明确调用 index
,则@all_ratings
将被初始化(通过ratings
方法)。一旦在任何实例方法中初始化,该对象的实例(在本例中为控制器)具有初始化的@all_ratings
实例变量:
def index
ratings
end
现在索引模板中可以使用@all_ratings
的值。
如果没有将实例变量初始化放在实例方法中,那么您实际在做的是在类 Foo
中创建一个实例变量,这是某种东西非常不同:
[1] pry(main)> class Foo
[1] pry(main)* @wat = self.class
[1] pry(main)* end
=> Class
[2] pry(main)> f = Foo.new
=> #<Foo:0x007fbfba8efba8>
[5] pry(main)> f.instance_variables
=> []
[6] pry(main)> Foo.instance_variables
=> [:@wat]
[7] pry(main)> Foo.instance_eval "@wat"
=> Class
答案 1 :(得分:3)
请将@all_ratings = Movie.all_ratings
移到控制器的索引操作中。如果它对所有操作都是通用的,那么将它放在before过滤器中,如下所示:
class MoviesController < ApplicationController
before_filter :load_ratings
def index
..
end
<other public methods>
private
def load_ratings
@all_ratings = Movie.all_ratings
end