I'm redirecting from one controller to another. The receiving controller, uploads, doesn't have an index action, but has a create action, which I'm trying to use obviously. However when I redirect, I get the following issue
Unknown action
The action 'index' could not be found for UploadsController
redirect_to :controller => 'uploads', :action => 'create', flash: {error: "there was an error"}
Probably because the redirect_to is assuming that its redirecting with a GET request.
Since the index & create actions both go to the same path and depending on the HTTP verb, Rails decides which action to call...
So if the application gets a GET request to /uploads it will render the index action and if it gets a POST it will call the create action.
Furthermore, I don't think you can redirect_to a http POST... Are you sure that's what you want to do?
Try specifying :method => :post in the request. Create actions should only respond to that, unless you're doing fancy things with routes.
Related
I have a rails project with the following route:
get 'login', to: 'user_sessions#new', as: :login
In my UserSessionsController I have
def create
#user_session = UserSession.new(params[:user_session])
respond_to do |format|
if #user_session.save
# Do all the happy stuff
else
format.html { render :action => 'new' }
format.xml { render xml: #user_session.errors, status: :unprocessable_entity }
end
end
end
That's working ok, except that when the user enters incorrect parameters the route is via /user_sessions instead of /login, which is untidy (and means my test assertions are confusing).
Obviously I could just redirect_to login_path, but then my #user_session.errors don't seem to be available so by page doesn't show what was wrong.
How do I redirect back to /login and still have the errors show?
Edit:
It looks as if Rails makes this difficult because it's something I shouldn't try to do. The RESTful path isn't really something the user cares about so I shouldn't be using it as part of my UI testing. Instead, I am looking at the actual content of the rendered page, which the user does care about. Thanks all.
You can add
post 'login', to: 'user_sessions#create', as: :post_login
and change the form action accordingly.
This is happening because when you get validation errors in your form then you are on create action and not new action. Your create action simply render your new actions template with errors, it doesn't send a request to server and hence your url remains same so to fix it you can simply change the route for your create action to this:
post 'login', to: 'user_sessions#create', as: :login
Update:
You'll just have to change your route for create action and then make changes in your form, something like this:
<%= from_for #resource, url: login_path do |f| %>
// form fields
<% end %>
If you'll inspect your form you'll see that its method is POST so when you'll submit it, your form will send a POST request and when you hit /login in your browsers address bar it'll send a GET request so in first case you'll go to create action and in second one you'll go to new action
RESTful resource, default type routes. Creating an event is supposed to work as follows:
def create
#event = current_user.events.build(params[:event])
if #event.save
redirect_to #event, :flash => { :success => "Event created!" }
else
render :action => "new" # new_event_path
end
end
When invalid data is entered, it does render the "new" view/form again, but it renders this view at the "localhost:3000/events" URL, where the "index" action/view should be on.
My event routes seem like they ought to be pretty predictable:
resources :events
I just updated to Capybara 2, began using DatabaseCleaner, and set transactional_fixtures to false in preparation for testing some JS-enabled functionality but can't think of any other way I might have stuffed this up.
Is there some simple thing I'm missing that could cause a weird routing muck up like this?
Ideas, anyone, on where to start troubleshooting it?
This is the correct behavior. What is happening is that it is using the POST method for that URL when issuing the create action. Using a GET at the URL would be the index action. Also note that rendering a different template does not change the URL (that would require a redirect).
Check out section 2.2 in the Rails Routing documentation:
http://guides.rubyonrails.org/routing.html
When you create event from submitting form you using post method to /events route. And when data becomes invalid rails render events/new for your /events(POST) request at /events address.
But you can
redirect_to action: "new", event: #event.attributes
and add to new action
#item = Item.new(params[:item].except('protected attributes','created_at', 'updated_at', 'id'))
Is there any method that i should look at in rails3.2 source code so as to know where the navigation or the url part of the render call get resolved?
The reason is, i have a small app in which url is of the form
www.example.com/bob/edit
the above route as it suggests renders the edit form.EDIT: i was able to get to this route by modifying response on the link_to helper.
def update
#when validation passes
redirect_to #user
#when validation fails
respond_to do |format|
format.html {render :action => "edit"}
end
end
Now the problem is when a validation error occurs on submission to update action of users_controller,
the url becomes
www.example.com/users/bob/edit
config/routes.rb
get "users/new", to: => "users#new"
resources :users
as you can see there's nothing interesting happening in routes,
in models/user.rb
def to_param
"#{name}"
end
in views/edit.html.erb
form_for(#user) do |f|
end
Observation: here when the form is rendered afresh, form 'action' points to "users/bob" but when the form is re-rendered 'cos of validation error, form action mysteriosly changes to "users/" which is weired and if i remove the to_param in user.rb model it works fine
Though its not such a big deal, i was thinking where, if i needed to override the url that is generated on render call, to change?????
Any suggestions and pointers to explore are wecome....
I'm not sure how you're getting the URLs you're getting, but a general answer to your question would be it doesn't. The URL you see after sending a request is the URL the request was sent to (or redirected to), not that of the page you came from, nor that of the template you render in the end. In your case, I'm guessing the problem is that you created a custom URL for the edit page, but not for update, and your form_for(#user) is sending the request to your update URL (probably PUT "/users/bob").
To fix this, the first thing is to create your custom update route. Maybe something like:
put ":id/update", to: => "users#update"
And then have your form_for use that URL:
form_for(#user, :url => "#{#user.to_param}/update")
I'm very new to Rails, so maybe I'm just missing the "Rails way" of doing this, but I have a model, call it Post. I can create a post from the canonical posts/new page but also from another page, say home/index.
In home/index i have a form_for #post (slightly different from the one in posts/new, but say that i can use a partial). The problem is that in the PostController.create I cannot pass the newly created #post object back to home/index (in case of errors) because:
if I don't specify a page to render, it will automatically render posts/new
i don't know the calling page in order to redirect it to the right calling page (posts/new or home/index)
even if i knew it (hacking the request referrer or using redirect_to :back), redirect_to doesn't pass objects back, so that #post is empty when called from home/index
Any help? thanks
EDIT
Maybe a possible solution would be to get the calling controller / action from the request and render it back. Any way to do this?
In theory, you could achieve what you're trying to do by checking the referer:
def create
#post = Post.new
if #post.update_attributes(params[:post])
# redirect as appropriate
else
render :action => case request.referer
when new_post_path then "posts/new"
when "/" then "home/index" # assuming that home/index is the root of the site
end
end
end
To get the referrer page, you can make a hidden field with the name redirect. You can use it in the controller.
redirect_to params[:redirect] || posts_path
Have you tried that you pass the post's id in the query string to the home/index
eg: /home/index?post_id=42
You can find out who called your page by looking at
request.referrer
I don't know if this is the "rails way" but here's my solution.
You can add a route for
match home/index/(:id) => "home#index"
and redirect to this after creating the Post. Then in your Home controllers index action just do a
#Post = Post.find(params[:index]) if params[:index]
Your view should display the post if #Post exists
I like this approach because it keeps all the logic where it should be. Routing logic in the controller and view logic in the views.
In my RSpec tests, I need to simulate an AJAX GET request to the index action, and have been using the code as described in both the Rails docs and the RSpec book:
xhr :get, :index
This always fails though, as the test tries to load the show action (without any parameters) rather than the specified index action.
The controller action is:
def index
#contacts = Contact.all
respond_to do |format|
format.html
format.js {
render :update do |page|
page.replace_html :contact_search_results, :partial => 'contacts'
end
}
end
end
The error thrown by running the spec is (showing the :show action being used):
ActionView::TemplateError in 'ContactsController as an administrator user when
showing the index of contacts' as an AJAX request should render results into the
contact_search_results element'
contact_url failed to generate from {:action=>"show", :controller=>"contacts",
:id=>#<Contact id: nil, first_name: nil, ....>}
Does anyone know how I can simulate an AJAX call the index action in tests?
Thanks!
Actually I think you're misunderstanding the error. Somewhere along the way Rails is trying to call contact_url and the parameters are wrong. My suspicion is that it is indeed calling the index action which then renders the contact partial. If I'm right, the contacts partial is the location of the issue. I would recommend reviewing the contacts partial for any possible errors. If you're still having trouble, please post the body of your contacts partial.
You're trying to make a URL to a non-persisted Contact object. You can see that in the message: :id=>#<Contact id: nil