我遇到的错误很可能是由我模型中的has_one关联引起的。
问题
在宣布这些关联后,我开始进行奇怪的交互,我突然得到"undefined method
电子邮件'为nil:NilClass“`以及来自错误控制台的以下片段:
<div class="row">
<div class="column-md-6 column-md-offset-3">
<% @posts.each do |post| %>
email: <%= post.user.email %> <br> # <= source of the issue!
Level: <%= post.level %> <br>
Region: <%= post.region %> <br>
Info: <%= post.description %> <br>
<% if post.user == current_user %>
<%= link_to "Edit", edit_post_path(post) %>
问题的根源
我很难追踪错误并尝试重现它。我在rails控制台中快速查看了我的数据库,发现即使从用户创建帖子成功,user_id也会变为零。我终于设法通过以下步骤重现错误:
1)登录
2)创建帖子
3)转到“所有帖子”。 Post index action会在这里正确呈现每个用户的所有帖子。
4)虽然仍以同一用户身份登录,但请创建另一个帖子。
5)返回“所有帖子”,我收到上述错误。
发布模型
class Post < ActiveRecord::Base
validates_presence_of :level, :region, :description
validates :level, length: { maximum: 50 }
belongs_to :user
end
用户模型
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_one :post
end
帖子控制器
class PostsController < ApplicationController
before_action :set_post, only: [:edit, :update]
before_action :authenticate_user!, except: [:index, :show]
def index
@posts = Post.all
end
def show
@post = Post.find(params[:id])
end
def new
@post = current_user.build_post
end
def create
@post = current_user.build_post(post_params)
if @post.save
flash[:success] = "Post successfully created!"
redirect_to posts_path
else
render 'new'
end
end
def edit
end
def update
#@post = Post.find(post_params)
if @post.update(post_params)
flash[:success] = "Profile updated"
redirect_to posts_path
else
render 'edit'
end
end
def destroy
Post.find(params[:id]).destroy
flash[:success] = "Post deleted"
redirect_to posts_path
end
private
def post_params
params.require(:post).permit(:description, :level, :region)
end
def set_post
@post = Post.find(params[:id])
end
端
schema.rb
ActiveRecord::Schema.define(version: 20151209193950) do
create_table "posts", force: :cascade do |t|
t.text "description"
t.string "level"
t.string "region"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
问题
我的目标是为每个用户设置一个帖子限制。我几乎可以肯定has_one关联是问题的一部分。我的问题是,这是否是实现我的目标的正确方法,还是我应该使用has_many关联并以其他方式强制执行限制?
如果has_one是正确的方法,我该如何解决这个问题?
答案 0 :(得分:2)
您必须在控制器的编辑操作中再次找到正确的用户并使其可供视图使用,否则实例 nil ,从而导致您的错误。
<强> Edit_0:强>
通常,在您发布的代码之前,添加:
<%= debug params %>
查看视图中缺少/可用的变量。
答案 1 :(得分:1)
由于您提到用户只能有一个帖子,您必须在创建之前检查用户是否没有任何帖子。试试如下
def create
@post = current_user.build_post(post_params) unless current_user.post
if @post.save
flash[:success] = "Post successfully created!"
redirect_to posts_path
else
flash[:success] = "You exceeded your limit!"
redirect_to root_path
end
end
并且您还应该添加@benjamin建议以及编辑操作。
答案 2 :(得分:1)
在你的新动作和创建动作中,你调用current_user.build_post
,这在Rails中有一些令人惊讶的副作用。
在分配或构建has_one关联之后,会立即触发一个查询,该查询将关联模型上的外键设置为nil。无法阻止此查询在has_one
关联上执行。如果您将User
上的关系更改为has_many,它将按预期工作。