【问题标题】:CRUD Laravel 4 how to link to destroy?CRUD Laravel 4如何链接销毁?
【发布时间】:2013-11-07 17:42:51
【问题描述】:

我将使用 HTML 链接销毁我的用户,但它似乎没有生成正确的链接,我做错了什么?

public function destroy($id)
{
    //Slet brugeren
    $e = new User($id);
    $e->destroy();

    //Log også brugeren ud
    Auth::logout();

    //redrect til forsiden
    Redirect::to("users/create");
}

在我看来,我称之为 {{URL::action('UserController@destroy', array($user->id))}}

【问题讨论】:

  • 它生成的链接是什么?

标签: php laravel laravel-4


【解决方案1】:

2017 年 8 月 21 日更新 Laravel 5.x

这个问题是关于 Laravel 4 的,但我把它包括在内,以防寻找 Laravel 5.x 答案的人在这里结束。表单助手(和其他一些)aren't available as of 5.x。如果您正在执行 GET 或 POST 之外的操作,您仍然需要在表单上指定一个方法。这是目前的实现方式:

<form action="/foo/bar" method="POST">
    <input type="hidden" name="_method" value="PUT">
    <input type="hidden" name="_token" value="{{ csrf_token() }}">
    <!-- other inputs... -->
</form>

您也可以使用{{ method_field('PUT') }} 而不是写出隐藏的_method 输入。

https://laravel.com/docs/5.4/routing#form-method-spoofing

Laravel 4 的原始答案

我认为当您单击链接时,它可能正在向该端点发送 GET 请求。 Laravel 中的 CRUD 根据 REST 工作。这意味着它期待的是 DELETE 请求而不是 GET。

这是来自 Boris Strahija 的 tutorial 的一种可能性。

    {{ Form::open(array('route' => array('admin.pages.destroy', $page->id), 'method' => 'delete')) }}
        <button type="submit" class="btn btn-danger btn-mini">Delete</button>
    {{ Form::close() }}

这样,您可以使用 DELETE 方法以表单形式发送请求。这篇文章解释了为什么传统链接不起作用:

您可能会注意到删除按钮位于表单内。原因是我们控制器的 destroy() 方法需要一个 DELETE 请求,可以通过这种方式完成。如果按钮是一个简单的链接,请求将通过 GET 方法发送,我们不会调用 destroy() 方法。

【讨论】:

  • 是否可以不使用 Laravel 的表单构建器来创建此按钮?
  • @IozadaOmr 看起来文档解释了 Laravel 是如何做到这一点的:laravel.com/docs/html#opening-a-form。相关部分是这样的:“注意:由于 HTML 表单仅支持 POST 和 GET,因此 PUT 和 DELETE 方法将通过自动向表单添加 _method 隐藏字段来进行欺骗。”所以看起来在服务器端,他们必须读取该输入的值并使用指定的方法。我想没有什么能阻止你这样做。
  • 对于 Laravel 5 等价物,请参阅下面的 my answer
【解决方案2】:

另一个“干净”的解决方案是按照here 描述的那样使用 Rails 方式:

  1. 公开新建一个.js文件并编写这个函数:

    $(function(){
       $('[data-method]').append(function(){
            return "\n"+
            "<form action='"+$(this).attr('href')+"' method='POST' style='display:none'>\n"+
            "   <input type='hidden' name='_method' value='"+$(this).attr('data-method')+"'>\n"+
            "</form>\n"
       })
       .removeAttr('href')
       .attr('style','cursor:pointer;')
       .attr('onclick','$(this).find("form").submit();');
    });
    
  2. 在包含 jQuery 之后,不要忘记在模板中包含 .js 文件。

  3. 使用经典的link_to()link_to_method() 函数创建删除记录的链接。请记住包含"data-method"="DELETE" 参数:

    {{ link_to_route('tasks.destroy', 'D', $task->id, ['data-method'=>'delete']) }}
    

我喜欢这个,它看起来比在刀片模板中使用 Form::open(); 膨胀你的代码要干净得多。

【讨论】:

  • 效果很好。谢谢你。它会更多地清理代码,主要是当您在同一页面上需要它 3-4 次时。
  • @PhilippeGilbert 那里的“D”有什么用?
  • 我更喜欢把$(this).attr('data-method')换成$(this).data('method')
  • 引入 Rails UJS 也值得考虑——它与框架无关,不再依赖于 jQuery。它增加了对有用的data 属性的整体帮助的支持,使处理这些东西变得非常容易。它在 NPM 上可用 rails-ujs- npmjs.com/package/rails-ujs
【解决方案3】:

一个很酷的 ajax 解决方案是这样的:

function deleteUser(id) {
    if (confirm('Delete this user?')) {
        $.ajax({
            type: "DELETE",
            url: 'users/' + id, //resource
            success: function(affectedRows) {
                //if something was deleted, we redirect the user to the users page, and automatically the user that he deleted will disappear
                if (affectedRows > 0) window.location = 'users';
            }
        });
    }
}

<a href="javascript:deleteUser('{{ $user->id }}');">Delete</a>

在 UserController.php 中我们有这个方法:

public function destroy($id)
{
    $affectedRows  = User::where('id', '=', $id)->delete();

    return $affectedRows;
}

 

【讨论】:

  • 如果您收到有关令牌不匹配异常 (Laravel 5) 的错误,您应该添加 $.ajaxSetup 行以发送 _token 字段。
【解决方案4】:
{{Form::open(['method'=>'delete','action'=>['ResourceController@destroy',$resource->id]])}}
 <button type="submit">Delete</button>                      
{{Form::close()}}   

【讨论】:

    【解决方案5】:

    这是一个老问题,但我只是在寻找一个快速的答案,对其中任何一个都不满意。我会建议任何有同样问题的人创建一条新路线。过分担心 crud 合规性是愚蠢的,因为 HTML 没有这样的事情。无论是隐藏的表单字段还是获取路径,任何解决方案都只能勉强适应。

    所以,在你的路线中,你可能有这样的东西:

    Route::resource('users', 'UsersController'); 这样做的问题是,到达“destroy”方法的唯一方法是发送一个 post 请求,该请求具有一个名为“_method”的隐藏输入和一个值为“DELETE”的值。

    只需在该行下添加: Route::get('users/{id}/destroy',['as'=&gt;'users.delete','uses'=&gt;'UsersController@destroy']);

    现在您有了一条可以从HTML::linkRouteRoute::url 或任何您喜欢的方式访问的路线。

    例如: {{ HTML::linkRoute( 'users.delete', 'Delete' , [ 'id' =&gt; $user-&gt;id ]) }}

    编辑

    我想澄清一下,虽然我已经解释了为什么向后弯腰以适应 crud 合规性有点愚蠢,但如果仅通过 POST 请求进行更改,您的应用仍然会更安全。

    【讨论】:

    • 使用 GET 进行删除不是很明智
    • 这就是您遵循程序而不是实际检查您面临的问题的那种点。无论如何都没有 HTTP 上的删除方法,所以严格遵守无论如何都只是假装。
    • 另外,它实际上达到了问题的目的。
    • 其实应该说,HTML中没有Put或Delete; HTTP 很好地支持它们。
    • 嗯,HTTP 对它们的定义如此明显.. 我没有说它违反程序、标准或其他什么,只是它不明智。是的,它以某种方式回答了这个问题,但如果有人问了“错误”的问题,那么你指出来会更有帮助。
    【解决方案6】:

    想要在表单外发送 DELETE 请求?

    好吧,Jeffrey Way 创建了一个不错的 javascript,它可以为您创建一个表单并使用它,您只需将 data-method="delete" 添加到您的删除链接。

    要使用,请导入script,并使用data-method="DELETE" 属性创建一个链接。

    脚本:

    (function() {
    
      var laravel = {
        initialize: function() {
          this.methodLinks = $('a[data-method]');
    
          this.registerEvents();
        },
    
        registerEvents: function() {
          this.methodLinks.on('click', this.handleMethod);
        },
    
        handleMethod: function(e) {
          var link = $(this);
          var httpMethod = link.data('method').toUpperCase();
          var form;
    
          // If the data-method attribute is not PUT or DELETE,
          // then we don't know what to do. Just ignore.
          if ( $.inArray(httpMethod, ['PUT', 'DELETE']) === - 1 ) {
            return;
          }
    
          // Allow user to optionally provide data-confirm="Are you sure?"
          if ( link.data('confirm') ) {
            if ( ! laravel.verifyConfirm(link) ) {
              return false;
            }
          }
    
          form = laravel.createForm(link);
          form.submit();
    
          e.preventDefault();
        },
    
        verifyConfirm: function(link) {
          return confirm(link.data('confirm'));
        },
    
        createForm: function(link) {
          var form = 
          $('<form>', {
            'method': 'POST',
            'action': link.attr('href')
          });
    
          var token = 
          $('<input>', {
            'type': 'hidden',
            'name': 'csrf_token',
              'value': '<?php echo csrf_token(); ?>' // hmmmm...
            });
    
          var hiddenInput =
          $('<input>', {
            'name': '_method',
            'type': 'hidden',
            'value': link.data('method')
          });
    
          return form.append(token, hiddenInput)
                     .appendTo('body');
        }
      };
    
      laravel.initialize();
    
    })();
    

    【讨论】:

    • 对我来说,这是最干净的解决方案。这种技术称为 UJS 或 Unobtrusive JavaScript
    • 真的很有帮助。你拯救了这一天。
    • 虽然这种方法不显眼,但它不会优雅地降级。如果用户关闭了 js,他将无法使用该功能。我想我们可以说这是过去的问题。
    • 对于那些使用 Laravel 5.x 的人,令牌现在被称为 _token 而不是 csrf_token,所以在线更新:'name': 'csrf_token'
    • 另外,您需要找出一种将令牌提供给脚本的方法。我将token添加到链接中(类似于设置方法的方式):data-token="{{ csrf_token() }}",并切换行:'value': '&lt;?php echo csrf_token(); ?&gt;''value': link.data('token')'
    【解决方案7】:

    对于那些希望在 Laravel 5 中创建删除按钮的人:

    {!! Form::open(['action' => ['UserController@destroy', $user->id], 'method' => 'delete']) !!}
      {!! Form::submit('Delete', ['class'=>'btn btn-danger btn-mini']) !!}
    {!! Form::close() !!}
    

    这类似于 Tayler 的回答,但我们使用新的刀片逃生标签({!!!!}),我们使用 Form 外观来生成按钮,我们使用更优雅的方法链接到控制器.

    在 Laravel Forms & HTML package 被自动拉入。在 Laravel 5 中,我们必须将此包添加到 composer.json

    ...
    "required": {
      ...
      "laravelcollective/html": "^5.1"
    }
    ...
    

    现在在config/app.php 中添加服务提供者和别名:

    ...
    'providers' => [
      ...
      Collective\Html\HtmlServiceProvider::class,
    ],
    
    'aliases' => [
      ...
      'Form' => Collective\Html\FormFacade::class,
      'Html' => Collective\Html\HtmlFacade::class,
    ],
    

    上面会输出

    <form method="POST" action="https://yourdomain.tld/users/1" accept-charset="UTF-8">
      <input name="_method" type="hidden" value="DELETE">
      <input name="_token" type="hidden" value="xxxCrAZyT0K3nsTr!NGxxx">
      <input class="btn btn-danger btn-mini" type="submit" value="Delete">
    </form>
    

    如果您使用的是不同的表单构建器,请确保它生成的内容与上述类似。

    【讨论】:

    • 如果你使用引导程序,类是.btn-xs,而不是.btn-mini。我很高兴你提到 Laravel 默认不再包含 HTML 包。
    【解决方案8】:

    我试过你的代码,这样使用它并且工作正常:

        <a href="{{URL::action('UserController@destroy',['id'=>$user->id]) }}" 
    onclick=" return confirm('Are you sure you want to delete this?')" 
    class="btn btn-default">
       DELETE     </a>
    

    我认为唯一的问题在于您的数组:

    ['id'=>$user->id]
    

    【讨论】:

      【解决方案9】:

      对于那些希望在 laravel 5 中使用锚标签创建删除按钮的人。

      {!! Form::open(['action' => ['UserController@destroy', $user->id], 'method' => 'DELETE', 'name' => 'post_' . md5($user->id . $user->created_at)]) !!}
          <a href="javascript:void(0)" title="delete" onclick="if (confirm('Are you sure?')) { document.post_<?= md5($user->id . $user->created_at) ?>.submit(); } event.returnValue = false; return false;">
              <span class="icon-remove"></span>
          </a>
      {!! Form::close() !!}
      

      【讨论】:

      • 不要把 js 和 HTML 混在一起——这只是时间问题,信息会改变,搜索+替换不是程序员最好的朋友。
      • @Srneczek 这里的想法是使用锚标签创建删除按钮。我同意这条信息会改变,但可以通过各种方式使其动态化。
      • 是的,我对那条评论有点迂腐,我知道,但是嘿,作为程序员,你必须迂腐,尤其是关于良好实践的做法,否则你最终会得到没人能理解的不可读代码。而且这个网站通常是由初学者访问的,他们至少应该从一开始就知道良好的做法。许多人只会复制和粘贴您的代码并进行一些小改动。我不喜欢只是“工作”的代码。
      猜你喜欢
      • 2015-07-29
      • 1970-01-01
      • 2015-07-05
      • 1970-01-01
      • 2016-08-09
      • 2013-11-24
      • 1970-01-01
      • 2013-07-08
      • 2014-09-05
      相关资源
      最近更新 更多