Ruby on Rails - nil:NilClass 错误的未定义方法“each”
Ruby on Rails - undefined method `each' for nil:NilClass error
我已经检查了 API 我的具体错误,但提供的答案无法解决我的问题。
我只是在试验在线获得的 "find nearest location" 代码,我的问题是当我将此代码实施到一个项目时,我获得了 "undefined method `each' for nil:NilClass error"。
我知道这个错误是由于调用@something 时未定义。所以,这是我正在使用的代码和文件:
locations.rb
class Nearby_Location < ActiveRecord::Base
geocoded_by :full_address
after_validation :geocode, :if => :address_changed?
def full_address
[address, city, postcode].compact.join(',')
end
end
locations_controller.rb
class Locations < ApplicationController
def index
@locations = Locations.all
if params[:search].present?
@locations = Locations.near(params[:search], 10, :order => :distance)
else
@locations = Locations.all.order("created_at DESC")
end
end
def new
@locations = Locations.new
end
def create
@locations = Locations.new(location_params)
if @locations.save
flash[:success] = 'Place added!'
redirect_to root_path
else
render 'new'
end
end
def location_params
params.require(:location).permit(:company_name, :address, :city,
:postcode, :latitude, :longitude)
end
def show
render :layout => nil
@locations = Locations.find(params[:id])
end
end
page.html.erb
<div class="container">
<div class="starter-template">
<h3>Find places near your location</h3>
<p class="lead">Enter your address or zip code</p>
<p><%= form_tag locations_path, :method => :get do %>
<%= text_field_tag :search, params[:search], placeholder: "e.g Statue of Liberty, New York" %>
<%= submit_tag "Search Near", :name => nil %>
<% end %>
</p>
</div>
<% @locations.each do |locations| %>
<%= link_to locations do %>
<%= locations.name %>
<% end %>
<% end %>
</div>
</div>
scheme.rb
create_table "locations", force: :cascade do |t|
t.string "address"
t.float "latitude"
t.float "longitude"
end
我修改了包含其他 API 答案的代码,但没有成功。我觉得这可能是由于代码的 def show 部分,但我不太确定。
你没有指定你在哪个控制器操作中遇到了这个错误,但是根据你的代码我猜它来自 show
方法。问题可能是您试图不渲染布局,但是您是在设置 @locations
变量之前这样做的。因此,Rails 在创建实例变量之前进入渲染。要修复,您应该在创建实例变量后将 render :layout => nil
行移动到方法的末尾,例如:
def show
@locations = Locations.find(params[:id])
render :layout => nil
end
但是,我认为根据您的文件名称,您可能没有完全理解此处发生的事件流程。默认情况下,在控制器操作结束时,Rails 将尝试通过从与控制器名称匹配的视图文件夹中查找与控制器操作匹配的文件名来呈现文件。例如:
app/controllers/books_controller.rb :
class BooksController < ApplicationController
def index
# Will automatically render `app/views/books/index.html.erb`
end
def show
render :other_show_page # Will look for a file `app/views/books/other_show_page.html.erb` rather than `app/views/books/show.html.erb` because it was explicitly specified
end
end
在你的例子中,你有一个名为 page.html.erb
的文件,但你没有控制器操作 (def page; end
),你的任何其他操作也没有专门呈现一个名为 [=17= 的文件].因此,Rails 无论如何都无法找到您的 page.html.erb
文件。我假设你确实有一个 show.html.erb
文件,否则你会得到一个不同的错误,但是如果你试图从你的 page.html.erb
文件中渲染 HTML,它不会发生在您的 show
方法中,除非您专门渲染该文件。
一些其他注意事项...
- 模型的名称通常应该是单数,而不是复数。您似乎使用
Locations
作为您的型号名称,而不是 Location
.
- 您的
show
方法 @locations
中的实例变量,尽管您使用的是 find
ActiveRecord 查询。此查询 returns 单个对象,而不是多个对象的集合代理。因此,您的 @locations
变量命名有点误导, @location
. 可能更好
- 如果您 尝试在您点击
show
方法时呈现 page.html.erb
文件,除非您这样做有某些特定原因是不必要的和不好的做法。您应该只将代码包含在 show.html.erb
文件中,然后让 Rails 自动呈现它,而不是创建您专门呈现的自定义文件。 Rails 约定优于配置,因此请尝试学习约定并遵循它们,直到您有充分的理由打破这种约定。
我已经检查了 API 我的具体错误,但提供的答案无法解决我的问题。
我只是在试验在线获得的 "find nearest location" 代码,我的问题是当我将此代码实施到一个项目时,我获得了 "undefined method `each' for nil:NilClass error"。
我知道这个错误是由于调用@something 时未定义。所以,这是我正在使用的代码和文件:
locations.rb
class Nearby_Location < ActiveRecord::Base
geocoded_by :full_address
after_validation :geocode, :if => :address_changed?
def full_address
[address, city, postcode].compact.join(',')
end
end
locations_controller.rb
class Locations < ApplicationController
def index
@locations = Locations.all
if params[:search].present?
@locations = Locations.near(params[:search], 10, :order => :distance)
else
@locations = Locations.all.order("created_at DESC")
end
end
def new
@locations = Locations.new
end
def create
@locations = Locations.new(location_params)
if @locations.save
flash[:success] = 'Place added!'
redirect_to root_path
else
render 'new'
end
end
def location_params
params.require(:location).permit(:company_name, :address, :city,
:postcode, :latitude, :longitude)
end
def show
render :layout => nil
@locations = Locations.find(params[:id])
end
end
page.html.erb
<div class="container">
<div class="starter-template">
<h3>Find places near your location</h3>
<p class="lead">Enter your address or zip code</p>
<p><%= form_tag locations_path, :method => :get do %>
<%= text_field_tag :search, params[:search], placeholder: "e.g Statue of Liberty, New York" %>
<%= submit_tag "Search Near", :name => nil %>
<% end %>
</p>
</div>
<% @locations.each do |locations| %>
<%= link_to locations do %>
<%= locations.name %>
<% end %>
<% end %>
</div>
</div>
scheme.rb
create_table "locations", force: :cascade do |t|
t.string "address"
t.float "latitude"
t.float "longitude"
end
我修改了包含其他 API 答案的代码,但没有成功。我觉得这可能是由于代码的 def show 部分,但我不太确定。
你没有指定你在哪个控制器操作中遇到了这个错误,但是根据你的代码我猜它来自 show
方法。问题可能是您试图不渲染布局,但是您是在设置 @locations
变量之前这样做的。因此,Rails 在创建实例变量之前进入渲染。要修复,您应该在创建实例变量后将 render :layout => nil
行移动到方法的末尾,例如:
def show
@locations = Locations.find(params[:id])
render :layout => nil
end
但是,我认为根据您的文件名称,您可能没有完全理解此处发生的事件流程。默认情况下,在控制器操作结束时,Rails 将尝试通过从与控制器名称匹配的视图文件夹中查找与控制器操作匹配的文件名来呈现文件。例如:
app/controllers/books_controller.rb :
class BooksController < ApplicationController
def index
# Will automatically render `app/views/books/index.html.erb`
end
def show
render :other_show_page # Will look for a file `app/views/books/other_show_page.html.erb` rather than `app/views/books/show.html.erb` because it was explicitly specified
end
end
在你的例子中,你有一个名为 page.html.erb
的文件,但你没有控制器操作 (def page; end
),你的任何其他操作也没有专门呈现一个名为 [=17= 的文件].因此,Rails 无论如何都无法找到您的 page.html.erb
文件。我假设你确实有一个 show.html.erb
文件,否则你会得到一个不同的错误,但是如果你试图从你的 page.html.erb
文件中渲染 HTML,它不会发生在您的 show
方法中,除非您专门渲染该文件。
一些其他注意事项...
- 模型的名称通常应该是单数,而不是复数。您似乎使用
Locations
作为您的型号名称,而不是Location
. - 您的
show
方法@locations
中的实例变量,尽管您使用的是find
ActiveRecord 查询。此查询 returns 单个对象,而不是多个对象的集合代理。因此,您的@locations
变量命名有点误导,@location
. 可能更好
- 如果您 尝试在您点击
show
方法时呈现page.html.erb
文件,除非您这样做有某些特定原因是不必要的和不好的做法。您应该只将代码包含在show.html.erb
文件中,然后让 Rails 自动呈现它,而不是创建您专门呈现的自定义文件。 Rails 约定优于配置,因此请尝试学习约定并遵循它们,直到您有充分的理由打破这种约定。