2009-09-23 27 views
16

Wierzę, że datetime_select to czarna magia. Naprawdę staram się rozgryźć całe mnóstwo różnych parametrów. W szczególności, jak jest obsługiwany w back-end (activerecord, coś innego?). Co oznacza "i" po numerze zamówienia? Czy to jest specyfikator typu? Jeśli tak, to jakie inne rodzaje są dostępne? Znam źródło date_helper.rb i jest dość nieprzejrzysty.Jak wyróżnić atrybuty wielu atrybutów ruby ​​na szynach * naprawdę * praca (datetime_select)

Oto moja motywacja:

Mam kolumnę :datetime w moim modelu i chcę, aby wprowadzić w widoku poprzez dwa text_field s: jeden dla daty i jeden dla czasu. Należy je zweryfikować, scalić ze sobą, a następnie zapisać w kolumnie datetime. Docelowo będę używać kalendarza javascript do wprowadzania dat w polu daty.

Czy ktoś to zrobił? Próbowałem używać atrybutów wirtualnych (niewiarygodnie nieudokumentowanych poza prymitywnym railscastem), a problem polegał na tym, że gdy tworzony jest nowy obiekt activerecord i ma on atrybuty zerowe, atrybut wirtualny ulega uszkodzeniu (niezdefiniowana metoda strftime dla klasy zerowej, co ma sens).

Ktoś ma jakieś sugestie lub najlepsze praktyki? Dzięki!

+0

w activerecord/base.rb [assign_multiparameter_attributes] tworzy instancje dla wszystkich klas atrybutów, które wymagają więcej niż jednego parametru konstruktora. Działa to przez wywołanie new na kolumnie lub obiekcie typu agregacji z tymi parametrami. tj: written_on (1) = "2004", written_on (2) = "6", written_on (3) = "24", utworzy napis pisemny (typ daty) z Date.new ("2004", "6", "24"). Możesz również określić znak typograficzny w nawiasach, aby parametry były typograficzne, zanim zostaną użyte w konstruktorze. Użyj i dla Fixnum, f dla Float, s dla String i a for Array. –

+1

Witam Dean, jeśli znalazłeś własną odpowiedź, zwykle stosujesz "Odpowiedz na moje pytanie", aby ludzie mogli zobaczyć, jak pytanie zostało rozwiązane. – nfm

Odpowiedz

18

Miałem to samo pytanie. Oto co znalazłem ...

http://apidock.com/rails/ActiveRecord/Base/assign_multiparameter_attributes

assign_multiparameter_attributes (par) prywatny

instancję obiektów dla wszystkich atrybutów klas, które potrzebuje więcej niż jeden parametr konstruktora. Jest to wykonywane przez wywoływanie nowego typu kolumny lub obiektu agregacji (poprzez created_of) z tymi parametrami. Tak więc o parach zapisanych (1) = "2004", written_on (2) = "6", written_on (3) = "24", utworzy instancję napisane_on (typ daty) z Date.new (" 2004 "," 6 "," 24 "). Można również określić typecast postać w nawiasach mieć parametry typecasted zanim zostaną one wykorzystane w konstruktorze . Użyj i dla Fixnum, f dla Float, dla String, a dla Array. Jeśli wszystkie wartości dla danego atrybutu są puste, atrybut zostanie ustawiony na zero.

Tak więc liczby dotyczą parametrów typu danych w kolumnie. Litera "i" zamienia ją na liczbę całkowitą. Obsługiwane są inne typy, np. "F" dla float, itp.

Możesz zobaczyć tutaj w execute_callstack_for_multiparameter_attributes, że wykrywa typ celu i tworzy instancje przekazujące wartości.

Tak więc, aby spróbować bezpośrednio odpowiedzieć na postawione pytanie, nie sądzę, że można go użyć do przesłonięcia sposobu, w jaki tworzony jest obiekt DateTime, ponieważ używa on konstruktora, który nie obsługuje formatu, który ma zostać przekazany. Moja praca -around miał podzielić kolumnę DateTime na jedną kolumnę Data i jedną godzinę. Wtedy interfejs mógłby działać tak, jak chciałem.

Zastanawiam się, czy możliwe jest utworzenie atrybutów w klasie, które reprezentują datę i godzinę oddzielnie, ale zachowają jedną kolumnę DateTime. Następnie formularz może odwoływać się do tych oddzielnych akcesorów. To może być wykonalne. Inną opcją może być użycie composed_of w celu dalszego dostosowania typu.

Nadzieję, że pomaga komuś innemu. :)

+0

Yup. Idę z wirtualnymi atrybutami. – Ricky

2

Oto, co wymyśliłem. Jeśli ktoś ma jakieś uwagi, daj mi znać. Chciałbym uzyskać informację zwrotną.

validate :datetime_format_and_existence_is_valid 
    before_save :merge_and_set_datetime 

    # virtual attributes for date and time allow strings 
    # representing date and time respectively to be sent 
    # back to the model where they are merged and parsed 
    # into a datetime object in activerecord 
    def date 
    if (self.datetime) then self.datetime.strftime "%Y-%m-%d" 
    else @date ||= (Time.now + 2.days).strftime "%Y-%m-%d" #default 
    end 
    end 
    def date=(date_string) 
    @date = date_string.strip 
    end 
    def time 
    if(self.datetime) then self.datetime.strftime "%l:%M %p" 
    else @time ||= "7:00 PM" #default 
    end 
    end 
    def time=(time_string) 
    @time = time_string.strip 
    end 

    # if parsing of the merged date and time strings is 
    # unsuccessful, add an error to the queue and fail 
    # validation with a message 
    def datetime_format_and_existence_is_valid  
    errors.add(:date, 'must be in YYYY-MM-DD format') unless 
     (@date =~ /\d{4}-\d\d-\d\d/) # check the date's format 
    errors.add(:time, 'must be in HH:MM format') unless # check the time's format 
     (@time =~ /^((0?[1-9]|1[012])(:[0-5]\d){0,2}(\ [AaPp][Mm]))$|^(([01]\d|2[0-3])(:[0-5]\d){0,2})$/) 
    # build the complete date + time string and parse 
    @datetime_str = @date + " " + @time 
    errors.add(:datetime, "doesn't exist") if 
     ((DateTime.parse(@datetime_str) rescue ArgumentError) == ArgumentError) 
    end 

    # callback method takes constituent strings for date and 
    # time, joins them and parses them into a datetime, then 
    # writes this datetime to the object 
    private 
    def merge_and_set_datetime 
    self.datetime = DateTime.parse(@datetime_str) if errors.empty? 
    end 
+0

Sprawdź validates_timeliness dla walidacji daty, o wiele łatwiej. Zobacz także Date :: DATE_FORMATS AND Time :: DATE_FORMATS, aby uzyskać lepszy sposób tworzenia kolejnych formatów, których możesz użyć ponownie. Na przykład dodaję format taki jak Date :: DATE_FORMATS [: in_words] = "% b% e,% Y" i możesz wtedy powiedzieć Date.today.to_s (: in_words) w inicjalizatorze. – brad

+0

Nie ma potrzeby prefiksowania self. * Kiedy właśnie czytasz atrybut, więc lepiej użyć "if (datetime)" ... – Scholle

+0

@Scholle Nie zgadzam się, pracując z innymi programistami lubię wiedzieć, czy coś jest atrybutem czy metoda prywatna. W ten sposób sygnalizuję, że ... – OneChillDude