Edit: I've seen a number of these but couldn't find an answer to this so I'm attempting to document it as best I can and asking this question.
I have a model-less rails app (calling an API) with a nested comments resource. I am able to post a comment against a story if I go directly to the comments#new or comments#index action and accordingly post to the comments#create action.
However I'd like very much to be able to post a comment on the same page as the #show action of the parent resource: (opusses#show)
I've tried using the rails url_helper path from rake routes as opuss_comments_path and explicitly stating the controller and action. In both cases I still get this message:
No route matches {:controller=>"comments", :action=>"create"}
Here is my routes db:
resources :users
resources :sessions, only: [:new, :create, :destroy]
resources :osessions, only: [:new, :create, :destroy]
resources :authors do
member do
get :following
get :followed
post :follow
end
end
resources :opusses do
resources :comments
member do
get :like
get :authorfeed
post :repost
end
end
And my Rake Routes:
DELETE /authors/:id(.:format) authors#destroy
opuss_comments GET /opusses/:opuss_id/comments(.:format) comments#index
POST /opusses/:opuss_id/comments(.:format) comments#create
new_opuss_comment GET /opusses/:opuss_id/comments/new(.:format) comments#new
edit_opuss_comment GET /opusses/:opuss_id/comments/:id/edit(.:format) comments#edit
opuss_comment GET /opusses/:opuss_id/comments/:id(.:format) comments#show
PUT /opusses/:opuss_id/comments/:id(.:format) comments#update
DELETE /opusses/:opuss_id/comments/:id(.:format) comments#destroy
&&
like_opuss GET /opusses/:id/like(.:format) opusses#like
authorfeed_opuss GET /opusses/:id/authorfeed(.:format) opusses#authorfeed
repost_opuss POST /opusses/:id/repost(.:format) opusses#repost
opusses GET /opusses(.:format) opusses#index
POST /opusses(.:format) opusses#create
new_opuss GET /opusses/new(.:format) opusses#new
edit_opuss GET /opusses/:id/edit(.:format) opusses#edit
opuss GET /opusses/:id(.:format) opusses#show
PUT /opusses/:id(.:format) opusses#update
DELETE /opusses/:id(.:format) opusses#destroy
When I call the code below from comments#index page it works perfectly. However it's quite common to post to another form from a different controller and when I call this code from the opusses#show page it fails with the error above.
On the off chance it had to do with the URL helper, I tried specifying the controller and action explicitly and that still didn't work - generated the same error.
Classic newbie mistake, but for others benefit =>
I had rake routes and I had the path correct, what I wasn't doing was submitting a the id of the parent resource. So POST to the path and include the object in question. In my case this mean opuss_comments_path(#opuss["xyz"]) where xyz was the id of my object.
opuss_comments GET /opusses/:opuss_id/comments(.:format) comments#index
POST /opusses/:opuss_id/comments(.:format) comments#create
Ah.. learning. :)
Based on your routes, You shouldn't have to use a url helper. but you do have to make sure that you have a handle on the Opuss object in the controller. so do something like this ;
#opuss = Opuss.find(params[:id]) #or your equivalent finder code
#comment = #opuss.comments.build
and then in your view;
<%= form_for([#opuss, #comment]) do |f| %>
.... rest of form
<% end %>
Related
I just only want to make a test and trying to understand the routes on rails. This is what I have on my controller:
class ItemsController < ApplicationController
def index
#data = params[:number]
end
end
and in index.html.erb
The number: <%= params[:number] %>
Well, if I made curl http://localhost:3000/?number=100 I can see on the view:
The number: 100
So, here everything is correct. But, I want to do the same, but with POST verb. So when I made curl -d "number=100" http://localhost:3000 I get the following error:
No route matches [POST] "/"
I have made:
def create
render plain: params[:number].inspect
end
to see the parameters, but as I said before, only works with GET verb.
So my question: How I can see the data sent by POST to the controller with curl and see the result on my view index.html.erb?
Note: On routes.rb I have:
Rails.application.routes.draw do
#get 'items/index'
resources :items
root 'items#index'
end
Notes: Based on the answer received, I have 2 more questions:
Why the verb GET works on http://localhost:3000/?number=100 and the same with http://localhost:3000/items/?number=100? Why the same does not happens with POST?
How can I remove the message No route matches [POST] "/" if the user points directly to http://localhost:3000 with POST verb?
You are posting to the root_url. Instead, POST your request to the items_url:
curl -d "number=100" http://localhost:3000/items
update:
Why the verb GET works on http://localhost:3000/?number=100 and the
same with http://localhost:3000/items/?number=100? Why the same does
not happens with POST?
The GET request to /?number=100 works because you have specified root 'items#index' in your routes file. This specifically creates a GET route that is mapped to the index action of the items controller.
How can I remove the message No route matches [POST] "/" if the user
points directly to http://localhost:3000 with POST verb?
You can create a single POST route using the post keyword:
# routes.rb
root 'items#index'
post '/', to: 'items#create'
which would generate the routes:
root GET / items#index
POST / items#create
(from your project directory run the command rails routes)
Or you can use the resource method to create all the CRUD paths:
resources :items, path: '/'
... which would create the following routes:
items GET / items#index
POST / items#create
new_item GET /new(.:format) items#new
edit_item GET /:id/edit(.:format) items#edit
item GET /:id(.:format) items#show
PATCH /:id(.:format) items#update
PUT /:id(.:format) items#update
DELETE /:id(.:format) items#destroy
Keep in mind that this may cause routing collisions if you try to add other resources to your app. If you need to add other resources, add them before these routes in the routes.rb file. Rails evaluates the routes file from top to bottom, so these resources would only load if no other paths match.
For more information see http://edgeguides.rubyonrails.org/routing.html
I'm taking an MOOC and the goal of this exercise is to add a new functionality to typo, where i can merge two articles together.
When I add the route to my new function merge to the routes.rb I'm losing the functionality to delete articles. I think something clashes here, but I have no idea what.
The original routes.rb:
%w{advanced cache categories comments content profiles feedback general pages
resources sidebar textfilters themes trackbacks users settings tags redirects seo post_types }.each do |i|
match "/admin/#{i}", :to => "admin/#{i}#index", :format => false
match "/admin/#{i}(/:action(/:id))", :to => "admin/#{i}", :action => nil, :id => nil, :format => false
end
This method in articles.rb creates the correct url for deleting
def delete_url
blog.url_for(:controller => "/admin/content", :action =>"destroy",:id => id)
end
correct url:
http://example.com/admin/content/destroy/7
If i follow this link i can successfully delete an article.
However, if I add the following before that to my routes.rb:
namespace "admin" do
resources :content do
post :merge, on: :member, as: :merge
end
end
The new merging functionality and forms are working fine, but the method delete_url now produces something like this:
http://example.com/admin/content/7
and if I follow a link created by this method i get:
Unknown action
The action 'show' could not be found for Admin::ContentController
Maybe I'm overwriting something? I can't figure out what's happening here and why this affects the delete action / route.
Thanks in advance!
EDIT: rake routes | grep content:
with the original routes.rb gives me:
admin_content /admin/content {:controller=>"admin/content", :action=>"index"}
/admin/content(/:action(/:id)) {:action=>nil, :id=>nil, :controller=>"admin/content"}
whereas my modified routes.rb produces
merge_admin_content POST /admin/content/:id/merge(.:format) {:action=>"merge", :controller=>"admin/content"}
admin_content_index GET /admin/content(.:format) {:action=>"index", :controller=>"admin/content"}
POST /admin/content(.:format) {:action=>"create", :controller=>"admin/content"}
new_admin_content GET /admin/content/new(.:format) {:action=>"new", :controller=>"admin/content"}
edit_admin_content GET /admin/content/:id/edit(.:format) {:action=>"edit", :controller=>"admin/content"}
admin_content GET /admin/content/:id(.:format) {:action=>"show", :controller=>"admin/content"}
PUT /admin/content/:id(.:format) {:action=>"update", :controller=>"admin/content"}
DELETE /admin/content/:id(.:format) {:action=>"destroy", :controller=>"admin/content"}
/admin/content {:controller=>"admin/content", :action=>"index"}
/admin/content(/:action(/:id)) {:action=>nil, :id=>nil, :controller=>"admin/content"}
Okay, thanks to #guitarman i worked through my routes code and found out I can add the following except:
namespace "admin" do
resources :content, except: [:index, :show, :update, :destroy, :edit, :new, :create] do
post :merge, on: :member, as: :merge
end
end
after that, the rake routes just shows the additional merge route I wanted and my destroy action works fine again.
Check rake routes command. I think there is a route /admin/content/:id which will be created by resources :content in the namespace "admin".
Your request to http://example.com/admin/content/7 will be catched be the defined route but I gess you have no show action in the controller.
Better:
namespace "admin" do
post "/content/:id/merge", to: "admin/content#merge", as: :merge
end
For more information about recources and the CRUD operations please see the rails routing guide.
I'm struggling with this line in the _form: <%= simple_form_for(#post, url: blog_path) do |f| %>, which gives me the error:
No route matches {:action=>"show", :controller=>"posts"} missing required keys: [:id]
Keep in mind that in my routes I have: resources :blog, controller: 'posts', which is to say I am working off of a posts MVC, but I wanted /posts/ to be replaced by /blog/ in the routes.
posts_controller
def new
#post = Post.new
end
def edit
end
The _form works when I go to edit, but not create new.
routes
blog_index GET /blog(.:format) posts#index
POST /blog(.:format) posts#create
new_blog GET /blog/new(.:format) posts#new
edit_blog GET /blog/:id/edit(.:format) posts#edit
blog GET /blog/:id(.:format) posts#show
PATCH /blog/:id(.:format) posts#update
PUT /blog/:id(.:format) posts#update
DELETE /blog/:id(.:format) posts#destroy
model_path by default routing logic in Rails leads to blog#show => /blogs/:id
Change it to blogs_path.
Looking at you routes, I see obvious naming conflict, you must be defined routes wrong.
Be sure it looks like resources :posts, :as=>"blogs", both plural.
UPD
If you want to have only one blog, then resource :post, :as=>"blog", both singular.
But that means one actual input. I'm quite sure you speak of blog/post1, blog/post2, otherwise I can't see any sense in calling it blog?
sorry my english...
<%= simple_form_for(#post, url: blog_path) do |f| %> In this line you are redirecting the form to show (blog_path)
But , depending on the route , the show needs an id (blog GET /blog/:id(.:format)).
You must create a "create" method in the controller that receives the parameters strong ...
There is another method you can use: rails generate scaffold_controller posts
This will build the full CRUD , so you only have to configure the parameters
I hope that helps you
I got best of both worlds this way:
resources :blog, to: 'posts'
resources :posts
I'm searching a reason why rake routes doesn't match the index path of my nested resource.
Here is my code:
namespace :api do
resources :photos do
resource :comments
end
end
Here is the result of the command: rake routes | grep comment
batch_action_admin_user_comments POST /admin/user_comments/batch_action(.:format) admin/user_comments#batch_action
admin_user_comments GET /admin/user_comments(.:format) admin/user_comments#index
POST /admin/user_comments(.:format) admin/user_comments#create
new_admin_user_comment GET /admin/user_comments/new(.:format) admin/user_comments#new
edit_admin_user_comment GET /admin/user_comments/:id/edit(.:format) admin/user_comments#edit
admin_user_comment GET /admin/user_comments/:id(.:format) admin/user_comments#show
PATCH /admin/user_comments/:id(.:format) admin/user_comments#update
PUT /admin/user_comments/:id(.:format) admin/user_comments#update
DELETE /admin/user_comments/:id(.:format) admin/user_comments#destroy
admin_comments GET /admin/comments(.:format) admin/comments#index
POST /admin/comments(.:format) admin/comments#create
admin_comment GET /admin/comments/:id(.:format) admin/comments#show
api_photo_comments POST /api/photos/:photo_id/comments(.:format) api/comments#create
new_api_photo_comments GET /api/photos/:photo_id/comments/new(.:format) api/comments#new
edit_api_photo_comments GET /api/photos/:photo_id/comments/edit(.:format) api/comments#edit
GET /api/photos/:photo_id/comments(.:format) api/comments#show
PATCH /api/photos/:photo_id/comments(.:format) api/comments#update
PUT /api/photos/:photo_id/comments(.:format) api/comments#update
DELETE /api/photos/:photo_id/comments(.:format) api/comments#destroy
I tried to add only: [:create, :index] to my comments resource but only the create route is visible.
According to the documentation about nested-resources I don't understand what's happening.
Thank you for your help.
It's because you are using a singular resource (resource :comments)
From the docs:
Sometimes, you have a resource that clients always look up without
referencing an ID. For example, you would like /profile to always show
the profile of the currently logged in user. In this case, you can use
a singular resource to map /profile (rather than /profile/:id) to the
show action
You'll need to use the standard resources method to get this working (resource omits the index action):
#config/routes.rb
namespace :api do
resources :photos do
resources :comments
end
end
My mistake. A "S" was missing on my resource.
namespace :api do
resources :photos do
resources :comments
end
end
Now it works.
I'm getting into Rails and trying to add a "vote" feature on a blog setup from here: http://guides.rubyonrails.org/getting_started.html
In app/controllers/posts_controller.rb I created this:
def incvotes
#post = Post.find(params[:id])
post.update_attributes(:upvotes => 1 )
format.html { redirect_to(#post, :notice => 'Vote counted.') }
format.xml { head :ok }
end
In app/views/posts/index.html.erb I created this:
<%= link_to 'Vote', :controller => "posts", :action => "incvotes", :id => post.id %>
But the link is giving the error
No route matches {:controller=>"posts", :action=>"incvotes", :id=>1}
I'm missing something here, but not sure what.
rake routes:
incvotes_post POST /posts/:id/incvotes(.:format) {:action=>"incvotes", :controller=>"posts"}
posts GET /posts(.:format) {:action=>"index", :controller=>"posts"}
POST /posts(.:format) {:action=>"create", :controller=>"posts"}
new_post GET /posts/new(.:format) {:action=>"new", :controller=>"posts"}
edit_post GET /posts/:id/edit(.:format) {:action=>"edit", :controller=>"posts"}
post GET /posts/:id(.:format) {:action=>"show", :controller=>"posts"}
PUT /posts/:id(.:format) {:action=>"update", :controller=>"posts"}
DELETE /posts/:id(.:format) {:action=>"destroy", :controller=>"posts"}
home_index GET /home/index(.:format) {:action=>"index", :controller=>"home"}
root /(.:format) {:action=>"index", :controller=>"home"}
try
= link_to "vote", incvotes_post_path(post), :method=>:post
and if that doesn't work, try changing the method to :put
My guess is that you probably do not have a definition in your routes file for the action you just defined in the controller. Both an action in the controller and an action in the routes file must be defined for Rails to generate urls correctly.
Your routes file probably has something like this:
resources :posts
But you want to add more than the standard actions generated by the resources keyword, so try something like this:
resources :posts do
member do
post 'incvotes'
end
end
This tells routes that you have another action in your posts controller called incvotes that accepts HTTP post requests as long as they are pointed at a member route with the correct action (/posts/14 is a member route, while /posts/ is a 'collection' route). So you will have a new route probably like /posts/14/incvotes that you can post a form to and everything should start working properly.
EDIT:
Actually I guess since you are just adding 1 to an attribute on a model, you don't need a POST action (which are normally associated with posting forms as with create and update). To send a post, you might need to change the HTML in the view to include a form and have it post to the correct url. So you can try that, or you can change your routes file to read get 'incvotes' instead of post 'incvotes'. Sorry for the confusion, hope that helps!
The incvotes_post route only accepts a HTTP POST, and a link always produces a HTTP GET.
Use a form with a button instead (or do a POST using AJAX).
Try using button_to instead link_to:
In your view:
<%= button_to 'Vote', incvotes_post_path(post) %>
In your config/routes.rb add the route to incvotes action as post:
resources :posts do
member do
post 'incvotes'
end
end
And in your controller, create the incvotes action:
def incvotes
# Something
redirect_to :posts
end