I am trying to set up some semistatic page in a rails 3 app,
I have created a Pages controller with some non restful actions
class PagesController < ApplicationController
def home
end
def about
end
def contact
end
def monday
end
def saturday
end
def sunday
end
end
it's showing the pages well at pages/monday etc... or /monday etc... if i set up the routes as is rails 3 removing controller name form url
But I was just wondering if it is possible to redirect a missing url to /. As per exampel i have /monday set up, but if one plays with the url and input /tuesday it won't hit a page. can i redirect this kind of actions?
==EDIT==
I've change my code to this:
resources :pages, :path => '/' do
collection do
# # match 'tuesday' => redirect('/')
# # match 'wednesday' => redirect('/')
# # match 'friday' => redirect('/')
%w{home monday thursday saturday sunday about contact resources}.each do |url|
get url
end
end
end
match 'pages/*page' => :root
the url rewriting works fine looping through the array.
I tried the put the wild cardline at the bottom of my root files and at the bottom of the resources :page block. But I get a "controller action show could not be found" message.
match 'pages/*page' => :root
IS that the correct place to put it to restrain missing url like /tuesday to generate an error page?
is it also possible to limit this redirection only to a few actions and not to all missing pages? ex only to tuesday, wednesday, friday...
You can use wildcard routes to do this. At the end of your routes.rb just add the line:
match '*page' => :root
and the missing pages will redirect to root with params[:page] set to the url requested.
If you want to only redirect missing pages in the Pages controller, do this instead
match 'pages/*page' => :root
You can read more about routing here. Wildcard routes are explained near the end of the article.
Hope this helped!
got it working
I changed the wildcard line to
match '*page' => redirect('/')
instead of => :root, and left it within the resources :pages block.
Related
i've started porting one of my apps from rails 3.x to rails 4.x....
when i start the app in development, i receive a route definition related error:
=> Booting WEBrick
=> Rails 4.2.5 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
Exiting
/home/francesco/.rvm/gems/ruby-2.2.2#Best-i-gest_v2/gems/actionpack-4.2.5/lib/action_dispatch/routing/route_set.rb:549:in `add_route': Invalid route name, already in use: 'app_settings' (ArgumentError)
You may have defined two routes with the same name using the `:as` option, or you may be overriding a route already defined by a resource with the same naming. For the latter, you can restrict the routes created with `resources` as explained here:
http://guides.rubyonrails.org/routing.html#restricting-the-routes-created
.....
here part of my routes.rb file containing the routes marked as double defined:
.....
get 'app_settings' => 'admin/app_settings#index', :as => 'app_settings'
put 'app_settings' => 'admin/app_settings#index', :as => 'app_settings'
post 'app_settings' => 'admin/app_settings#index', :as => 'app_settings'
post 'app_settings/upload' => 'admin/app_settings#upload_logo', :as => 'app_settings/upload'
.....
i've defined these routes because i'm going to manage all actions related to application setting using the 'index' action only (the app has a single db record storing all settings, this record is automatically created at the first time the user will load page, then updated when it saves) as you can see here:
# only one record here! it will store all the application settings
def index
# manages all the controller actions inside the index...
if request.get?
# this is a get request... returns the first settings record or a new one if none exists!
#app_settings = !AppSettings.all.first.nil? ? AppSettings.all.first : AppSettings.new
elsif request.post?
# this is a post request, the settings record will be created
#app_settings = AppSettings.new(params[:app_settings])
#app_settings.save
elsif request.put?
# this will update the existing app_settings record
#app_settings = AppSettings.find_by_id(params[:app_settings][:id].to_i)
#app_settings.update_attributes(params[:app_settings])
end
# renders the index page
render "index"
end
i'm looking for a way to correct the routes.rb file (keeping my controller and view as is!!) or an alternative way to manage this issue!!
waiting your suggestions,
many thanks in advance for your time,
francesco
Seems like you have way too much logic in one method. I'm fairly sure even in rails 3 that wasn't acceptable.
What about using rest route ( resources as described in the rails routing guide )
resources :app_settings, only: [:index, :update, :create]
This will create three routes for index (geT), update (patch), create (post).
Your controller will now look like this:
def index
#app_settings = !AppSettings.all.first.nil? ? AppSettings.all.first : AppSettings.new
end
def create
#app_settings = AppSettings.new(params[:app_settings])
#app_settings.save
end
def update
#app_settings = AppSettings.find_by_id(params[:app_settings][:id].to_i)
#app_settings.update_attributes(params[:app_settings])
end
There will also be no need to use render 'index' ... rails will automatically look for /app/app_settings/index.html.erb
ok guys,
i've solved...
many thanks to Alexandre and Ryan who guided me in solving this issue.....
well,
Alexandre sure you're right!! too much logic inside a single action so...
here is the new version of my files:
routes.rb:
....
post 'app_settings/upload' => 'admin/app_settings#upload_logo', :as => 'app_settings/upload'
# site admin area
namespace :admin do
resources :app_settings, only: [:index, :update, :create]
resources :users
......
end
.....
as you can see, i've inserted app_settings route inside the admin namespace ..
app_settings_controller.rb:
# app_settings security settings - used for declarative authorization
filter_access_to [:index, :create, :update], :require => :manage
filter_access_to :upload_logo, :require => :manage
# app_settings index method (this replaces the show method so all actions will be managed in the index view page)
def index
# this is a get request... returns the first settings record or a new one if none exists!
#app_settings = !AppSettings.first.nil? ? AppSettings.first : AppSettings.new(id: 1)
#app_settings.save
end
# app_settings create method
def create
# this is a post request, the settings record will be created
#app_settings = AppSettings.new(app_settings_params)
#app_settings.save
# renders the index page
render "index"
end
# app_settings update method
def update
# this will update the existing app_settings record
#app_settings = AppSettings.find_by_id(params[:app_settings][:id].to_i)
#app_settings.update_attributes(app_settings_params)
# renders the index page
render "index"
end
......
as you can see, i've implemented your solution keeping the index view as only view used by the app, just for not changing too much inside the app....
i've fixed the declarative_authorization section accordingly with the modifications you've suggested and simplified the creation of the new record as Ryan suggested but adding a little extra (i've specified the record id and then saved the record itself) all to prevent another issue in my view where the form_for is declared as follows:
<!-- application settings edit form -->
<%= form_for [:admin, #app_settings] do |app_sett| %>
.....
.....
<% end %>
so many thanks again to you all!!
hoping to continue learning from you all the times i read a page of this site!!
regards,
francesco
I am looking for the correct way to redirect an entire site to a 404 page in the routes.rb file in a rails 3 application.
I can do a page using: match 'url' => redirect("/404")
But I want to know how to 404 all the pages without using adding a redirect to every route?
You can create a new method in your ApplicationController like below:
class ApplicationController < ActionController::Base
# ... other code
def redirect_to_404
raise ActionController::RoutingError.new('Not Found')
end
end
Then call that function within the controllers which handle the views you want to redirect.
In Rails you can create a method to render 404's in the Application Controller, ActiveRecord and Abstract Controller:
def make_404
raise ActionController::RoutingError.new('404')
end
I have a Rails 2.3.5 app with many controllers, models etc. which I'm trying to upgrade to Rails 3.2.21. I'm having some troubles with my routes. I tried to follow the Rails 3 new routing format but it doesn't seem to work. I'm getting two problems (which I guess all indicate one fundamental issue with my routing):
In the root ('/') I'm getting the generic "Welcome abroad" Rails
page. My routes (see below) have defined routing for root.
For some controllers I get No route matches [GET] "/study" message. My route shows this route, but for some reason doesn't define the GET method.
Here's my config/routes.rb code:
Myapp::Application.routes.draw do
root :to => 'study#index'
match 'login' => 'login', :protocol => 'https://'
resources :study_maps do
get :clone, :on => :member
end
# Route report create actions to the report controller
match 'report/create', :as => 'report'
match ':controller(/:action(/:id))(.:format)'
end
If I'm running rake routes I'm getting:
root / study#index
login /login(.:format) login#login {:protocol=>"https://"}
clone_study_map GET /study_maps/:id/clone(.:format) study_maps#clone
study_maps GET /study_maps(.:format) study_maps#index
POST /study_maps(.:format) study_maps#create
new_study_map GET /study_maps/new(.:format) study_maps#new
edit_study_map GET /study_maps/:id/edit(.:format) study_maps#edit
study_map GET /study_maps/:id(.:format) study_maps#show
PUT /study_maps/:id(.:format) study_maps#update
DELETE /study_maps/:id(.:format) study_maps#destroy
report /report/create(.:format) report#create
/:controller(/:action(/:id))(.:format) :controller#:action
Here's my StudyController#index code:
require 'myapp/studymgr'
require 'project_user'
require_dependency 'myapp/controller_extensions/report_manager'
class StudyController < ApplicationController
include PaginatorController
before_filter(:authenticate, :except => [:todo])
before_filter(:authorize,
:only => [:update, :destroy, :edit, :prune, :select_experiments ])
def index
#tags = Stag.find(:all).collect { |stag| stag.tag }
...
#include_ext = true
end
end
Can someone advise on what I'm missing?
Finally found a solution - my views had .rhtml extension. I found that this format is no longer supported under Rails 3 (What is the difference Between .erb , .rhtml and .html.erb?), so I changed all views extensions to .html.erb and then the routes worked with no need to specify explicit resource for each controller, just using the generic route: match ':controller(/:action(/:id))'.
As for the issue in the root route (#1 above), where I always got the Rails "Welcome abroad" page, despite having explicit route in my routes.rb, turns out I had to remove public/index.html which is loaded for root by Rails, and then my view was loaded.
I am trying to use a controller and action to do a simple check to see if a user account with that email address exists or not.
The controller's action looks like this:
def checkEmail
email = params["email"]
if Account.find_by_email(email).blank?
render :inline=>"true"
else
render :inline=>"false"
end
end
And to test this action, I can go to:
http://localhost:3000/home/checkEmail/email#website.com
When I do so, I can see in the Ruby console the following being queried:
Parameters: {"email"=>"email#website"}
Account Load (0.0ms) SELECT `accounts`.* FROM `accounts` WHERE `accounts`.`email` = 'email#website' LIMIT 1
You can see that the TLD of the email address has been cropped off.
However, when I go to:
http://localhost:3000/home/checkEmail/email#website.co.uk
I get a routing error:
No route matches [GET] "/home/checkEmail/email#website.co.uk"
My routes.rb file looks like this:
Gallery::Application.routes.draw do
#Match home URL
match 'home(/:file)' => "home#index"
match 'home/checkUser/:username' => "home#checkUser"
match 'home/checkEmail/:email' => "home#checkEmail"
root :to=> "home#index"
end
Yeah, the default behavior in Rails is to treat a dot (.) in a route as a format specifier, instead of part of the parameter.
In order to match the dot as part of the parameter, specify the route like this:
match "/home/checkEmail/:email" => "home#checkEmail", :constraints => { :email=> /[^\/]*/ }
Here's a post that describes the problem and the fix:
http://coding-journal.com/rails-3-routing-parameters-with-dots/
I have a simple question I can't figure out.
I have a rails 3 app using subdomains.
A firm have many users. When a user log in, I want to redirect them to their firms subdomain.
I've used Ryan Bates screencast to get subdomains working.
http://railscasts.com/episodes/221-subdomains-in-rails-3
In my user_sessions_controller I have.
def create
#user_session = UserSession.new(params[:user_session])
if #user_session.save
#firm = current_user.firm
flash[:notice] = "Successfully logged in."
redirect_to root_url(:subdomain => #firm.subdomain)
else
render :action => 'new'
end
end
This sends the user in the firm with subdomain lizz to this url
http://lvh.me:3000/?subdomain=lizz
when the user is logged in this link works
<%= link_to current_firm.subdomain, root_url(:subdomain => current_firm.subdomain) %>
Do you have any ideas on how to redirect from the controller to the subdomain?
I think you problem is that you are url the named url root_url. The helper method url_for that you modified (if you followed the Railscasts closely) is probably not used for the named url.
Try using url_for instead.
Edit
The names urls are generated in actionpack-3.0.x/lib/action_dispatch/routing/route_set.rb and will not use your custom url_for method. However, does support a :host parameter so you need to write something like
... root_url(:host => "#{current_firm.subdomain}.domain.tld") ...