Odpowiedz

41

Użycie date_select daje 3 oddzielne pary klucz/wartość odpowiednio dla dnia, miesiąca i roku. Możesz więc przekazać je do Date.new jako parametry do utworzenia nowego obiektu Date.

Przykładem date_select powrócił params dla Event modelu

"event"=> 
{"name"=>"Birthday", 
    "date(1i)"=>"2012", 
    "date(2i)"=>"11", 
    "date(3i)"=>"28"}, 

Następnie, aby utworzyć nowy Date obiektu:

event = params[:event] 
date = Date.new event["date(1i)"].to_i, event["date(2i)"].to_i, event["date(3i)"].to_i 

może zamiast decydować się owinąć tę logikę w metodzie:

def flatten_date_array hash 
    %w(1 2 3).map { |e| hash["date(#{e}i)"].to_i } 
end 

A następnie nazwij to jako date = Date.new *flatten_date_array params[:event]. Ale to nie jest logika, która naprawdę należy do kontrolera, więc możesz zdecydować, aby przenieść ją gdzie indziej. Możesz nawet rozszerzyć to na klasę Date i nazwać ją jako date = Date.new_from_hash params[:event].

+9

Bardzo zaskakujące, że Railsy nie zawierają prostego mechanizmu konwersji, ponieważ mają już ukryty mechanizm, gdy dołączanie daty wybierze model. Znalazłem w dokumentacji Rails Guides, że sugerują użycie 'Date.civil', jaka jest różnica między tym a' Date.new'? –

+0

@at. Według dokumentów ruby, 'Date.civil' i' Date.new' są całkowicie identyczne. Zawsze używałem 'Date.new' jako jej więcej OOP-owski. I tak, zgadzam się z tobą, byłem również zaskoczony, że nie jest wbudowany w szyny. Ale prosta metoda 1-liniowa, taka jak powyższa, jest łatwa do naprawienia. – joofsh

+0

nie brzmi zbyt trudne do wdrożenia jako część torów – BKSpurgeon

3

Oto kolejna

Date.civil(params[:event]["date(1i)"].to_i,params[:event]["date(2i)"].to_i,params[:event]["date(3i)"].to_i) 
1

Z odpowiedzią date_select przykład @ joofsh, oto jest "jeden liner" I użyj, zakładając, że pole daty jest nazywane start_date:

ev_params = params[:event] 

date = Time.zone.local(*ev_params.select {|k,v| k.to_s.index('start_date(') == 0 }.sort.map {|p| p[1].to_i}) 
0

Oto kolejny jeden na szynach 5:

module Convert 
    extend ActiveSupport::Concern 

    included do 
    before_action :convert_date 
    end 

    protected 

    def convert_date 
    self.params = ActionController::Parameters.new(build_date(params.to_unsafe_h)) 
    end 

    def build_date(params) 
    return params.map{|e| build_date(e)} if params.is_a? Array 

    return params unless params.is_a? Hash 

    params.reduce({}) do |hash, (key, value)| 
     if result = (/(.*)\(\di\)\z/).match(key) 
     params_name = result[1] 
     date_params = (1..3).map do |index| 
      params.delete("#{params_name}(#{index}i)").to_i 
     end 
     hash[params_name] = Date.civil(*date_params) 
     else 
     hash[key] = build_date(value) 
     end 

     hash 
    end 
    end 
end 

trzeba dołączyć go do kontrolera lub application_controller.rb:

class ApplicationController < ActionController::Base 
    include Convert 
end 
-1

Albo po prostu to zrobić:

your_date_var = Time.parse(params[:my_date]) 
+0

params [: my_date] will be zero –

0

Używam następującej metody, która ma następujące zalety:

  1. nie trzeba jawnie wymienić klucze param xxx(1i) poprzez xxx(3i) (a więc może być zmodyfikowany tak, aby uchwycić godzinę i minutę po prostu zmieniając Date do DateTime); i
  2. wyodrębnia datę ze zbioru params, nawet jeśli te parametry są wypełnione wieloma innymi parami klucz-wartość.

params to skrót nazwy formatu { xxx(1i): '2017', xxx(2i): 12, xxx(3i): 31, ... }; date_key to wspólny podłańcuch xxx parametrów docelowej daty.

def date_from_params(params, date_key) 
    date_keys = params.keys.select { |k| k.to_s.match?(date_key.to_s) }.sort 
    date_array = params.values_at(*date_keys).map(&:to_i) 
    Date.civil(*date_array) 
end 

wybrałem, aby umieścić to jako metoda klasy ApplicationRecord, a nie jako metoda instancji pomocnikiem ApplicationController. Moje rozumowanie jest takie, że podobna logika istnieje w module ActiveRecord instantiator (, tj.Model.new) w celu analizowania dat przesłanych z formularzy Rails.