2016-01-20 73 views
0

我有测试这个问题我CommentsControllerRSpec的控制器:redirect_to的其他控制器

Failure/Error: redirect_to user_path(@comment.user), notice: 'Your comment was successfully added!' ActionController::UrlGenerationError: No route matches {:action=>"show", :controller=>"users", :id=>nil} missing required keys: [:id]

这是我的方法,我控制器

def create 
    if params[:parent_id].to_i > 0 
     parent = Comment.find_by_id(params[:comment].delete(:parent_id)) 
     @comment = parent.children.build(comment_params) 
    else 
     @comment = Comment.new(comment_params) 
    end 
    @comment.author_id = current_user.id 
    if @comment.save 
     redirect_to user_path(@comment.user), notice: 'Your comment was successfully added!' 
    else 
     redirect_to user_path(@comment.user), notice: @comment.errors.full_messages.join 
    end 
    end 

这是我RSpec的

context "User logged in" do 
    before :each do 
     @user = create(:user) 
     sign_in @user 
    end 

    let(:comment) { create(:comment, user: @user, author_id: @user.id) } 
    let(:comment_child) { create(:comment_child, user: @user, author_id: @user.id, parent_id: comment.id) } 

    describe "POST #create" do 
     context "with valid attributes" do 
     it "saves the new comment object" do 
      expect{ post :create, comment: attributes_for(:comment), id: @user.id}.to change(Comment, :count).by(1) 
     end 

     it "redirect to :show view " do 
      post :create, comment: attributes_for(:comment), user: @user 
      expect(response).to redirect_to user_path(comment.user) 
     end 
     end 

     ... 
    end 
    end 

我的评论模式

class Comment < ActiveRecord::Base 
    belongs_to :user 
    acts_as_tree order: 'created_at DESC' 

    VALID_REGEX = /\A^[\w \.\[email protected]:),.!?"']*$\Z/ 
    validates :body, presence: true, length: { in: 2..240}, format: { with: VALID_REGEX } 
end 

我如何添加user_id这一要求?当我将我的控制器redirect_to user_path(@comment.user)中的代码更改为redirect_to user_path(current_user) - 测试通过。我可以在评论控制器中使用redirect_to用户吗?任何可能性都做对了吗?谢谢你的时间。

回答

2

基本上错误是由于@comment.user为零的事实造成的。

让我们开始通过清理规范固定它:

context "User logged in" do 

    # declare lets first. 
    let(:user) { create(:user) } 
    let(:comment) { create(:comment, user: user, author: user) } 
    # use do instead of braces when it does not fit on one line. 
    let(:comment_child) do 
    # use `user: user` instead of `user_id: user.id`. 
    # the latter defeats the whole purpose of the abstraction. 
    create(:comment_child, user: user, author: user, parent: comment) 
    end 

    before { sign_in(user) } 

    describe "POST #create" do 
    context "with valid attributes" do 
     it "saves the new comment object" do 
     expect do 
      post :create, comment: attributes_for(:comment) 
     end.to change(Comment, :count).by(1) 
     end 

     it "redirects to the user" do 
     post :create, comment: attributes_for(:comment) 
     expect(response).to redirect_to user 
     end 
    end 
    end 
end 

通常你应该避免使用实例乏,而使用在大多数情况下lets。使用混合只会增加混淆,因为很难看到延迟加载甚至实例化的地方。

然后我们可以照顾的执行情况:

def create 
    @comment = current_user.comments.new(comment_params) 

    if @comment.save 
    redirect_to @comment.user, notice: 'Your comment was successfully added!' 
    else 
    # ... 
    end 
end 

private 
    def comment_params 
    # note that we don't permit the user_id to be mass assigned 
    params.require(:comment).permit(:foo, :bar, :parent_id) 
    end 

基本上你可以砍掉了很多的overcomplication的:

  • 如果没有身份验证的用户产生一个错误。与设计,你会做before_action :authenticate_user!
  • 从会话中获取用户 - 不是参数。你不想要或需要用户代表他人发表评论。
  • comments键中包裹参数。
  • 使用redirect_to @some_model_instance并让轨道执行其多态路由魔术。
  • 如果用户尝试通过错误parent_id,让ActiveRecord发出错误。

此外,您的评论模型是否真的需要一个userauthor的关系?当然,其中一个就足够了。

+0

WOW!它正在工作!你是天才!非常感谢!你的回答对我来说非常重要。我学到了很多!谢谢! :) – myf

+0

@ comment.author_id是保存实际用户的变量。如何以其他方式保存作为评论作者的用户?我在哪里可以找到代码重构的魔力? – myf

+0

增加了关于如何改善关系的解释。重构没有什么魔力 - 如果是这样的话,那么你就可以肆意破坏垃圾代码,并依靠计算机为你修复它。不幸的是,情况并非如此。有像Rubucop这样的代码质量工具,虽然有一点帮助。 – max

相关问题