创建一个has_one其他类的类

时间:2014-10-03 21:19:05

标签: ruby-on-rails rspec

当我运行以下测试时:

describe "Ghost pages" do
  subject { page }
  let(:user) { FactoryGirl.create(:user) }
  before do
    user.save
  end
  describe "for signed-in user" do
    before do
      sign_in user
    end
    describe "trying to view his own ghost" do
      before do
        visit ghost_path(user.ghost)
      end
      it { should have_title('Ghost') }
    end
  end
end

我收到以下错误,我无法确定原因:

失败/错误:访问ghost_path(user.ghost)

的ActiveRecord :: RecordNotFound:

找不到ID = 429的Ghost

./ app / controllers / ghosts_controller.rb:48:在`correct_ghost'

每个用户都有一个鬼。当用户注册并创建时,会自动创建重影(self.create_ghost)。也许鬼魂不能以某种方式正确保存?

相关的代码位是:

class User < ActiveRecord::Base
  has_one :ghost, dependent: :destroy
  before_create :create_remember_token
  before_save do
    email.downcase!
    self.create_ghost
  end
  validates :name, presence: true,
                   length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(?:\.[a-z\d\-]+)*\.[a-z]+\z/i
  validates :email, presence:   true,
                    format:     { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
  validates :password, length: { minimum: 6 }
end

class Ghost < ActiveRecord::Base
  belongs_to :user
  validates :user_id, presence: true
end

class UsersController < ApplicationController
  before_action :signed_in_user, only: [:index, :show, :edit, :update, :destroy]
  before_action :non_signed_in_user, only: [:new, :create]
  before_action :correct_user,       only: [:edit, :update]
  before_action :admin_user,         only: :destroy
  def index
    @users = User.paginate(page: params[:page])
  end
  def show
    @user = User.find(params[:id])
  end
  def new
    @user = User.new
  end
  def create
    @user = User.new(user_params)
    if @user.save
      sign_in @user
      flash[:success] = "Welcome!"
      redirect_to @user
    else
      render 'new'
    end
  end
end

class GhostsController < ApplicationController
  before_action :signed_in_user
  before_action :correct_ghost, only: [:show]
  before_action :correct_destroyer, only: [:destroy]
  before_action :go_away, only: [:index, :edit, :update]
  def index
  end
  def edit
  end
  def update
  end
  def show
    @ghost = Ghost.find(params[:id])
  end
  def new
    @ghost = Ghost.new
  end
  def create
    @ghost = current_user.build_ghost(ghost_params)
    if @ghost.save
      flash[:success] = "Ghost successfully created"
    else
      flash[:error] = "Ghost creation failed"
    end
  end
  def destroy
    @ghost = Ghost.find(params[:id])
    @ghost.destroy
    flash[:success] = "Ghost deleted, master."
    redirect_to current_user
  end
  private
    def ghost_params
      params.require(:ghost).permit()
    end
    def correct_ghost
      @ghost = Ghost.find(params[:id])
      redirect_to(root_url) unless (current_user.id == @ghost.user_id)
    end
    def correct_destroyer
      redirect_to(root_url) unless current_user.admin?
    end
    def go_away
      redirect_to(root_url)
    end
end

2 个答案:

答案 0 :(得分:3)

let(:user) { FactoryGirl.create(:user) }
before do
  user.save
end

执行before块时user返回新创建的用户,然后在其上调用save。因此before_save回调将运行两次。当我运行你的代码部分时,我看到:

 Failed to remove the existing associated ghost. The record failed to save after its foreign key was set to nil.

您的结果可能会有所不同。无论如何,你不想创造两个幽灵。

您可以更改回调以避免在存在时创建重影:

before_save do
  create_ghost unless ghost
end

但最好使用before_create,因为你只需要创建一次幽灵。

before_create do
  create_ghost
end

答案 1 :(得分:1)

您在保存Ghost之前创建User,因此用户没有ID,并且ghost验证失败。将其移至after_save回调:

after_save do
  self.create_ghost
end

从语义上讲,根据你的代码dependent: :destroy在没有用户对象的情况下不能存在的ghost对象也会在其用户之后创建。