将yield()插入form_for()会引发测试

时间:2016-10-06 23:37:36

标签: ruby-on-rails railstutorial.org yield form-for

我跟随http://railstutorial.org。我把所有内容都排除在10.2以外。然后我遇到了某种问题。我目前的申请代码如下。

7.3.4节中的练习2让我向应用程序添加了一些额外的代码。因此,我必须更新路线并在第10.1.1节中创建我自己的解决方案练习2(作者建议使用yieldprovide方法,我做过 - 在代码中看到)。在这之后,我创建了一个成功和不成功编辑用户的测试(第10.1.3和10.1.4节)。两个测试都通过了,但我的应用程序没有按预期工作。

问题描述:当我登录时(不是必需的,授权是10.2部分的目标)并转到编辑页面/ users /:id / edit,网站正常工作。当我按"保存更改"按钮,它返回一个错误(无论我尝试编辑哪个用户):

No route matches [PATCH] "/users/1/edit"
Rails.root: /home/akazecik/workspace/sample_app

并且所有测试都通过了。

另一方面,当我将@user替换为user_path(@user)文件中的edit.html.erb时,错误消失了,网站正常工作。所有测试仍然通过。

在第三手牌上&#39;当我在yield(:needed_link)文件中用@user替换_form.html.erb时(因此省略了第一种情况下使用yield方法)并忽略不通过测试(显而易见的事情):< / p>

FAIL["test_invalid_signup_information", UsersSignupTest, 0.5256564110004547]
test_invalid_signup_information#UsersSignupTest (0.53s)
        Expected at least 1 element matching "form[action="/signup"]", found 0..
        Expected 0 to be >= 1.
        test/integration/users_signup_test.rb:6:in `block in <class:UsersSignupTest>'

我再次获得工作现场,其余的测试似乎都过去了。

所以我的问题是:

  • 为什么测试通过,即使我的网站不起作用?为什么users_edit_test.rb能够更新用户,即使我不能
  • @useryield(:needed_link)provide(:needed_link, @user)之间有什么区别?
  • 在10.2节的开头,我们读到了操作编辑和更新:
  

他们允许任何人(甚至是非登录用户)访问任一操作,   任何登录用户都可以更新任何其他用户的信息

情况并非如此,因为即使是非登录用户,我也可以更新信息。我错过了什么?登录后,我的意思是logged_in? app/helpers/sessions_helper.rb中的方法返回true。

/app/views/users/new.html.erb

<% provide(:title, 'Sign up') %>
<% provide(:button_text, 'Create my account') %>
<% provide(:needed_link, signup_path) %>
<h1>Sign up</h1>
<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= render 'form' %>
  </div>
</div>

/app/views/users/edit.html.erb

<% provide(:title, 'Edit user') %>
<% provide(:button_text, 'Save changes') %>
<% provide(:needed_link, @user) %>
<h1>Update your profile</h1>
<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= render 'form' %>
    <div class="gravatar_edit">
      <%= gravatar_for @user %>
      <a href="http://gravatar.com/emails" target="_blank">Change</a>
    </div>
  </div>
</div>

/app/views/users/_form.html.erb

<%= form_for(@user, url: yield(:needed_link)) do |f| %>
  <%= render 'shared/error_messages', object: @user %>

  <%= f.label :name %>
  <%= f.text_field :name, class: 'form-control' %>

  <%= f.label :email %>
  <%= f.email_field :email, class: 'form-control' %>

  <%= f.label :password %>
  <%= f.password_field :password, class: 'form-control' %>

  <%= f.label :password_confirmation %>
  <%= f.password_field :password_confirmation, class: 'form-control' %>

  <%= f.submit yield(:button_text), class: "btn btn-primary" %>
<% end %>

应用/控制器/ users_controller.rb

class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])
  end
  def new
    @user = User.new
  end
  def create
    @user = User.new(user_params)     # Not the final implementation!
    if @user.save
      log_in @user
        flash[:success] = "Welcome to the Sample App!"
        redirect_to user_url(@user)
    else
        render 'new'
    end
  end
  def edit
    @user = User.find(params[:id])
  end
  def update
    @user = User.find(params[:id])
    if @user.update_attributes(user_params)
      flash[:success] = "Profile updated"
      redirect_to user_path(@user)
    else
      render 'edit'
    end
  end
  private
      def user_params
        params.require(:user).permit(:name, :email, :password, :password_confirmation)
    end
end

测试/集成/ users_edit_test.rb

require 'test_helper'

class UsersEditTest < ActionDispatch::IntegrationTest
  def setup
    @user = users(:michael)
  end

  test "unsuccessful edit" do
    get edit_user_path(@user)
    assert_template 'users/edit'
    patch user_path(@user), params: {user: { name: "", email: "foo@invalid", password: "foo", password_confirmation: "bar" } }
    assert_template 'users/edit'
    assert_select 'div.alert', "The form contains 4 errors."
  end

  test "successful edit" do
    get edit_user_path(@user)
    assert_template 'users/edit'
    name  = "Foo Bar"
    email = "foo@bar.com"
    patch user_path(@user), params: { user: { name:  name,
                                              email: email,
                                              password:              "",
                                              password_confirmation: "" } }
    assert_not flash.empty?
    assert_redirected_to @user
    @user.reload
    assert_equal name,  @user.name
    assert_equal email, @user.email
  end
end

测试/装置/ users.yml里

michael:
  name: Michael Example
  email: michael@example.com
  password_digest: <%= User.digest('password') %>

应用/助手/ sessions_helper.rb

module SessionsHelper
    # Logs in the given user.
    def log_in(user)
        session[:user_id] = user.id
    end

  # Remembers a user in a persistent session.
  def remember(user)
    user.remember
    cookies.permanent.signed[:user_id] = user.id
    cookies.permanent[:remember_token] = user.remember_token
  end

    # Returns the current logged-in user (if any).
    def current_user
      if (user_id = session[:user_id])
        @current_user ||= User.find_by(id: user_id)
      elsif (user_id = cookies.signed[:user_id])
        user = User.find_by(id: user_id)
        if user && user.authenticated?(cookies[:remember_token])
          log_in user
          @current_user = user
        end
      end
    end

    # Returns true if the user is logged in, false otherwise.
    def logged_in?
        !current_user.nil?
    end

  # Forgets a persistent session.
  def forget(user)
    user.forget
    cookies.delete(:user_id)
    cookies.delete(:remember_token)
  end

  # Logs out the current user.
  def log_out
    forget(current_user)
    session.delete(:user_id)
    @current_user = nil
  end
end

1 个答案:

答案 0 :(得分:0)

<% provide(:needed_link, @user) %>

@user不是链接 - 它是用户实例。您可以将模型的实例传递给链接生成方法(例如,控制器中的render或模板中的link_to),该方法使用Rails-magic *将模型转换为链接......但它本身并不是链接,所以如果你试图在一个不是特殊(不成文)方法之一的地方使用它......它就不会工作。< / p>

这可能就是为什么:link_needed的东西没有按照你预期的方式运作。

表单的url可能不是其中一种方法......所以您需要使用edit_user_path(@user)方法实际创建链接。

*幕后,一些rails方法在模型上调用url_for将其转换为正确的链接 - 但只有一些方法。