레일의 시간대 다루기

16003 단어 rubytimezonesrails
이 Rails 포트폴리오 프로젝트를 하면서 정말 즐거웠습니다. 내 레일 프로젝트에 대한 나의 아이디어는 기도 모임이었습니다. 기도회에는 많은 참석자가 있어야 하고 기도회에 가져갈 기도도 있어야 합니다. 또한 관리자 역할을 하는 호스트가 있으며 호스트만 모임에서 CRUD 작업을 수행할 수 있습니다. 모든 사용자는 기도 모임을 위한 기도를 만들 수도 있습니다. 다음은 내 관계 테이블입니다.



기도 모임 협회

나는 도전적인 2개의 영역을 가지고 있었다. 하나는 내 모임 양식에 주소를 올바르게 추가하는 것이 었습니다. 이 양식에서는 모델을 사용하여 주소 개체를 만들어야 했습니다. 돌이켜보면 이것은 복잡한 문제에 대한 간단한 해결책이었습니다. 이것이 주소와 관련하여 시작한 코드입니다.

    def gathering_params
        params.require(:gathering).permit(:name, :meeting_date, :phone_number, :host_id, :url, :timezone, :address => [:address_1, :address_2, :city, :state, :zipcode])
    end


그리고 이것은 아래의 내 양식이었습니다.

<%= form_for @gathering do |f| %>
<%= f.label :name %><br>
<%= f.text_field :name %><br><br>
<%= f.label :meeting_date %><br>
<%= f.datetime_select :meeting_date, default: Time.now.localtime, ampm: true %><br><br>
<%= f.label :timezone %><br>
<%= f.time_zone_select :timezone, ActiveSupport::TimeZone.us_zones %><br><br>
<%= f.label :phone_number %><br>
<%= f.text_field :phone_number %><br><br>
<%= f.hidden_field :host_id, :value => @host.id %>
<%= f.label :url, "URL" %><br>
<%= f.text_field :url %><br><br>
<%= f.fields_for :address, @address do |a| %>

    <%= a.label :address_1 %><br>
    <%= a.text_field :address_1 %><br><br>
    <%= a.label :address_2 %><br>
    <%= a.text_field :address_2 %><br><br>
    <%= a.label :city %><br>
    <%= a.text_field :city %><br><br>
    <%= a.label :state %><br>
    <%= a.select :state, options_for_select(us_states) %><br><br>
    <%= a.label :zipcode %><br>
    <%= a.text_field :zipcode %><br><br>

<% end %>

    <%= f.submit :class => "button" %><br><br>
<% end %>


나는 원래 주소라는 해시에서 모든 것을 받아들일 수 있는 한 레일이 주소라는 객체를 생성해야 한다고 생각했습니다. 그러나 나는 rails가 주소 필드를 허용하지 않는다는 것을 금방 깨달았습니다. 인터넷 검색을 하고 주소 개체를 여러 번 가지고 놀다가 주소 대신 address_attributes가 필요하다는 것을 깨달았습니다. 또한 내 채집 개체의 주소가 하나뿐이었기 때문에 빌드 방법이 다릅니다. 다음과 같아야 합니다.

self.build_address(attributes)


이 작업을 수행하고 강력한 매개변수를 아래에 표시된 것으로 변경한 후 마침내 계속 진행할 수 있었습니다.

    def gathering_params
        params.require(:gathering).permit(:name, :meeting_date, :phone_number, :host_id, :url, :timezone, :address_attributes => [:address_1, :address_2, :city, :state, :zipcode])
    end


제 두 번째 주요 문제는 시간 검증과 관련이 있었습니다. 모임 시간을 위해 datetime 개체를 만들었습니다. 처음에 내 양식은 다음과 같습니다.

<%= f.label :meeting_date %><br>
<%= f.datetime_select :meeting_date, default: Time.now.localtime, ampm: true %>


생성 버튼을 눌렀을 때 생성된 날짜/시간이 현지 시간이 아닌 UTC 시간임을 깨달았습니다. 머리를 뽑고 나서 이 문제를 해결할 방법이 없다는 것을 깨달았습니다. 나는 2개의 선택이 있었다. 하나는 UTC(소프트웨어 엔지니어 외에는 아무도 이해하지 못하는)로 회의 시간을 만드는 것이거나 시간대를 설정해야 했습니다. 나는 이 문제를 해결하는 것이 나의 교화를 위한 것임을 깨달았고, 그래서 나는 고통스럽게 "시간대"라는 모임 테이블에 열을 추가하고 다음과 같이 내 양식을 다시 실행하기로 결정했습니다.

<%= f.label :meeting_date %><br>
<%= f.datetime_select :meeting_date, default: Time.now.localtime, ampm: true %><br><br>
<%= f.label :timezone %><br>
<%= f.time_zone_select :timezone, ActiveSupport::TimeZone.us_zones %><br><br>


time_zone_select를 사용하면 사용자가 시간대를 올바르게 식별하고 시간대 오프셋을 조정할 수 있습니다. 내 set_in_timezone 방법은 다음과 같습니다.

    def set_in_timezone(time, zone)
        Time.use_zone(zone) { time.to_datetime.change(offset: Time.zone.now.strftime("%z")) }
    end


Me Gathering 컨트롤러는 다음과 같이 생겼습니다.

    def create

        @host = current_user
        @gathering = @host.gatherings.build(gathering_params)
                @gathering.set_in_timezone(@gathering.meeting_date, @gathering.timezone)
                @gathering.save
    end    


내 컨트롤러에서 내 업데이트 작업을 실행할 때까지 이 작업을 수행하는 데 아무런 문제가 없었습니다. 여기에 코드가 있습니다.

    def update
        @host = current_user
        @gathering = Gathering.find(params[:id])
        #@gathering.meeting_date = set_in_timezone(@gathering.meeting_date, gathering_params[:timezone])

        if @gathering.update(gathering_params) && @gathering.address.save
            redirect_to gathering_path(@gathering)
        else
            flash[:error] = @gathering.errors.full_messages.to_sentence + @gathering.address.errors.full_messages.to_sentence
            render :edit
        end
        #binding.pry
        #@gathering.address.update(gathering_update_address_params)
    end


여기서 문제는 업데이트와 유효성 검사가 모두 @gathering.update 메서드에서 일어난다는 것입니다! before_validation 메서드를 사용할 수 있다는 것을 알게 되었습니다. 그래서 이것을 제대로 하기 위해서는 유효성 검사 전에 적절한 시간을 재설정해야 했습니다. 내 코드는 다음과 같습니다.

    before_validation do
        self.meeting_date = set_in_timezone(self.meeting_date, self.timezone)
    end


마침내 그 변경을 한 후에 나는 갈 수있었습니다. 또한 유효성 검사 중에 생성된 meeting_date가 과거가 아닌지 확인했습니다. 이 유효성 검사는 다음과 같습니다.

    validate    :future_event

    def future_event
        if meeting_date != nil

            errors.add(:meeting_date, "cannot be in the past.") if self.meeting_date.in_time_zone < Time.zone.now
        end

    end 


이 모든 것이 구현된 후 마침내 계속 진행할 수 있었습니다. 즐거운 코딩하세요!

좋은 웹페이지 즐겨찾기