I am rendering a new action but somehow getting the "index" URL. To be more specific, my create action looks like this:
class ListingsController < ApplicationController
def create
#listing = Listing.new(params[:listing])
#listing.user = #current_user
if #listing.save
redirect_to #listing
else
flash[:error] = "There were errors"
render :action => "new"
end
end
end
When there are errors, I get the "new" action but my URL is the index URL - http://domain.com/listings
Anyone know why this would happen? My routes file is fairly standard:
map.connect 'listings/send_message', :controller => 'listings', :action => 'send_message'
map.resources :listings
map.root :controller => "listings"
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
when you render you just get the content that will be returned to the browser as the response body. On Rendering your url is not get changed.
Best example of that create a scaffold application.so when you submit the form on the new and error occurs your 'new.html.erb' is displayed but your url shows domain_name/controller_name/create
Hope that helps :)
Related
I have a small app where the index page is a form that instructs the user for their email, I have changed my route so that the root_path is the 'new' action which renders my form:
Oa::Application.routes.draw do
resources :signups
match "/confirm", :to => "pages#confirm"
root :to => 'signups#new'
end
This is working fine, when I submit the form it is working fine. When I submit on the root page and I cause a validation error the address bar has the url localhost:3000/signups and shows me my validation errors, which is also good but if I were to manually visit http://localhost:3000/signups it gives me an error "The action 'index' could not be found for SignupsController". Would it be ok if I created the 'index' action and redirect_to root_path so that I don't receive the "The action 'index' could not be found for SignupsController" if I were to access http://localhost:3000/signups directly? Is this the proper way to do this?
class SignupsController < ApplicationController
def index
redirect_to root_path
end
def new
#signup = Signup.new
end
def create
#signup = Signup.new(params[:signup])
if #signup.save
UserMailer.registration_confirmation(#signup).deliver
flash[:notice] = "Signup created successfully."
redirect_to confirm_path
else
render :action => "new"
end
end
end
Thanks!
J
Do something like this:
post '/' => 'signups#create'
root to: 'signups#new'
Do not use resources :signups
The reason that http://localhost:3000/signups gives me an error "The action 'index' could not be found for SignupsController" is because:
The first 'matched' routes is used.
So all of this:
match "/confirm", :to => "pages#confirm"
root :to => 'signups#new'
is ignored by the /signups URL because IT gets dealt with by
resources :signups
which creates all the routes - index, show, create, new, edit, update, destroy
and when 'signups' is used it implies the signups index action.
Try removing it and/or reading up on RESTful routes in rails and apply that.
Edit: i am using Mongoid/MongoDB for my database, meaning I don't get the normal Active Record tools I think.
I have a simple Rails 3.1 app with a model Page. I would like to match '/:customURL' to the Page#show action for the Page with the relevant :customURL. How should I change the controller and routes? Keep in mind that there are a few routes from '/SOMETHING' that I want to keep. For instance '/pages' should still go to my Page#index action not try to find a page with customURL of 'pages'.
current controller:
def show
#page = Page.find(params[:id])
#title = #page.title
respond_to do |format|
format.html # show.html.erb
format.json { render json: #page }
end
end
routes:
resources :pages do
resources :feeds
end
get "pages/index"
get "pages/show"
get "pages/new"
root :to => "pages#index"
Thanks a million.
Assuming that your Page has a customURL attribute from its database table. In your controller:
def show
#page = Page.first(:conditions => {:customURL => params[:customURL]})
#title = #page.title
respond_to do |format|
format.html # show.html.erb
format.json { render json: #page }
end
end
In your routes
resources :pages, :except => :show do
resources :feeds
end
# Anything you want to match before the custom URLs needs to go above the next route definition
get "/:customURL" => "pages#show"
root :to => "pages#index"
I am really confused about Ruby on Rails REST routing. Even though I have specified that after the success it should go to the confirm action it goes to the show action and pass the ID=confirm.
def create
#article = Article.new(params[:article])
respond_to do |format|
if #article.save
format.html { redirect_to :action => "confirm" }
else
format.html { render :action => "new" }
end
end
end
The error I get is the following:
ActiveRecord::RecordNotFound in ArticlesController#show
Couldn't find Article with ID=confirm
Rails.root: /Projects/highoncoding
Application Trace | Framework Trace | Full Trace
app/controllers/articles_controller.rb:31:in `show'
UPDATE 1:
Here is my Route.rb file:
resources :articles
get "articles/confirm"
# config/routes.rb
MyApp::Application.routes.draw do
resources :articles do
member do
get 'confirm'
end
end
end
# app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
def create
#article = Article.new(params[:article])
respond_to do |format|
if #article.save
# use a named route here
format.html { redirect_to confirm_article_url(#article) }
else
format.html { render :action => "new" }
end
end
end
end
you'll need to add the route so it looks like
match 'articles/confirm/', :controller => 'article', :action => 'confirm'
resources :articles
you need to have the :id in there or it will think that confirm is an id which is why you are seeing the error ID=confirm. make sure also that this is the first route. (at least before the resources for the articles controller.
You should probably add the confirm route directly in your routes file.
match 'articles/confirm' => 'articles#confirm'
resources only work for create/update/destroy/etc.
Im trying make a login page for my rails application that looks like "www.domain.com" and when you login you still are still located at the domain "www.domain.com". Is there a way that I can map 2 different actions to the same url using routes. Twitter does it this way, you log in at twitter.com and after you are logged in you are still located at twitter.com.
You can't do this by simply modifying the routes, but you can do some kind of conditional statement in your controller.
def index
if logged_in
render :action => 'show'
else
render :action => 'new'
end
end
def show
...
end
def new
...
end
There are going to be numerous ways to do this, of course.
After successful login redirect to the root URL.
routes.rb
map.resources :landings
# let's assume that, home page corresponds to landings/index
map.root :controller => "landings", :action => "index"
UserSessionsController
def create
#user_session = UserSession.new(params[:user_session])
if #user_session.save
redirect_to root_url
else
render :action => :new
end
end
I've just added a contact form to my Rails application so that site visitors can send me a message. The application has a Message resource and I've defined this custom route to make the URL nicer and more obvious:
map.contact '/contact', :controller => 'messages', :action => 'new'
How can I keep the URL as /contact when the model fails validation? At the moment the URL changes to /messages upon validation failure.
This is the create method in my messages_controller:
def create
#message = Message.new(params[:message])
if #message.save
flash[:notice] = 'Thanks for your message etc...'
redirect_to contact_path
else
render 'new', :layout => 'contact'
end
end
Thanks in advance.
One solution would be to make two conditional routes with the following code:
map.contact 'contact', :controller => 'messages', :action => 'new', :conditions => { :method => :get }
map.connect 'contact', :controller => 'messages', :action => 'create', :conditions => { :method => :post } # Notice we are using 'connect' here, not 'contact'! See bottom of answer for explanation
This will make all get request (direct requests etc.) use the 'new' action, and the post request the 'create' action. (There are two other types of requests: put and delete, but these are irrelevant here.)
Now, in the form where you are creating the message object change
<%= form_for #message do |f| %>
to
<%= form_for #message, :url => contact_url do |f| %>
(The form helper will automatically choose the post request type, because that is default when creating new objects.)
Should solve your troubles.
(This also won't cause the addressbar to flicker the other address. It never uses another address.)
.
Explanation why using connect is not a problem here
The map.name_of_route references JUST THE PATH. Therefore you don't need a new named route for the second route. You can use the original one, because the paths are the same. All the other options are used only when a new request reaches rails and it needs to know where to send it.
.
EDIT
If you think the extra routes make a bit of a mess (especially when you use it more often) you could create a special method to create them. This method isn't very beautiful (terrible variable names), but it should do the job.
def map.connect_different_actions_to_same_path(path, controller, request_types_with_actions) # Should really change the name...
first = true # There first route should be a named route
request_types_with_actions.each do |request, action|
route_name = first ? path : 'connect'
eval("map.#{route_name} '#{path}', :controller => '#{controller}', :action => '#{action}', :conditions => { :method => :#{request.to_s} }")
first = false
end
end
And then use it like this
map.connect_different_actions_to_same_path('contact', 'messages', {:get => 'new', :post => 'create'})
I prefer the original method though...
I just came up with a second solution, guided by Omar's comments on my first one.
If you write this as your resources route
map.resources :messages, :as => 'contact'
This gives (amongst others) the following routes
/contact # + GET = controller:messages action:index
/contact # + POST = controller:messages action:create
So when you move your 'new' action code into your 'index' action, you will have the same result. No flicker and an easier to read routes file. However, your controller will make no more sense.
I, however, think it is a worse solution because you'll soon forget why you put your 'new' code into the index action.
Btw. If you want to keep a kind of index action, you could do this
map.resources :messages, :as => 'contact', :collection => { :manage => :get }
This will give you the following route
manage_messages_path # = /contact/manage controller:messages action:manage
You could then move your index action code into the manage action.
I suspect you are posting to '/messages' from the form which creates the message which explains why you see that in your URL.
Any reason why this won't work:
def create
#message = Message.new(params[:message])
if #message.save
flash[:notice] = 'Thanks for your message etc...'
redirect_to contact_path
else
flash[:notice] = 'Sorry there was a problem with your message'
redirect_to contact_path
end
end
Not to my knowledge, no. Since im assuming you want to render so that you keep the #message object as is with the errors attached.
There is a horrible solution that I have which will let you do it, but, its so horrible, I wouldn't recommend it:
before_filter :find_message_in_session, :only => [:new]
def new
#message ||= Message.new
end
def create
#message = Message.new(params[:message])
if #message.save
flash[:notice] = 'Thanks for your message etc...'
redirect_to contact_path
else
flash[:notice] = 'Sorry there was a problem with your message'
store_message_in_session
redirect_to contact_path
end
end
private
def find_message_in_session
#message = session[:message]; session[:message] = nil
end
def store_message_in_session
session[:message] = #message
end