Rails 3.2 friendly url routing by date
ruby-on-rails, ruby-on-rails-3, url-routing
Solution
The problem was in post's path helper usage as `post_path(post)`, because first parameter must be year since I use `:as => :post` in parametrized match in `routes.rb`.
Nevertheless, to make the entire solution clear here are some actions needed to make that all work proper:
You must add proper path helpers names for each match, e.g.
# Get /posts/2012/07/slug-of-the-post
match "/posts/:year/:month/:slug", <...>,
:as => :post_date
Now you can use `post_date_path("2012","12","end-of-the-world-is-near")` in views.
Same for `posts_path`, `posts_year_path("2012")`, `posts_month_path("2012","12")` if properly named.
I advice not to use neither `:as => :post` in that match nor creating `to_param` in model file as it can break something you don't expect (as `active_admin` for me).
Controller file `posts-controller.rb` should be filled with posts that needed extraction and checking of date's correctness before slug. Nevertheless in this state it is OK and breaks nothing.
Model file `posts.rb` should be filled with year and month extraciton in proper format, e.g.:
def year
created_at.year
end
def month
created_at.strftime("%m")
end
There is no `to_param` method really needed as I've noticed already.
Problem
I want to implement blog\news application with ability to: - show all posts at root: `example.com/` - show all posts answering some year: `example.com/2012/` - show all posts answering some year and month: `example.com/2012/07/` - show some post by its date and slug: `example.com/2012/07/slug-of-the-post` So I have created a mockup for `routes.rb` file: ``` # GET /?page=1 root :to => "posts#index" match "/posts" => redirect("/") match "/posts/" => redirect("/") # Get /posts/2012/?page=1 match "/posts/:year", :to => "posts#index", :constraints => { :year => /\d{4}/ } # Get /posts/2012/07/?page=1 match "/posts/:year/:month", :to => "posts#index", :constraints => { :year => /\d{4}/, :month => /\d{1,2}/ } # Get /posts/2012/07/slug-of-the-post match "/posts/:year/:month/:slug", :to => "posts#show", :as => :post, :constraints => { :year => /\d{4}/, :month => /\d{1,2}/, :slug => /[a-z0-9\-]+/ } ``` So I should work with params in `index` action and just get post by slug in `show` action (checking whether date is corect is an option): ``` # GET /posts?page=1 def index #render :text => "posts#index<br/><br/>#{params.to_s}" @posts = Post.order('created_at DESC').page(params[:page]) # sould be more complicated in future end # GET /posts/2012/07/19/slug def show #render :text => "posts#show<br/><br/>#{params.to_s}" @post = Post.find_by_slug(params[:slug]) end ``` Also I have to implement `to_param` for my model: ``` def to_param "#{created_at.year}/#{created_at.month}/#{slug}" end ``` This is all I have learned from all night long searching in api/guides/SO. But the problem is strange things keep happenning for me as new to rails: When I go to `localhost/`, the app breaks and says that it had invoked `show` action but first object in database had been recieved as :year (sic!): ``` No route matches {:controller=>"posts", :action=>"show", :year=>#<Post id: 12, slug: "*", title: "*", content: "*", created_at: "2012-07-19 15:25:38", updated_at: "2012-07-19 15:25:38">} ``` When I go to `localhost/posts/2012/07/cut-test` same thing happens: ``` No route matches {:controller=>"posts", :action=>"show", :year=>#<Post id: 12, slug: "*", title: "*", content: "*", created_at: "2012-07-19 15:25:38", updated_at: "2012-07-19 15:25:38">} ``` I feel that there is something very easy that I haven't made, but I can't find what is it. Anyway, this post will be helpful when it is solved, because there are solutions only for just slugs in url without date and similar but not useful questions.