【问题标题】:has_one association and disappearing user idhas_one 关联和消失的用户 ID
【发布时间】:2016-03-17 14:49:27
【问题描述】:

我遇到了一个错误,这很可能是由我的模型中的 has_one 关联引起的。

问题

在声明了这些关联之后,我开始进行奇怪的交互,我会突然从错误控制台中得到 "undefined methodemail' for nil:NilClass"`,并带有以下 sn-p:

<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 变为 nil 即使从用户创建帖子成功。我终于通过以下步骤设法重现了错误:

1) 登录

2) 创建帖子

3) 转到“所有帖子”。帖子索引操作在此处正确呈现每个用户的所有帖子。

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 是正确的方法,我该如何解决这个问题?

【问题讨论】:

  • 你能发布你的数据库架构吗?
  • @PadmanabanGokula 更新了我原来的帖子。

标签: ruby-on-rails ruby ruby-on-rails-4 associations


【解决方案1】:

您必须在控制器的编辑操作中再次找到正确的用户并使其可用于视图,否则实例为nil,导致您的错误。

Edit_0:
一般来说,在您发布的代码之前,添加:

<%= debug params %>

查看视图中缺少/可用的变量。

【讨论】:

  • 我认为这是正确的,除非在创建方法上也出现错误
  • 您介意分享您的解决方案的一段代码吗?我正在尝试,但后来我的编辑操作中断了。
【解决方案2】:

由于您提到用户只能拥有一个帖子,因此您必须在创建之前检查用户是否没有任何帖子。像下面这样试试

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 建议。

【讨论】:

    【解决方案3】:

    在您的 new 和 create 操作中,您调用 current_user.build_post,这在 Rails 中有一个有点令人惊讶的副作用。

    在分配或建立 has_one 关联后,立即触发一个查询,将关联模型上的外键设置为 nil。无法阻止此查询在 has_one 关联上执行。如果您将User 上的关系更改为has_many,它将按预期工作。

    http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_one#737-build-association-deletes-existing-dependent-record

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多