【问题标题】:RSpec controller: redirect_to other controllerRSpec 控制器:redirect_to 其他控制器
【发布时间】:2016-01-20 19:09:29
【问题描述】:

我在测试我的 CommentsController 时遇到了这个问题:

失败/错误:redirect_to user_path(@comment.user),注意:'你的 评论已成功添加! ActionController::UrlGenerationError: 没有路线匹配 {:action=>"show", :controller=>"users", :id=>nil} 缺少必需的键:[: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 \.\-@:),.!?"']*$\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 cmets 控制器中的用户吗?有没有做对的可能性?谢谢你的时间。

【问题讨论】:

    标签: ruby-on-rails ruby rspec


    【解决方案1】:

    基本上该错误是由@comment.user 为nil 引起的。

    让我们通过清理规范开始修复它:

    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
    

    基本上你可以减少很多过于复杂的事情:

    • 如果没有经过身份验证的用户,则会引发错误。使用 Devise,您可以使用 before_action :authenticate_user!
    • 从会话中获取用户 - 而不是参数。您不希望或不需要用户代表他人发表评论。
    • 将参数包装在 comments 键中。
    • 使用 redirect_to @some_model_instance 并让 Rails 发挥其多态路由的魔力。
    • 如果用户试图传递一个错误的parent_id,让 ActiveRecord 抛出一个错误。

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

    【讨论】:

    • 哇!它正在工作!你真是天才!非常感谢!你的回答对我来说非常重要。我学到了很多!谢谢! :)
    • @comment.author_id 是保存实际用户的变量。如何以其他方式保存评论作者的用户?我在哪里可以找到代码重构的魔力?
    • 添加了有关如何改进关系的说明。重构没有什么魔力——如果是这样的话,你可以直接敲出垃圾代码并依靠计算机为你修复它。不幸的是,事实并非如此。有一些像 Rubucop 这样的代码质量工具确实有点帮助。
    猜你喜欢
    • 1970-01-01
    • 2013-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-29
    • 1970-01-01
    相关资源
    最近更新 更多