开发者

:destroy method not working in a Rails 3.1.0 rc2 application?

开发者 https://www.devze.com 2023-03-13 18:49 出处:网络
I\'m working through Agile Web Development with Rails and my :destroy method fro开发者_高级运维m products_controller just takes me to the product show page. I ran into this problem with another applic

I'm working through Agile Web Development with Rails and my :destroy method fro开发者_高级运维m products_controller just takes me to the product show page. I ran into this problem with another application a couple weeks ago, on a Rails 3.0 application. In that case, I had to edit the javascript, so I'm guessing that might work here, too.

Here's my javascript_link_tag from my application.html.erb file:

<%= javascript_include_tag :defaults %>
<%= csrf_meta_tags %>

Here's the :destroy method from my controller:

def destroy
  @product = Product.find(params[:id])
  @product.destroy

respond_to do |format|
  format.html { redirect_to products_url }
  format.json { head :ok }

I've got the jquery gem installed, and jquery is the default library with Rails 3.1, so maybe I'm wrong about why this isn't working? Any help is greatly appreciated. Thanks!


If you're not using javascript, the :delete action just takes you to that particular post.

If you wish to delete the entry, use

<%= button_to "destroy", post, :method => :delete %>    

instead of

<%= link_to "destroy", post, :method => :delete %>     

Here's how you get the javascript to work(make sure the jquery loads though).

Load up rails.js from my repository below after your jquery code.

Take a look at the following files from my repository at https://github.com/imjp/bluh

app/assets/javascripts/rails.js
app/assets/javascripts/app.js
app/views/posts/index.html    look for the delete button at the bottom
app/views/controllers/posts_controller.rb   look for the destroy action

The code should now make your destroy link work via ajax.


This is because you are not including the proper js files or because you are not supplying the delete method. I looks like you got this going correctly:

app/views/layouts/application.html.erb

<%= stylesheet_link_tag :all %>
<%= javascript_include_tag :defaults %>
<%= csrf_meta_tag %>

The delete method is not working because of how rails 3 needs the info from the csrf meta tag which is generated by the javascript files from :defaults

Then in your link_to method make sure you include this:

<%= link_to "destroy", post, :method => :delete %>


I faced the same issue...

Check my answer on this Delete / Destroy is not working in rails 3 with Jquery

If you are using Jquery not prototype then you need to add Jquery.rails.js in your project else everytime you try to delete anything it will take you to show page.

I dont remember from where I got the solution and this Jquery.rails.js file. But sure from some trust-able source.

Here is the code for that file. May be will help somebody.

jQuery(function ($) {
    var csrf_token = $('meta[name=csrf-token]').attr('content'),
        csrf_param = $('meta[name=csrf-param]').attr('content');

    $.fn.extend({
        /**
         * Triggers a custom event on an element and returns the event result
         * this is used to get around not being able to ensure callbacks are placed
         * at the end of the chain.
         *
         * TODO: deprecate with jQuery 1.4.2 release, in favor of subscribing to our
         *       own events and placing ourselves at the end of the chain.
         */
        triggerAndReturn: function (name, data) {
            var event = new $.Event(name);
            this.trigger(event, data);

            return event.result !== false;
        },

        /**
         * Handles execution of remote calls firing overridable events along the way
         */
        callRemote: function () {
            var el      = this,
                data    = el.is('form') ? el.serializeArray() : [],
                method  = el.attr('method') || el.attr('data-method') || 'GET',
                url     = el.attr('action') || el.attr('href');

            if (url === undefined) {
              throw "No URL specified for remote call (action or href must be present).";
            } else {
                if (el.triggerAndReturn('ajax:before')) {
                    $.ajax({
                        url: url,
                        data: data,
                        dataType: 'script',
                        type: method.toUpperCase(),
                        beforeSend: function (xhr) {
                            el.trigger('ajax:loading', xhr);
                        },
                        success: function (data, status, xhr) {
                            el.trigger('ajax:success', [data, status, xhr]);
                        },
                        complete: function (xhr) {
                            el.trigger('ajax:complete', xhr);
                        },
                        error: function (xhr, status, error) {
                            el.trigger('ajax:failure', [xhr, status, error]);
                        }
                    });
                }

                el.trigger('ajax:after');
            }
        }
    });

    /**
     *  confirmation handler
     */
    $('a[data-confirm],input[data-confirm]').live('click', function () {
        var el = $(this);
        if (el.triggerAndReturn('confirm')) {
            if (!confirm(el.attr('data-confirm'))) {
                return false;
            }
        }
    });


    /**
     * remote handlers
     */
    $('form[data-remote]').live('submit', function (e) {
        $(this).callRemote();
        e.preventDefault();
    });
    $('a[data-remote],input[data-remote]').live('click', function (e) {
        $(this).callRemote();
        e.preventDefault();
    });

    $('a[data-method]:not([data-remote])').live('click', function (e){
        var link = $(this),
            href = link.attr('href'),
            method = link.attr('data-method'),
            form = $('<form method="post" action="'+href+'">'),
            metadata_input = '<input name="_method" value="'+method+'" type="hidden" />';

        if (csrf_param != null && csrf_token != null) {
          metadata_input += '<input name="'+csrf_param+'" value="'+csrf_token+'" type="hidden" />';
        }

        form.hide()
            .append(metadata_input)
            .appendTo('body');

        e.preventDefault();
        form.submit();
    });

    /**
     * disable-with handlers
     */
    var disable_with_input_selector = 'input[data-disable-with]';
    var disable_with_form_selector = 'form[data-remote]:has(' + disable_with_input_selector + ')';

    $(disable_with_form_selector).live('ajax:before', function () {
        $(this).find(disable_with_input_selector).each(function () {
            var input = $(this);
            input.data('enable-with', input.val())
                 .attr('value', input.attr('data-disable-with'))
                 .attr('disabled', 'disabled');
        });
    });

    $(disable_with_form_selector).live('ajax:after', function () {
        $(this).find(disable_with_input_selector).each(function () {
            var input = $(this);
            input.removeAttr('disabled')
                 .val(input.data('enable-with'));
        });
    });
});


You might have removed the rails.js file, the file containing the javascript code that read the data-method attribute in your link created by the link_to method, and change the verb of the request (get, post, put, delete). I had the exact same problem because I was only loading the jquery.js through the javascript_include_tag.

If this is the case, make sure you have the rails.js and it should fix the problem!


Agile Web Development suggests changing the default application.html.erb from:

<%= stylesheet_link_tag "application" %>
<%= javascript_include_tag "application" %>

to

<%= stylesheet_link_tag :all %>
<%= javascript_include_tag :defaults %>

Keep to the rails default and it should work fine.

0

精彩评论

暂无评论...
验证码 换一张
取 消