0

私はRspec DSLに本当に苦労しています! 私は SO やインターネット上で多くのことを読んでいるので、私の弱い心が解決策にたどり着けないため、特定の問題を投稿しています。

ユーザーの電子メールを更新する post メソッドをコントローラーに用意します。正常に動作しますが、取得しているのは NilClass の未定義のメソッドだけであるため、仕様に苦労しています (すべてのオブジェクトとメソッドなどをスタブ化しようとしましたが)。

users_controller.rb

def update_user_email
   @user = User.find_by_id(params[:id])
   new_email = params[:user][:new_email].downcase.strip
   user_check = User.find_by_email('new_email')
   if user_check.blank?
     @user.email = new_email
     @user.save
     flash[:notice] = "Email updated to #{new_email}"
   else
     flash[:alert] = "This email is already being used by someone else!"
   end

   respond_with @user do |format|
     format.html { redirect_to admin_user_path(@user) }
     format.json { head :no_content }
   end
 end

これが私が書こうとしている仕様です。これではない場合、どのテストを作成する必要があり、NilClass エラーで未定義のメソッドを防ぐために何ができるでしょうか!

users_controller_spec.rb

describe Admin::UsersController do
  let!(:user) { FactoryGirl.create(:user, password: 'oldpass', email: 'bar@foo.com') }
  ...
  describe "admin actions for each user" do
    it "resets user email" do
      post :update_user_email, {user: {new_email: 'foo@bar.com'} }
      response.status.should == 200
    end
  end
 ...
end

そしてエラー:

Admin::UsersController admin actions for each user resets user email
Failure/Error: post :update_user_email, {user: {new_email: 'foo@bar.com'} }
NoMethodError:
   undefined method `email=' for nil:NilClass
4

3 に答える 3

1

User問題は、更新したいの id も渡す必要があることです。失敗している行は です。@user.email = new_emailなぜなら、@usernil です。

postテストに合格するには、メソッドを次のように変更する必要があります。

post :update_user_email, {id:'bar@foo.com', user: {new_email: 'foo@bar.com'} }

余談ですが、UsersController#updateRESTful ルートを維持するためには、実際にメソッドでこれを行った方がよいと言えます。Userまた、一意の電子メール アドレスを強制することについては、検証を使用してクラスでこれを行う方がよい場合があります。

于 2013-10-11T00:45:49.220 に答える
1

失敗している行は次のとおりです。

@user = User.find_by_id(params[:id)

テスト中にIDを渡していないため、ユーザーが見つからないため、nilでemail =を呼び出そうとしています。コントローラーをクリーンアップしてテストする方法は次のとおりです。

class YourController < ApplicationController
  before_filter :find_user, only: [:update_user_email]

  def update_user_email
    new_email = params[:user][:new_email].downcase.strip
    user_check = User.where(email: new_email)
    if user_check.blank?
       @user.email = new_email
       @user.save
       flash[:notice] = "Email updated to #{new_email}"
    else
       flash[:alert] = "This email is already being used by someone else!"
    end

    respond_with @user do |format|
      format.html { redirect_to admin_user_path(@user) }
      format.json { head :no_content }
    end
  end

  def find_user
    @user = User.find(params[:id])
    rescue ActiveRecord::RecordNotFound
      flash[:error] = "It looks like that user does not exist"
      # redirect or render
  end
end


# your test


describe "admin actions for each user" do
  it "resets user email" do
    post :update_user_email, id: user.id, user: {new_email: 'foo@bar.com'}
    response.status.should == 200
  end
end

また、ロジックをコントローラーからサービス オブジェクトに移動することを検討することもできます。そのコントローラ メソッドは少し長くなります。

于 2013-10-11T00:46:49.713 に答える
0

あなたpost :update_user_emailは :id... を渡していないので@user = User.find_by_id...、ユーザーを見つけていないので、 @user は nil オブジェクトです。

post :update_user_email, id: user.id, {user: {new_email: 'foo@bar.com'} }
于 2013-10-11T00:45:28.053 に答える