2010-08-17 15 views
8

Tôi có một date_select trong quan điểm của tôi bên trong một hình thức, tuy nhiên trên trình giá trị trả về là ở dạng băm như vậy:cách chuyển đổi giá trị băm được trả về từ ngày_select trong đường ray thành đối tượng Ngày?

{"(1i)"=>"2010", "(2i)"=>"8", "(3i)"=>"16"} 

làm thế nào tôi có thể chuyển đổi đó vào một định dạng ngày trong đường ray vì vậy tôi có thể sử dụng nó như một điều kiện khi truy vấn cơ sở dữ liệu ví dụ: :condition => {:dates == :some_date_from_date_select}? tôi đã thử gọi Date.parse(:some_date_from_date_select) nhưng nó không hoạt động vì mong đợi một chuỗi và không phải là bản đồ băm.

có cách nào để làm điều này không?

nhờ

Trả lời

9

Tôi không biết về một cách đường ray, nhưng điều này "one-liner" hiện các trick:

irb(main):036:0> d = Date.parse({"(1i)"=>"2010", "(2i)"=>"8", "(3i)"=>"16"}.to_a.sort.collect{|c| c[1]}.join("-")) 
=> #<Date: 4910849/2,0,2299161> 
irb(main):037:0> d.to_s 
=> "2010-08-16" 

Hoặc, với ít ma thuật:

h={"(1i)"=>"2010", "(2i)"=>"8", "(3i)"=>"16"} 
d=Date.new(h['(1i)'].to_i, h['(2i)'].to_i, h['(3i)'].to_i) 
d.to_s 
=> "2010-08-16" 
+0

anh hùng, cảm ơn bạn –

0

Mã đặc biệt này (mã chuyển đổi) có thể được theo dõi từ lib/active_record/connection_adapters/abstract/schema_definitions.rb, dòng số 67 trở đi, tức là phương pháp type_cast.

Hai phương pháp được sử dụng để tạo ra một ngày từ chuỗi:

def fast_string_to_date(string) 
    if string =~ Format::ISO_DATE 
    new_date $1.to_i, $2.to_i, $3.to_i 
    end 
end 

# Doesn't handle time zones. 
def fast_string_to_time(string) 
    if string =~ Format::ISO_DATETIME 
    microsec = ($7.to_f * 1_000_000).to_i 
    new_time $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, microsec 
    end 
end 

# Note that ISO_DATE is: 
ISO_DATE = /\A(\d{4})-(\d\d)-(\d\d)\z/ 
2

tôi có một giải pháp dòng ngắn cho điều này

params["due_date"] = {"date(3i)"=>"14", "date(2i)"=>"4", "date(1i)"=>"2014"} 


params["due_date"].map{|k,v| v}.join("-").to_date 
=> Mon, 14 Apr 2014 
+2

là thứ tự của các yếu tố của một băm yên tâm? Mã này dường như phụ thuộc vào điều đó. – navjotk

+0

thứ tự của băm được đảm bảo trong ruby ​​1.9, nhưng không phải trong 1.8.7 –

1

Đây là một cách tổng quát để làm điều đó, mà cũng hỗ trợ một phần ngày/giờ và các trường trống:

def date_from_date_select_fields(params, name) 
    parts = (1..6).map do |e| 
    params["#{name}(#{e}i)"].to_i 
    end 

    # remove trailing zeros 
    parts = parts.slice(0, parts.rindex{|e| e != 0}.to_i + 1) 
    return nil if parts[0] == 0 # empty date fields set 

    Date.new(*parts) 
end 

Ví dụ cách sử dụng:

# example input: 
# 
# params = { 
# "user": 
#  "date_of_birth(1i)": "2010", 
#  "date_of_birth(2i)": "8", 
#  "date_of_birth(3i)": "16" 
# } 
# } 
date_of_birth = date_from_date_select_fields(params[:user], 'date_of_birth') 
+0

Ví dụ của bạn đã không làm việc cho tôi .. nhưng tôi đã chuyển đổi: Date.new (* parts) thành Time.zone.now (parts.join ("/")) sau đó nó làm việc tuyệt vời –

1
Date.new(*params["due_date"].values.map(&:to_i)) 

Lưu ý: Làm việc trong ruby ​​1.9.2+ vì nó phụ thuộc vào thứ tự của phần tử băm.

Hai goodies đây:

Các vấn đề liên quan