In routes.rb I have
map.resources :groups, :collection => { :find_or_create => :get, :search => :get } do |group|
group.resources :recruitment_periods, :controller => 'groups/recruitment_periods' do |period|
period.resources :recruits, :controller => 'groups/recruitment_periods/recruits'
if I wanted to redirect to the show action of a specific group,recruit_period, recruit what would the path be?
i.e. redirect_to groups_recruitment_period_recruit_path(x,y,z)
I think you almost had it. It looks like it should be:
redirect_to group_recruitment_period_recruit_path(x,y,z)
No plural on group since you know which one.
Related
I have a Rails controller with about 60+ actions. I need to change it to allow only POST requests on about 20 actions and any request method for the rest of them.
Is there a way to do this so I don't have to manually specify ever route that is allowed for all routes?
This is what I have so far (and works):
post_regex = /first_route|second_route/
all_routes_regex = /third_route|fourth_route/
map.connect '/myroute/:id/:action', :controller => 'my_controller', :constraints => {:action => post_regex }, :conditions => { :method => :post }
map.connect '/myroute/:id/:action', :controller => 'my_controller', :constraints => {:action => all_routes_regex }
I tried creating something like this but it would just cause a RoutingError.
post_regex = /first_route|second_route/
class AllRoutesConstraint
def self.matches?(request)
(request.query_parameters[:action] !~ post_regex)
end
end
map.connect '/myroute/:id/:action', :controller => 'my_controller', :constraints => {:action => post_regex }, :conditions => { :method => :post }
map.connect '/myroute/:id/:action', :controller => 'my_controller', :constraints => {:action => AllRoutesConstraint }
If you are willing to do it in the controller instead of in routes.rb, it should be pretty straightforward. Let all request types through in the routes file:
# in config/routes.rb
map.connect '/myroute/:id/:action', :controller => 'my_controller'
And then, filter for POST-only actions in the controller.
# in app/controllers/my_controller.rb
POST_ONLY_ACTIONS = [:first_route, :second_route]
before_filter :must_be_post, :only => POST_ONLY_ACTIONS
# your actions...
protected
def must_be_post
unless request.method == "POST"
raise ActionController::MethodNotAllowed.new("Only post requests are allowed.")
end
end
This gets you the same error and error message that Rails would generate for you if you set the method in routes.rb.
The drawback is that your routes.rb file is no longer the single authoritative source on exactly what requests are permissible. But since you were trying to remove some of that information (the list of non-POST requests) from the routes file anyway, you might find the tradeoff acceptable.
I am trying to set up my routes for the will paginate plugin so I don't have ?page=1 at the end of the url, and so I can later try to use page caching.
I've been browsing around online and I found a few tutorials explain to use map.connect, however, I am having trouble getting it to work with my application.
Here's an example url: http://localhost:3000/profile/1/browse?page=1
Here's the routes code I've got so far:
map.connect '/profile/:id/browse/:page',
:controller => 'profiles',
:action => 'browse',
:id => /\d+/,
:page => /\d+/
This doesn't work. Does anyone have any advice?
I thought map.connect was pattern matching, but maybe I am missing something.
Thank you,
Looking at your route, you might be crossing two different things. What are you paginating? If it's profiles, there's no need to supply an id. Let's assume you're trying to paginate profiles. Your route would look like this:
map.connect '/profiles/browse/:page',
:controller => 'profiles',
:action => 'index',
:page => /\d+/
And your controller action would look like this:
def index
#profiles = Profile.paginate :page => params[:page]
end
If you are trying to nest something within profiles, say browsing a profile's pictures, you'll need to do it more like this:
map.connect '/profiles/:id/browse/:page',
:controller => 'profiles',
:action => 'index',
:id => /\d+/,
:page => /\d+/
with your controller like so:
def index
#profile = Profile.find(params[:id])
#pictures = #profile.pictures.paginate :page => params[:page]
end
Let me know if this works.
UPDATE:
You listed in the comments that /profile/1/ is referring to the user's own profile. First, this is dangerous because you don't want people to change what profile the app thinks they are, just by changing that id number by hand. Rely on whatever current_user method your authentication gives you.
However, using your current setup as the example, this is what it would look like:
map.connect '/profiles/:id/browse/:page',
:controller => 'profiles',
:action => 'browse',
:id => /\d+/,
:page => /\d+/
with your controller like so:
def browse
#profile = Profile.find(params[:id])
#profiles = Profile.paginate :page => params[:page]
end
Let me know if you still have questions.
UPDATE 2
In order to get a nice link_to with this, change the route to a named route:
map.profile_browse '/profiles/:id/browse/:page',
:controller => 'profiles',
:action => 'browse',
:id => /\d+/,
:page => /\d+/
Now you can call link_to like so:
link_to profile_browse_path(:id => 1, :page => 10)
I have the following routes defined:
map.resources :categories, :has_many => :downloads
map.resources :downloads, :member => {:go => :get}, :collection => {:tag => :get}
map.connect '/downlods/page/:page', :controller => 'downloads', :action => 'index'
map.connect '/categories/:category_id/downloads/page/:page', :controller => 'downloads', :action => 'index'
For some reason, the first page that the will_paginate helper is called on causes links with ?page=2 to be rendered, while subsequent pages have links with /downloads/page/2. Do you know what might be causing this?
If you simply declare a route with map.connect, it can be hit and miss as to how it's routed if you do something like:
link_to("Next", :page => 2)
What you might want to do is name the route and then use it that way:
map.downloads_paginated '/downloads/page/:page', :controller => 'downloads', :action => 'index'
Then you use the route by name:
link_to("Next", downloads_paginated_path(2))
These are much more reliable.
As a note, you have '/downlods' in your path instead of '/downloads' but I'm not sure that'd be causing the trouble described.
I am attempting to create a custom route in rails and am not sure if I am going about it in the right way. Firstly I have a RESTful resource for stashes that redirects to mystash as the controller:
map.resources :stashes, :as => 'mystash'
site.com/mystash goes to :controller => 'stashes', :action => 'show'
Which is what I want. Now is where it gets somewhat confusing. I would like to be able to add conditional params to this route. Ultimately I would like to have a route that looks like this:
site.com/mystash/zoomout/new/quiz_on/
I have places this in routes:
map.connect 'mystash/:zoom/:nav_option/:quiz',
:controller => 'stashes',
:action => 'show'
map.connect 'mystash/:zoom/:nav_option',
:controller => 'stashes',
:action => 'show'
map.connect 'mystash/:zoom',
:controller => 'stashes',
:action => 'show'
map.connect 'mystash',
:controller => 'stashes',
:action => 'show'
My routes have ended up looking like this in the browser:
site.com//mystash/zoomin?nav_option=New&quiz=quizon
and this is what one of my links looks like:
<%= link_to "In", stash_path("zoomin", :nav_option => #nav_option, :quiz => #quiz) %>
Any help is appreciated, I am pretty new to custom routes!
You should be giving these routes different names instead of the default, or you should be specifying your route with a hash and not a X_path call. For instance:
map.stash_zoom_nav_quiz 'mystash/:zoom/:nav_option/:quiz',
:controller => 'stashes',
:action => 'show'
map.stash_zoom_nav 'mystash/:zoom/:nav_option',
:controller => 'stashes',
:action => 'show'
Keep in mind that when you declare a named route, the parameters in the path must be specified in the X_path call with no omissions, and not as a hash.
link_to('Foo', stash_zoom_nav_quiz_path(#zoom, #nav_option, #quiz))
link_to('Bar', stash_zoom_nav_path(#zoom, #nav_option))
The alternative is to not bother with named routes and let the routing engine figure it out on its own:
link_to('Foo', :controller => 'stashes', :action => 'show', :zoom => #zoom, :nav_option => #nav_option, :quiz => #quiz)
If you're uncertain what routes are defined, or how to call them, always inspect the output of "rake routes" very carefully. You can also write functional tests for routes with the assert_routing method.
I want to use page_cache with will_paginate.
There are good information on this page below.
http://railsenvy.com/2007/2/28/rails-caching-tutorial#pagination
http://railslab.newrelic.com/2009/02/05/episode-5-advanced-page-caching
I wrote routes.rb looks like:
map.connect '/products/page/:page', :controller => 'products', :action => 'index'
But, links of url are not changed to '/products/page/:page' which are in will_paginate helper.
They are still 'products?page=2'
How can i change url format is in will_paginate?
Is that route declared above any RESTful resources routes? That is, your route file should look like the following:
map.connnect '/products/page/:page', :controller => 'products', :action => 'index'
map.resources :products, :except => [:index]
If your routes look correct, you could try monkey-patching the way will_paginate generates the page links. It does so in WillPaginate::ViewHelpers#url_for(page). It's some fairly complex logic in order to handle some tricky edge cases, but you could write a new version that tried the simple version for your products first:
# in lib/cache_paginated_projects.rb
WillPaginate::ViewHelpers.class_eval do
old_url_for = method(:url_for)
define_method(:url_for) do |page|
if #template.params[:controller].to_s == 'products' && #template.params[:action].to_s == 'index'
#template.url_for :page => page
else
old_url_for.bind(self).call(page)
end
end
end
this works for me
app/helpers/custom_link_renderer.rb
class CustomLinkRenderer < WillPaginate::LinkRenderer
def page_link(page, text, attributes = {})
#template.link_to text, "#{#template.url_for(#url_params)}/page/#{page}", attributes
end
end
add this line to config/environment.rb file
WillPaginate::ViewHelpers.pagination_options[:renderer] = 'CustomLinkRenderer'
A little addition to the current answers, I had to spend hours to figure it out.
If you have some more complex routes, like for example including filtering in my case, make sure that the "higher level" routes come first (and not just that they are above the RESTful one), otherwise will_paginate picks up the first usable one and sticks the extra params at the end of the URL in a non-pretty way.
So in my case I ended up with this:
map.connect "wallpapers/:filter/page/:page", :controller => "wallpapers", :action => "index", :requirements => {:page => /\d+/, :filter => /(popular|featured)/ }
map.connect "wallpapers/page/:page", :controller => "wallpapers", :action => "index", :requirements => {:page => /\d+/ }
map.resources :wallpapers
So now I get pretty URLs like: wallpapers/popular/page/2 instead of wallpapers/page/2?filter=popular
Do this:
map.products_with_pages "/products/page/:page", :controller => "products", :action => "index"
You can even do it with a has_many ie: products has_many :items
map.resources :products do |product|
map.items_with_pages "/products/:id/page/:page", :controller => "products", :action => "show"
end
Then your controller could look like
def show
product = Product.find(params[:id])
#items = product.items.paginate :per_page => 5, :page => params[:page]
end
Which would give you a url like: http://domain.com/products/123/page/3 where 123 is the product id and 3 is the page id. You could also use permalinks and have the 123 id changed to a more seo friendly word.