Custom path for resourceful route - ruby-on-rails

I'd like to be able to do ...
resources :posts
... and be able to customize the contextual url to be ...
:year/:month/:day/:id
... and still be able to do ...
post_path post
This would have it generate /2012/1/1/something-something.
However it appears I have to ...
get ':year/:id' => 'posts#show', as: 'posts'
Then in the view I have to ...
post_path post.year, post.id instead of post_path post
Is there anyway to have the post_path helper pick up the extra parameters it needs for the route?
If not this seems like it might be worth a feature request.

Sounds like you need something like:
match "posts/:year/:month/:day/:id" => "posts#show", :constraints => { :year => /\d{4}/, :month => /\d{2}/, :day => /\d{2}/ }

Related

Can't figure out how Rails route helper should look

I am working on an assignment which includes adding a feature to Typo.
rake routes shows:
admin_content /admin/content {:controller=>"admin/content", :action=>"index"}
/admin/content(/:action(/:id)) {:action=>nil, :id=>nil, :controller=>"admin/content"}
I need to create a route helper which matches the following RESTful route: /admin/content/edit/:id and an example of url is /admin/content/edit/1
But I can't figure out how to do it. I tried something like admin_content_path(edit,some_article) but it didn't work. (some_article is just an article object)
In routes.rb file:
# some other code
# Admin/XController
%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
#some other code
Thanks a lot for your help!
If you are using RESTful routes, why not use the Rails default routes?
So your routes.rb would look like
namespace :admin do
resources :content
resources :advanced
resources :categories
resources :comments
...
<etc>
end
This does assume all your controllers are in the folder admin (but from your comment this seems to be the case.
If you do that, you can just use the standard route-helper: edit_admin_content_path.
If you want to do it manually, you should try adding a name to your route. E.g. as follows:
match "/admin/#{i}/:action(/:id)" => "admin/#{i}", :as => "admin_#{i}_with_action"
and then you should do something like
admin_content_with_action(:action => 'edit', :id => whatevvvva)
As a side-note: I really do not like the meta-programming in your config/routes.rb, if for whatever you really find that the default resources are not a right fit, I would advise to use methods instead (as explained here)
So for example in your config/routes.rb you would write:
def add_my_resource(resource_name)
match "/#{resource_name}", :to => "#{resource_name}#index", :format => false
match "/#{resource_name}(/:action(/:id))", :to => "#{resource_name}", :as => 'admin_#{resource_name}_with_action", :action => nil, :id => nil, :format => false
end
namespace :admin do
add_my_resource :content
add_my_resource :advanced
add_my_resource :categories
...
end
which imho is much more readable.
But my advice, unless you really-really need to avoid it, would be to use the standard resources since you do not seem to add anything special.
HTH.

How can I pass additional parameters to a resource route in Rails?

I have a model called Post. In config/routes.rb, I defined its route as:
resources :post
Everything works fine with the default paths. I can create a new post at the following url:
/posts/new
I need to pass additional parameters so that the new url becomes:
/posts/new/:year/:month/:day
If I do the following, it assumes a post_id should exists:
resources :posts do
match '/new/:year/:month/:day',
:to => 'posts#new',
:constraints => {:year => /\d{4}/, :month => /\d{2}/, :day => /\d{2}/},
:as => 'new_post'
end
For the above, rake routes give me:
/posts/:post_id/new/:year/:month/:day(.:format)
How can I configure the default new path to pass additional parameters?
...
match '/new/:year/:month/:day', :on => :new
...

How to add a custom action to the controller in Rails 3

I want to add another action to my controller, and I can't figure out how.
I found this on RailsCasts, and on most StackOverflow topics:
# routes.rb
resources :items, :collection => {:schedule => :post, :save_scheduling => :put}
# items_controller.rb
...
def schedule
end
def save_scheduling
end
# items index view:
<%= link_to 'Schedule', schedule_item_path(item) %>
But it gives me the error:
undefined method `schedule_item_path' for #<#<Class:0x6287b50>:0x62730c0>
Not sure where I should go from here.
A nicer way to write
resources :items, :collection => {:schedule => :post, :save_scheduling => :put}
is
resources :items do
collection do
post :schedule
put :save_scheduling
end
end
This is going to create URLs like
/items/schedule
/items/save_scheduling
Because you're passing an item into your schedule_... route method, you likely want member routes instead of collection routes.
resources :items do
member do
post :schedule
put :save_scheduling
end
end
This is going to create URLs like
/items/:id/schedule
/items/:id/save_scheduling
Now a route method schedule_item_path accepting an Item instance will be available. The final issue is, your link_to as it stands is going to generate a GET request, not a POST request as your route requires. You need to specify this as a :method option.
link_to("Title here", schedule_item_path(item), method: :post, ...)
Recommended Reading: http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
Ref Rails Routing from the Outside In
Following should work
resources :items do
collection do
post 'schedule'
put 'save_scheduling'
end
end
You can write routes.rb like this:
match "items/schedule" => "items#schedule", :via => :post, :as => :schedule_item
match "items/save_scheduling" => "items#save_scheduling", :via => :put, :as => :save_scheduling_item
And the link_to helper can not send post verb in Rails 3.
You can see the Rails Routing from the Outside In

How to name a route in rails

I have some routes looking like this :
match 'hotels/:action(/:id)', :controller => 'hotel', :action => /[a-z]+/i, :id => /[0-9]+/i
And i want to use something like hotels_dislike_path somewhere in my code which refers to /hotels/dislike
How can i do that?
From the routing guide:
3.6 Naming Routes
You can specify a name for any route using the :as option.
match 'exit' => 'sessions#destroy', :as => :logout
So, in your case, that would be:
match 'hotels/:action(/:id)', :controller => 'hotel', :action => /[a-z]+/i, :id => /[0-9]+/i
match 'hotels/dislike(/:id)', :controller => 'hotel', :id => /[0-9]+/i, :as => :hotels_dislike
match 'hotels/like(/:id)', :controller => 'hotel', :id => /[0-9]+/i, :as => :hotels_like
I don't think there's a way to do this dynamically (so you have to define one route for each action, basically). However, you can just define a couple of routes (like above) for the most used actions, and just use hotels_path :action => :really_like for more uncommon actions.
A lot has changed in the world of Rails since 2011 - this is how you would accomplish the same goal in Rails 4.
resources :hotels do
member do
post 'dislike'
post 'like'
end
end
The resulting routes:
dislike_hotel POST /hotels/:id/dislike(.:format) hotels#dislike
like_hotel POST /hotels/:id/like(.:format) hotels#like
hotels GET /hotels(.:format) hotels#index
POST /hotels(.:format) hotels#create
new_hotel GET /hotels/new(.:format) hotels#new
edit_hotel GET /hotels/:id/edit(.:format) hotels#edit
hotel GET /hotels/:id(.:format) hotels#show
PATCH /hotels/:id(.:format) hotels#update
PUT /hotels/:id(.:format) hotels#update
DELETE /hotels/:id(.:format) hotels#destro
Notice thats rails prefixes instead of postfixes the action - dislike_hotel_path not hotels_dislike.

Rails RESTful Routing With '/' and Slugs

I am looking to do something similar a wordpress slug where I have a URL like this while maintaining RESTful routing:
http://foo.com/blog/2009/12/04/article-title
The reason I am interested in keep RESTFUL routing is that I am unable to use many plugins because I am using custom routes.
I have already done the RESTful appearance with:
map.connect '/blog/:year/:mon/:day/:slug',
:controller => 'posts', :action => 'show',
:year => /\d{4}/, :month => /\d{2}/,
:day => /\d{2}/, :slug => /.+/,
:requirements => { :year => /\d{4}/, :month => /\d{2}/, :day => /\d{2}/, :slug => /.+/ }
In order to write the links, I had to write custom link_to helpers to generate the proper URLs. I really would like to make this RESTful and have the link_to post_path( #post ) yield the URL above and the link_to edit_post_path(#post) ...article-title/edit
I also have :has_many => [:comments] and I would that to work as well. The link_to that I have tried looks like this:
'posts', :action => 'show', :year => recent_post.datetime.year.to_s,
:month => sprintf('%.2d', recent_post.datetime.mon.to_i),
:day => sprintf('%.2d', recent_post.datetime.mday.to_i),
:slug => recent_post.slug %>
and yields this (which isn't what I want):
http://foo.com/posts/show?day=30&month=11&slug=welcome-to-support-skydivers&year=2009
I'm not sure what I am doing wrong. Is it even possible to accomplish this?
I think it's not working because you're not using a custom route. I do this all of the time. I simply setup a simple custom route:
map.present_page '/blog/:year/:month/:day/:slug',
:controller => 'posts', :action => 'show'
Then you should be able to do:
present_page_path(:year => 2009,
:month => "December",
:day => "13",
:slug => "just-an-example")
The reason you're getting a query string is most likely because rails isn't making the connection to your route for whatever reason. Using a named route explicitly tells rails to use that route. Let me know if that solves it for you!
Here's how I went about this...
First, I'm not trying to use the route-generated url method. Also, I'm not going to the same extent as you in terms of checking formatting of the date parameters. Since I'm auto-generating the datestamps and the URL creation, I'm not concerned about format validity, I'm simply formatting a ActiveSupport::TimeWithZone object.
Let's start with the relevant route:
map.post_by_date 'content/:year/:month/:day/:slug',
:controller => 'posts',
:action => 'show_by_date_slug'
Since I didn't want to worry about argument formatting, or repetition, I created a helper method and included the helper in the relevant controller:
def pubdate_slug_url(post)
year = post.published_on.strftime('%Y')
month = post.published_on.strftime('%m')
day = post.published_on.strftime('%d')
url = "/" + ["content", year, month, day, post.slug].join("/")
return url
end
Finally, in my view, I simply call the method, passing in my Post object:
<h2><%= link_to post.headline, pubdate_slug_url(post) %></h2>
I end up with a url like: http://wallscorp.us/content/2009/12/06/links
Cheers.

Resources