问题
I have a Rails 4 app running SQLite locally and PostgreSQL on Heroku.
I am having problems with the index action of my PostController. I get the above error, but only on Heroku.
I have double checked all the code and run all migrations and restarted the Heroku server. I have also double checked that the migrations are identical both locally and on Heroku. The issue seems to be specifically related to accessing data in the User model through the Post model. For instance, I've tried to access other attributes such as email through the rails console on Heroku but I get the same undefined method error. So I'm pretty sure it has something to do with the table join.
Also to clarify, I do have data in the production DB
Here's my PostsController action:
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
My Post model:
class Post < ActiveRecord::Base
belongs_to :user
end
My code in the User model:
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
And my index.html.erb file:
<% @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 %>
The output from my Heroku log:
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
Again, the code works perfectly on my local machine but fails with the above error after I have deployed to Heroku. There error is in the index.html.erb file when the app tries to reference post.user.name. I'm pulling my hair out trying to figure it out. I would appreciate if anyone can see where my problem is. What am I doing wrong?
回答1:
According to your update I will propose this: Every time you delete a user who has posts and then try to list their posts <%= post.user.name %> will return nil because this post no longer has a user to refer to. You can either use the
has_many :posts, dependent: :destroy
in the User model as I suggested above, or you add some functionality to the deleting of users to prevent errors when trying to view their posts. Some choices are:
When a user is deleted you can just delete everything but their name and id in that row of the user table, that will allow you to have <%= post.user.name %> return a value.
When a user is deleted you can delete everything in their User table info and add "-user-deleted" after it kind of like what Tumblr does when a user deactivates their account and their name shows up in a post on some other Tumblr.
You can create a User in the DB called "user-deleted" and have that user inherit every post from a user who is deleted. In the User controller add something in your delete action to change the user_id field in their posts to the "user-deleted" account.
Or finally you could just check to see if post.user returns a value, and if not just print something like "The user no longer exists in the system"
This is all dependent of course on if you even want to allow users to be deleted but still keep their posts. That's certainly a likely case if this is more than just a class project or something you are doing just to learn Rails. Hope this helps. It certainly got me thinking about the pitfalls in allowing users to delete their profiles without having something in place to clean up after them.
回答2:
It looks like I may have had some corrupt data in the Heroku DB. I ended up deleting all existing posts via the rails console. Now everything is working fine!
I ran @posts = Post.all @posts.each do |post| post.destroy end
Then I went ahead and entered new posts without any problem. The issue was that I had deleted a user but not the corresponding posts
来源:https://stackoverflow.com/questions/20674647/why-do-i-get-actionviewtemplateerror-undefined-method-name-for-nilnilcla