1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
module ApplicationHelper def time_month(month) return Time.now.months_ago(month) end def last_number_of_months(number) months = [] number.times do |month| months << link_to(time_month(month).strftime("%B %Y"), #posts_path + time_month(month).strftime("/%Y/%m")) end return months.join("<br />") end end
Refactorings
No refactoring yet !
rpheath
January 20, 2008, January 20, 2008 18:02, permalink
There are a couple of things to note, here. Some of them are just preferences and there are A LOT of different ways to do this (I don't necessarily claim this is the best way).
One thing I try to always do in Ruby is avoid the functional style calls (i.e. time_month(month)), but since Ruby is so object-oriented, I try to extend or create classes/methods that allow for month.time_month type of calls.
See the comments below...
lib/fixnum_extensions.rb
1 2 3 4 5 6 7 8 9
# you can open up the FixNum class and # add this method there (optional approach) # # renamed 'time_month' to 'months_ago' class Fixnum def months_ago Time.now.months_ago(self) end end
config/initializers/date_time_formats.rb
1 2 3 4 5 6 7 8 9 10 11 12
# Rails 2.0+ gives you an initializers directory # within the config/ directory that gets auto-loaded # when Rails starts # # you can extend the built-in DATE_FORMATS constant # to get rid of the strftime("...") all over the place # (it's much more maintainable, too, because you only # change it in one place) ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!( :visual => "%B %Y", :for_params => "/%Y/%m" )
app/helpers/application_helper.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# by using returning, you can get rid of the explicit # return at the end of your method # # note: Ruby automatically returns the last executed # line within a method, so even without 'returning', you # don't need the explicit 'return ...' def last_number_of_months(number) returning months = [] do number.times do |n| year, month = n.months_ago.year, n.months_ago.month months << link_to(n.months_ago.to_s(:visual), posts_path(:year => year, :month => month)) end months.join '<br />' end end
config/routes.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
# define a route that matches your desired route so you're not # concat'ing the "/%Y/%m" map.posts '/posts/:year/:month', :controller => '...', :action => '...', :requirements => { # regex requirements on the year/month params :year => /(19|20)\d\d/, :month => /[01]\d/ } # further, i recommend wrapping the link_to in list items, # rather than joining by <br /> elements... something like... # # months << content_tag(:li, link_to(n.months_ago.to_s(:visual), posts_path(:year => year, :month => month)) # # but of course, i don't know the full extent of your needs # # hope that helps...
netzdamon.myopenid.com
January 20, 2008, January 20, 2008 18:27, permalink
Thanks for the great response. I was already doing the map.posts for my archive section. I was not thinking I could easily reuse what I have to get rid of that section of code. Thanks for clearing things up.
netzdamon.myopenid.com
January 20, 2008, January 20, 2008 19:26, permalink
Was a couple issues with the code above I fixed to work with my setup. Weird is though is the link_to links to the right url lets say 2008/01 but the :visual will display December 2007 for that. So you end up with a something like this.
<a href="http://localhost:3000/2008/01">December 2007</a>
What would be causing that? Happens with or without my modifications to your above code.
rpheath
January 20, 2008, January 20, 2008 21:14, permalink
Hmm... that's odd. I've never had any issues with incorrect date representations using that method, so I'm not sure. If you did choose to open up the Fixnum class, you may want to play with that in the console or something, to make sure it behaves as expected. It appears that it's 1 month off, so it could be an issue with how you're thinking it works (may or may not be inclusive or something).
Also, again, if you are opening the Fixnum class, you should renamed the 'time' method to 'months_ago' so you can simply call things like: 5.months_ago instead of 5.time. It's clearer and makes a lot more sense (I've edited the code above to reflect that change).
netzdamon.myopenid.com
January 20, 2008, January 20, 2008 23:51, permalink
Had to do with not renaming time to what you now named months_ago. Thanks for the help.
Jeremy Weiskotten
January 22, 2008, January 22, 2008 11:51, permalink
Rails provides an alternative to Time.now.months_ago(month)
1
month.months.ago
Just wrote my first rails application, and now I'm trying to go back and refactor parts of it. This piece is really bothering me. Just not sure what I can do with it.
Pay no attention to the bad function names. :P