Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Current year in Ruby on Rails

How can I get current year in Ruby on Rails?

I tried a variety of things, including

  • Date.current.year
  • Time.now.year

The problem is they return the previous year in cases where year changes after launching the server (eg. after new year's).

Relevant code:

Model brewery.rb

class Brewery < ActiveRecord: :Base
...
validates :year, numericality: { only_integer: true, less_than_or_equal_to: Date.today.year }
...

Problem occurs when creating a new brewery, so I assumed Date.today.year would be evaluated whenever that action takes place.

like image 726
Atte Juvonen Avatar asked Feb 05 '16 15:02

Atte Juvonen


4 Answers

In your example Date.today.year is evaluated only once when the class is loaded and therefore doesn't change later on.

When you use a lambda in your validator declaration then it re-evaluates the block each time when it runs the validation for that attribute:

validates :year, numericality: { 
  only_integer: true, 
  less_than_or_equal_to: ->(_brewery) { Date.current.year }
}

Furthermore, I suggest using Date.current instead of Date.today because the current method pays attention to timezone settings.

like image 72
spickermann Avatar answered Nov 03 '22 00:11

spickermann


<%= Time.zone.now.year %> -- factors in time zone

like image 28
Joshua Baker Avatar answered Nov 03 '22 00:11

Joshua Baker


Actually, it's better to use Time.current instead of Time.now in Rails, because the first one adopts current time zone. http://edgeguides.rubyonrails.org/active_support_core_extensions.html#time-current

like image 31
Tensho Avatar answered Nov 03 '22 00:11

Tensho


@spickermann's recipe seems to be correct, I'll just try to explain why it works.

The code you write inside your class is executed at compile time, when Ruby compiles to the VM bytecode. Therefore, the Date.today.year in your validator is calculated exactly once, when the class is compiled.

By introducing the lambda you enable ActiveRecord to use the return value of said lambda. The lambda itself will be executed with each validation.

Hope that made the situation clearer!

like image 36
art-solopov Avatar answered Nov 02 '22 23:11

art-solopov