【问题标题】:Why do I get ActionView::Template::Error: undefined method `name' for nil:NilClass on Heroku but not locally为什么我在 Heroku 上得到 ActionView::Template::Error: undefined method `name' for nil:NilClass 但不是在本地
【发布时间】:2014-01-07 14:31:48
【问题描述】:

我有一个在本地运行 SQLite 和在 Heroku 上运行 PostgreSQL 的 Rails 4 应用程序。

我的 PostController 的索引操作有问题。我收到上述错误,但仅限于 Heroku。

我已经仔细检查了所有代码并运行了所有迁移并重新启动了 Heroku 服务器。我还仔细检查了本地和 Heroku 上的迁移是否相同。该问题似乎与通过 Post 模型访问 User 模型中的数据特别相关。例如,我尝试通过 Heroku 上的 rails 控制台访问其他属性,例如电子邮件,但我得到了相同的未定义方法错误。所以我很确定这与表连接有关。

另外澄清一下,我在生产数据库中确实有数据

这是我的 PostsController 操作:

class PostsController < ApplicationController
  before_filter :authenticate_user!, except: [:index, :show]

  before_action :set_post, only: [:show, :edit, :update, :destroy]

  # GET /posts
  # GET /posts.json
  def index
    @posts = Post.all
  end
end

我的帖子模型:

class Post < ActiveRecord::Base

    belongs_to :user
end

我在用户模型中的代码:

class User < ActiveRecord::Base

  rolify

  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
  :recoverable, :rememberable, :trackable, :validatable, :confirmable

  belongs_to :qualification
  has_many :posts

  validates :phone, presence: true, format: { with: /\d{3}.\d{3}.\d{4}/, message: "Must be in 555.555.5555 format" }
  validates :name, presence: true
  validates :email, presence: true
  validates :acknowledgement, presence: true

  # new function to set the password without knowing the current password used in our confirmation controller. 
  def attempt_set_password(params)
    p = {}
    p[:password] = params[:password]
    p[:password_confirmation] = params[:password_confirmation]
    update_attributes(p)
  end

  # new function to return whether a password has been set
  def has_no_password?
    self.encrypted_password.blank?
  end

  # new function to provide access to protected method unless_confirmed
  def only_if_unconfirmed
    pending_any_confirmation {yield}
  end

  def password_required?
  # Password is required if it is being set, but not for new records
  if !persisted? 
    false
  else
    !password.nil? || !password_confirmation.nil?
  end
end

end

还有我的 index.html.erb 文件:

<% @posts.each do |post| %>
<h2 class='subheader'><%= link_to post.title, post %></h2>
<h6>written by <%= post.user.name %> on <%= post.created_at.to_s(:long) %></h6>
<div><%= post.body.html_safe %></div>
<% if user_signed_in? %>
<% if current_user.has_role? :admin %>
<div><%= link_to 'Edit', edit_post_path(post) %></div>
<div><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %>  </div>
<% end %>
<% end %>
<% end %>
<br>

<%= link_to 'New Post', new_post_path %>

我的 Heroku 日志的输出:

2013-12-19T06:31:13.280899+00:00 app[web.1]: Started GET "/posts" for 64.114.175.126 at     2013-12-19 06:31:13 +0000
2013-12-19T06:31:13.280899+00:00 app[web.1]: Started GET "/posts" for 64.114.175.126 at  2013-12-19 06:31:13 +0000
2013-12-19T06:31:13.283663+00:00 app[web.1]: Processing by PostsController#index as HTML
2013-12-19T06:31:13.283663+00:00 app[web.1]: Processing by PostsController#index as HTML
2013-12-19T06:31:13.292344+00:00 app[web.1]:   Rendered posts/index.html.erb within layouts/application (6.9ms)
2013-12-19T06:31:13.292553+00:00 app[web.1]: Completed 500 Internal Server Error in 9ms
2013-12-19T06:31:13.292344+00:00 app[web.1]:   Rendered posts/index.html.erb within layouts/application (6.9ms)
2013-12-19T06:31:13.292553+00:00 app[web.1]: Completed 500 Internal Server Error in 9ms
2013-12-19T06:31:13.295581+00:00 app[web.1]:
2013-12-19T06:31:13.295581+00:00 app[web.1]:     6: <div><%= post.body.html_safe %></div>
2013-12-19T06:31:13.295581+00:00 app[web.1]:     3: <% @posts.each do |post| %>
2013-12-19T06:31:13.295581+00:00 app[web.1]:     7: <% if user_signed_in? %>
2013-12-19T06:31:13.295581+00:00 app[web.1]:     2:
2013-12-19T06:31:13.295581+00:00 app[web.1]:     4: <h2 class='subheader'><%= link_to post.title, post %></h2>
2013-12-19T06:31:13.295581+00:00 app[web.1]: ActionView::Template::Error (undefined method `name' for nil:NilClass):
2013-12-19T06:31:13.295581+00:00 app[web.1]:     5: <h6>written by <%= post.user.name %> on <%= post.created_at.to_s(:long) %></h6>
2013-12-19T06:31:13.295778+00:00 app[web.1]:   app/views/posts/index.html.erb:3:in `_app_views_posts_index_html_erb__338969566965495969_70155247178440'
2013-12-19T06:31:13.295778+00:00 app[web.1]:     2:
2013-12-19T06:31:13.295778+00:00 app[web.1]:
2013-12-19T06:31:13.295778+00:00 app[web.1]: ActionView::Template::Error (undefined method `name' for nil:NilClass):
2013-12-19T06:31:13.295778+00:00 app[web.1]:
2013-12-19T06:31:13.295778+00:00 app[web.1]:     3: <% @posts.each do |post| %>
2013-12-19T06:31:13.295778+00:00 app[web.1]:
2013-12-19T06:31:13.295581+00:00 app[web.1]:     8: <% if current_user.has_role? :admin %>
2013-12-19T06:31:13.295581+00:00 app[web.1]:   app/views/posts/index.html.erb:5:in `block in _app_views_posts_index_html_erb__338969566965495969_70155247178440'
2013-12-19T06:31:13.295778+00:00 app[web.1]:     5: <h6>written by <%= post.user.name %> on <%= post.created_at.to_s(:long) %></h6>
2013-12-19T06:31:13.295778+00:00 app[web.1]:     6: <div><%= post.body.html_safe %></div>
2013-12-19T06:31:13.295947+00:00 app[web.1]:     7: <% if user_signed_in? %>
2013-12-19T06:31:13.295947+00:00 app[web.1]:     8: <% if current_user.has_role? :admin %>
2013-12-19T06:31:13.295947+00:00 app[web.1]:   app/views/posts/index.html.erb:5:in `block in _app_views_posts_index_html_erb__338969566965495969_70155247178440'
2013-12-19T06:31:13.295947+00:00 app[web.1]:   app/views/posts/index.html.erb:3:in `_app_views_posts_index_html_erb__338969566965495969_70155247178440'
2013-12-19T06:31:13.295778+00:00 app[web.1]:     4: <h2 class='subheader'><%= link_to post.title, post %></h2>
2013-12-19T06:31:13.295947+00:00 app[web.1]:
2013-12-19T06:31:13.295947+00:00 app[web.1]:
2013-12-19T06:31:13.303637+00:00 heroku[router]: at=info method=GET path=/posts host=www.kettlecreekventure.com fwd="64.114.175.126" dyno=web.1 connect=8ms service=25ms status=500 bytes=1266
2013-12-19T06:31:14.630725+00:00 heroku[router]: at=info method=GET path=/favicon.ico host=www.kettlecreekventure.com fwd="64.114.175.126" dyno=web.1 connect=1ms service=4ms status=200 bytes=0
2013-12-19T06:31:22.445573+00:00 heroku[run.7634]: Process exited with status 0
2013-12-19T06:31:22.459444+00:00 heroku[run.7634]: State changed from up to complete

同样,代码在我的本地机器上运行良好,但在我部署到 Heroku 后失败并出现上述错误。当应用程序尝试引用 post.user.name 时,index.html.erb 文件中存在错误。我正在拔头发试图弄清楚。 如果有人能看到我的问题在哪里,我将不胜感激。我做错了什么?

【问题讨论】:

  • 当您尝试访问索引页面时,您能否添加 Heroku 的 Web 服务器日志的输出?
  • 我已经添加了 Heroku 日志
  • 生产中的问题完全相同,使用 rails 4.1.4。我没有使用heroku,但生产中的相同问题和数据与开发和登台仍然相同

标签: postgresql heroku ruby-on-rails-4


【解决方案1】:

根据您的更新,我将建议:每次您删除有帖子的用户然后尝试列出他们的帖子时,&lt;%= post.user.name %&gt; 将返回 nil,因为该帖子不再有用户可参考。您可以使用

has_many :posts, dependent: :destroy 

在我上面建议的用户模型中,或者您添加一些功能来删除用户以防止在尝试查看他们的帖子时出错。一些选择是:

当一个用户被删除时,你可以在用户表的那一行中删除除他们的姓名和 ID 之外的所有内容,这将允许你让 &lt;%= post.user.name %&gt; 返回一个值。

当用户被删除时,您可以删除其用户表信息中的所有内容并在其后添加“-user-deleted”,这有点像 Tumblr 在用户停用他们的帐户并且他们的名字出现在其他一些帖子中时所做的事情微博。

您可以在名为“user-deleted”的数据库中创建一个用户,并让该用户继承已删除用户的每篇文章。在用户控制器中,在您的 delete 操作中添加一些内容,以将他们帖子中的 user_id 字段更改为“用户已删除”帐户。

或者最后你可以检查一下 post.user 是否返回一个值,如果不是就打印类似“用户不再存在于系统中”的内容

当然,这完全取决于您是否希望允许删除用户但仍保留他们的帖子。如果这不仅仅是一个课堂项目或您正在做的事情只是为了学习 Rails,那肯定是一种可能的情况。希望这可以帮助。这当然让我想到了允许用户删除他们的个人资料而没有任何东西可以清理的陷阱。

【讨论】:

    【解决方案2】:

    看起来我在 Heroku 数据库中可能有一些损坏的数据。 我最终通过 rails 控制台删除了所有现有的帖子。现在一切正常!

    我跑了 @posts = Post.all @posts.each 做 |post| post.destroy 结束

    然后我继续输入新帖子,没有任何问题。问题是我删除了一个用户,但没有删除相应的帖子

    【讨论】:

    • 也许你应该在 User 模型中有has_many :posts, dependent: :destroy
    • 我想过,但我不想因为用户被删除而删除帖子。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-28
    • 1970-01-01
    • 1970-01-01
    • 2015-04-15
    • 1970-01-01
    相关资源
    最近更新 更多