Ruby Rails:无法从评论访问用户属性
Ruby on Rails: Can't access User Attributes From a Comment
在这个应用程序中,我有一个 Recipe 模型、一个 User 模型(Devise)和一个 Comment 模型。
class User < ActiveRecord::Base
has_many :recipes
has_many :comments
end
class Recipe < ActiveRecord::Base
belongs_to :user
has_many :comments, :dependent => :destroy
end
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :recipe
end
这就是我的评论控制器的样子。
class CommentsController < ApplicationController
def create
@recipe = Recipe.find(params[:recipe_id])
@comment = @recipe.comments.build(comment_params)
@comment.user = current_user
if @comment.save
redirect_to root_path #change this the the appropriate path later
end
end
private
def comment_params
params.require(:comment).permit(:content)
end
end
这是我遇到的错误
ActionView::Template::Error (undefined method `first_name' for nil:NilClass):
68: <p><%= @recipe.comments.count %> Comments</p>
69: <% @recipe.comments.each do |comment| %>
70: <p><%= comment.content %><p>
71: <%= comment.user.first_name %>
72: <% end %>
73: </div>
74: </div>
所以当我尝试访问 first_name 属性时出现问题。如果我只是 'comment.user' 它吐出 # User:0x007f8f4f9b6780.
我查看了 Rails 控制台,发现我的评论正在保存。在 Rails 控制台中,我可以执行
@recipe = Recipe.first
@recipe.comments.first.user.first_name => "John"
这是失败的实际代码
<% @recipe.comments.each do |comment| %>
<% byebug %>
<p><%= comment.content %><p>
<p><%= comment.user.first_name %></p>
<% end %>
我尝试使用 byebug 进行调试,我可以做到 'comment.user.first_name' => John
我不确定这里有什么问题,希望得到帮助。 Rails 4.2.0 顺便说一句
编辑:RecipeController#Show
class RecipesController < ApplicationController
before_action :find_user, only: [:edit, :update, :show, :destroy]
before_action :find_recipe, only: [:edit, :update, :show, :destroy]
...
def show
end
private
def find_user
@user = User.find(params[:user_id])
end
def find_recipe
@recipe = Recipe.find(params[:id])
end
end
部分评论表
<div class="container">
<% if user_signed_in? %>
<%= form_for([@recipe.user, @recipe, @recipe.comments.build]) do |f| %>
<%= f.label :content %><br>
<%= f.text_area :content %><br>
<br>
<%= f.submit class: "btn btn-default" %>
<% end %>
<% end %>
</div>
因为您正在迭代 Comments 集合
@recipe.comments.each
出现您提到的错误,因为其中一条评论没有设置 user
(这导致 first_name
调用 nil
,以及您提到的错误).
尝试按如下方式修改您的模板,以跟踪 "problematic" 评论:
<% @recipe.comments.each do |comment| %>
<p><%= comment.content %><p>
<% if comment.user.nil? %>
Anonymous
<% else %>
<%= comment.user.first_name %>
<% end %>
<% end %>
希望对您有所帮助!
更新
尝试更新 RecipesController
:
class RecipesController < ApplicationController
def show
@comment = Comment.new
end
end
并部分替换@recipe.comments.build
:
<div class="container">
<% if user_signed_in? %>
<%= form_for([@recipe.user, @recipe, @comment]) do |f| %>
<%= f.label :content %><br>
<%= f.text_area :content %><br>
<br>
<%= f.submit class: "btn btn-default" %>
<% end %>
<% end %>
</div>
此时您不需要 "linking" @recipe
和 Comment
,因为它会在 CommentsController#create
.
中得到妥善处理
这是很好的练习!
从技术上讲,您永远不会检查 current_user
是否存在。
因此,当您在每个评论中进行迭代时,如果没有登录的人发表评论,则该用户将为零。
为了防止这个错误,你可以在你的控制器中添加这个 Devise Helper :
class CommentsController < ApplicationController
before_filter :authenticate_pro_user!
如果有人尝试访问评论控制器,它将自动重定向到登录视图。
更好的处理方法是使用委托并允许 nil,让我解释一下
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :recipe
delegate :first_name, to: :user, prefix: true, allow_nil: true
end
这将创建一个名为 user_first_name
的方法(user
是 prefix
),allow_nil
表示如果用户不存在 return nil
查看代码会是这样
<% @recipe.comments.each do |comment| %>
<p><%= comment.content %><p>
<p><%= comment.user_first_name %></p> # notice it's 1 dot
<% end %>
当循环到达没有用户的评论时,它将return nil
变成一个空字符串,
当用户存在时,评论将要求用户 return 它是 first_name
在这个应用程序中,我有一个 Recipe 模型、一个 User 模型(Devise)和一个 Comment 模型。
class User < ActiveRecord::Base
has_many :recipes
has_many :comments
end
class Recipe < ActiveRecord::Base
belongs_to :user
has_many :comments, :dependent => :destroy
end
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :recipe
end
这就是我的评论控制器的样子。
class CommentsController < ApplicationController
def create
@recipe = Recipe.find(params[:recipe_id])
@comment = @recipe.comments.build(comment_params)
@comment.user = current_user
if @comment.save
redirect_to root_path #change this the the appropriate path later
end
end
private
def comment_params
params.require(:comment).permit(:content)
end
end
这是我遇到的错误
ActionView::Template::Error (undefined method `first_name' for nil:NilClass):
68: <p><%= @recipe.comments.count %> Comments</p>
69: <% @recipe.comments.each do |comment| %>
70: <p><%= comment.content %><p>
71: <%= comment.user.first_name %>
72: <% end %>
73: </div>
74: </div>
所以当我尝试访问 first_name 属性时出现问题。如果我只是 'comment.user' 它吐出 # User:0x007f8f4f9b6780.
我查看了 Rails 控制台,发现我的评论正在保存。在 Rails 控制台中,我可以执行
@recipe = Recipe.first
@recipe.comments.first.user.first_name => "John"
这是失败的实际代码
<% @recipe.comments.each do |comment| %>
<% byebug %>
<p><%= comment.content %><p>
<p><%= comment.user.first_name %></p>
<% end %>
我尝试使用 byebug 进行调试,我可以做到 'comment.user.first_name' => John
我不确定这里有什么问题,希望得到帮助。 Rails 4.2.0 顺便说一句
编辑:RecipeController#Show
class RecipesController < ApplicationController
before_action :find_user, only: [:edit, :update, :show, :destroy]
before_action :find_recipe, only: [:edit, :update, :show, :destroy]
...
def show
end
private
def find_user
@user = User.find(params[:user_id])
end
def find_recipe
@recipe = Recipe.find(params[:id])
end
end
部分评论表
<div class="container">
<% if user_signed_in? %>
<%= form_for([@recipe.user, @recipe, @recipe.comments.build]) do |f| %>
<%= f.label :content %><br>
<%= f.text_area :content %><br>
<br>
<%= f.submit class: "btn btn-default" %>
<% end %>
<% end %>
</div>
因为您正在迭代 Comments 集合
@recipe.comments.each
出现您提到的错误,因为其中一条评论没有设置 user
(这导致 first_name
调用 nil
,以及您提到的错误).
尝试按如下方式修改您的模板,以跟踪 "problematic" 评论:
<% @recipe.comments.each do |comment| %>
<p><%= comment.content %><p>
<% if comment.user.nil? %>
Anonymous
<% else %>
<%= comment.user.first_name %>
<% end %>
<% end %>
希望对您有所帮助!
更新
尝试更新 RecipesController
:
class RecipesController < ApplicationController
def show
@comment = Comment.new
end
end
并部分替换@recipe.comments.build
:
<div class="container">
<% if user_signed_in? %>
<%= form_for([@recipe.user, @recipe, @comment]) do |f| %>
<%= f.label :content %><br>
<%= f.text_area :content %><br>
<br>
<%= f.submit class: "btn btn-default" %>
<% end %>
<% end %>
</div>
此时您不需要 "linking" @recipe
和 Comment
,因为它会在 CommentsController#create
.
这是很好的练习!
从技术上讲,您永远不会检查 current_user
是否存在。
因此,当您在每个评论中进行迭代时,如果没有登录的人发表评论,则该用户将为零。
为了防止这个错误,你可以在你的控制器中添加这个 Devise Helper :
class CommentsController < ApplicationController
before_filter :authenticate_pro_user!
如果有人尝试访问评论控制器,它将自动重定向到登录视图。
更好的处理方法是使用委托并允许 nil,让我解释一下
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :recipe
delegate :first_name, to: :user, prefix: true, allow_nil: true
end
这将创建一个名为 user_first_name
的方法(user
是 prefix
),allow_nil
表示如果用户不存在 return nil
查看代码会是这样
<% @recipe.comments.each do |comment| %>
<p><%= comment.content %><p>
<p><%= comment.user_first_name %></p> # notice it's 1 dot
<% end %>
当循环到达没有用户的评论时,它将return nil
变成一个空字符串,
当用户存在时,评论将要求用户 return 它是 first_name