7

I've got an existing codebase that I'm attempting to upgrade from Rails 3.2 to Rails 4.0

I have controller called assets_controller with a 'create' method and I have a an entry in my routes file:

resources :assets

Using jQuery for ajax on the front end, if I send a post request to '/assets' from a browser, I get 405 (Method Not Allowed):

$.ajax({method: 'POST', data: asset, url: '/assets' });

This worked just fine in Rails 3, and I can't seem to figure out what the issue is.

Updates:

Heres a simplified version of my controller:

class AssetsController < ApplicationController
  skip_before_filter :verify_authenticity_token 
    def create
        # params[:assets] is passed if a mass addition of assets (i.e. book) occurs
        assets = []
        if params[:assets]
          assets = params[:assets]
        else
          assets.push params
        end

        last_asset_id = 0

        assets.each do |asset_data|
          asset = Object.const_get(asset_data[:asset_type]).new(asset_data)
          if !asset.save
            json_false_errors(asset.errors.full_messages)
            return
          else
            last_asset_id = asset.id
          end
        end
      end
end

Heres the output from 'rake routes'

 assets GET        /assets(.:format)                                        assets#index
                                          POST       /assets(.:format)                                        assets#create
                                new_asset GET        /assets/new(.:format)                                    assets#new
                               edit_asset GET        /assets/:id/edit(.:format)                               assets#edit
                                    asset GET        /assets/:id(.:format)                                    assets#show
                                          PATCH      /assets/:id(.:format)                                    assets#update
                                          PUT        /assets/:id(.:format)                                    assets#update
                                          DELETE     /assets/:id(.:format)                                    assets#destroy

Heres my development log:

Started POST "/assets" for 127.0.0.1 at 2015-05-27 09:39:42 -0400

(yeah thats all the log has)

POST DATA: { "asset_type":"Document", "title":"DNS", "heading_id":9999, "copyrighted":false, "url":"https://confidental.url", "pubtitle":"DNS", "author":""}

Another Edit: I commented out my entire routes file for diagnostic purposes, these are the results of doing some manual testing:

POST http://localhost:8000/assets 405 (Method Not Allowed)
POST http://localhost:8000/asset 404 (Not Found)
POST http://localhost:8000/ass 404 (Not Found)

is assets some sort of reserved endpoint in rails 4?

acolchagoff
  • 1,926
  • 3
  • 18
  • 30
  • This might just be a hunch but rails 4 checks for cross-site request forgery. This means you can't post to a route without the csrf token. You should give some more details on the problem. Like controller code and how the `asset` data looks like you are posting to the controller. Rails 4 security guide: http://guides.rubyonrails.org/security.html – Jens May 27 '15 at 14:06
  • I added ' skip_before_filter :verify_authenticity_token' to my controller, which I think should skip any csrf token verification, but that doesn't seem to help. – acolchagoff May 27 '15 at 14:24
  • @JensD I've added the requested information – acolchagoff May 29 '15 at 18:10
  • denodster you might try to request parameters from the params hash with strong parameters. Rails 4 introduces strong parameters as a means to force the form post to contain certain white listed values. http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html – Jens May 30 '15 at 20:11
  • I have gem 'protected_attributes' in my Gemfile, so I don't have to worry about this until I upgrade to rails 4.1 – acolchagoff Jun 01 '15 at 13:04
  • I am seeing a very similar error. However it is due to a conflict between Grape routes and Rails routes. Some change in some code somewhere has caused this collision, despite the fact that they are using separate HTTP methods. The Grape route is: POST /:version/users The Rails route is: GET /admin/users Extremely frustrating. I do not yet have a fix. – Jeff Gandt Nov 03 '15 at 21:08

3 Answers3

8

It turns out the problem was with the name 'assets' I can't find any documentation to confirm this, but renaming the asset model and controller to something else fixed the problem.

acolchagoff
  • 1,926
  • 3
  • 18
  • 30
  • 1
    Same results on this end. I opted for the lazy fix of just wrapping the route in a scope. – fatty Jun 02 '15 at 02:01
  • 1
    was your model specifically called 'asset'? – acolchagoff Jun 05 '15 at 13:37
  • 4
    It was, but the issue looked like it came from the route name itself. Defining it as `scope :something do resources :assets end` was the simplest thing I could think of to get around this and not affect Controller or Model names and View folder structure. – fatty Jun 06 '15 at 23:12
  • 1
    Wow, thanks, that would have taken a while to figure out! ;) – Brian Underwood Aug 24 '15 at 19:19
6

This isn't just about the word assets. Rails does not like when a route path and the asset directory are in the same subdirectory.

When making a post request, you will get method not allowed. The problem is there can be no overlap with paths and the asset directory. The problem is specifically with POST requests in that path. I am assuming somewhere in rails, they must have disabled all non-GET requests for the assets directory.


In this very simple app below, you will get a method not allowed error. Because the path /welcomes is being used for a route and for an asset prefix.

File: config/environment/development.rb

config.assets.prefix = '/welcomes'

File: config/routes.rb

resources :welcomes, path: 'welcomes', only: ['index', 'create']

File: app/controllers/welcomes_controller.rb

class WelcomesController < ApplicationController
  def index
    @welcome = 'hello';
  end

  def create
    @welcome = 'world';
  end
end

File: app/views/welcomes/index.html.rb

<%= form_for(@welcome) do |f| %>
    <%= f.submit 'Submit' %>
<% end %>

File: app/views/welcomes/create.html.rb

<h1>Welcomes#create</h1>
<p>Find me in app/views/welcomes/create.html.erb</p>
Arian Faurtosh
  • 17,987
  • 21
  • 77
  • 115
2

The issue is that your asset controller routes are conflicting with the rails default /assets path.

The simplest solution is to modify your config/routes.rb file line to read as follows (or any other path of your choosing that is not assets):

resources :assets, path: 'site_assets'

s_dolan
  • 1,196
  • 1
  • 9
  • 21