【问题标题】:Ruby on Rails 6 Turbolinks Stripe form values not persisting on backRuby on Rails 6 Turbolinks Stripe 表单值不会保留在背面
【发布时间】:2020-10-19 18:15:48
【问题描述】:

我正在尝试构建一个表单,允许用户预订他们希望参加的武术课程。我创建了一个表单,该表单根据用户所做的选择动态更改,当我更改任何选择选项时,表单会更新,当我提交表单时,它会重定向到 Stripe 结帐。我遇到的问题是在提交表单后单击浏览器后退按钮或 Stripe 结帐页面上提供的后退按钮,已更新的选择选项已恢复为默认选项,而不是更新后的选项。谁能帮我纠正这种行为并让正确的表单元素持续存在? 这是我用来执行此操作的代码: 我正在呈现表单的视图:

<% content_for :banner_title, @page_data['bannerTitle'] %>
<% content_for :head do %>
    <meta name="turbolinks-cache-control" content="no-cache">
<% end %>

<div class="content container py-5">
    <div class="row">
        <div class="col-12 col-md-7 mx-auto">
            <%= render "forms/booking", options: @options %>
        </div>
    </div>
</div>

我使用的表格:

<%= form_for @booking, class: 'booking clearfix' do |f| %>
    <div class="form-group">
        <%= f.label(:class_name, "Select a class you wish to attend: ") %>
        <%= f.select(:class_name, options_for_select(options[:class_names], @booking.class_name), {}, class: 'form-control' ) %>
    </div>

    <div class="form-group">
        <%= f.label(:date, "Select a date:") %>
        <%= f.select(:date, options_for_select( options[:dates], @booking.date ), {}, class: 'form-control' ) %>
    </div>

    <div class="form-group">
        <%= f.label(:time, "Select a time: ")%>
        <%= f.select(:time, options_for_select(options[:times], @booking.time), {}, class: 'form-control') %>
    </div>

    <div class="form-group">
        <%= f.label(:attendees, "How many attending: ") %>
        <%= f.select(:attendees, options_for_select(options[:attendees], @booking.attendees), {}, class: 'form-control' )%>
    </div>
    <%= f.submit 'Place Booking', class: 'btn btn-primary btn-lg text-light float-right', id: 'create-booking' %>
<% end %>

<%= javascript_pack_tag 'booking_form' %>
<script src="https://js.stripe.com/v3/"></script>

表单的模型(我没有使用 ActiveRecord,我不知道这是否有什么不同?):

class Booking
    include ActiveModel::Model

    MAX_ATTENDEES = 10
    attr_accessor :time, :class_data, :attendees, :date, :class_name

    def initialize(args={})
        @time = args['time']
        @class_name = args['class_name']
        @class_data = args['class_data']
        @date = args['date']
        @attendees = args['attendees']
    end

    def day
        @date.split(',').first
    end

    def available_dates
        days_index_array = class_data['times'].keys.map {|k| day_index(k) }
        days_within( days_index_array ) 
    end

    def available_times
        if !date
            class_data['times'][class_data['times'].keys.first.downcase]
        else
            class_data['times'][day.downcase]
        end
    end

    def total_cost
        @class_data['cost'].to_i * @attendees.to_i
    end

    def attending_string
        ActionController::Base.helpers.pluralize(attendees, 'person')
    end

    private

    def days_within(days, timeframe=1.month)
        start_date = Date.tomorrow
        end_date = start_date + timeframe
        (start_date..end_date).to_a.select {|k| days.include?(k.wday) }
    end

    def day_index(day)
        DateTime::DAYNAMES.index(day.to_s.capitalize)
    end
end

以及我在其中调用新操作的控制器:

class BookingsController < ApplicationController
    include BookingsHelper
    before_action :set_class_data
    skip_before_action :set_page_data, except: :new

    def new
        set_booking
        
        # store values to be passed to the form helper method options_for_select. Each value must be an array populated with arrays with the format [value, text]
        @options = {
            class_names: @class_data.map {|c| [ c['name'], c['name'] ]}, 
            dates: @booking.available_dates.map {|d| [d.strftime('%A, %d %B'), d.strftime('%A, %d %B')] },
            times: @booking.available_times.map {|t| [t,t]},
            attendees: Booking::MAX_ATTENDEES.times.map {|i| [i+1, i+1]}
        }
    end

    def create
    end

    def booking_form_data
        booking_form_data = set_booking_form_data(params)    
        update_session_booking(booking_form_data)
        render json: booking_form_data
    end
    
    private
    
    def set_booking
        if session[:current_booking]
            pp "session exists"
            @booking = Booking.new(session[:current_booking])
        else
            pp "session does not exist"
            @booking = Booking.new
            session[:current_booking] = @booking.instance_values
        end
        set_booking_class_data
    end

    def set_booking_class_data
        !@booking.class_name ? @booking.class_data = @class_data.first.except('information') : @booking.class_data = @class_data.find {|cd| cd['name'] == @booking.class_name}.except('information')
    end
    
    def booking_params
        params.permit(:class_name, :date, :time, :attendees, :update_type)
    end

    def update_session_booking(booking_form_data)
        if params[:update_type] == 'class_name'
            session[:current_booking]['class_name'] = params[:class_name]
            session[:current_booking]['date'] = booking_form_data[:date_options].first
            session[:current_booking]['time'] = booking_form_data[:time_options].first
        elsif params[:update_type] == 'date'
            session[:current_booking]['date'] = params[:date]
            session[:current_booking]['time'] = booking_form_data[:time_options].first
        elsif params[:update_type] == 'time'
            session[:current_booking]['time'] = params['time']
        elsif params[:update_type] == 'attendees'
            session[:current_booking]['attendees'] = params[:attendees]
        elsif params[:update_type] == 'load'
            session[:current_booking] = booking_params.except(:update_type) 
        end
        pp "Session Booking: #{session[:current_booking]}"
    end

    def set_booking_form_data(params)
        booking_form_data = {}
        selected_class = @class_data.find {|cd| cd['name'] == params[:class_name] }
        # when the class_name select is changed
        if params[:update_type] == 'class_name'
            booking_form_data[:date_options] = days_within( selected_class['times'].keys.map {|k| day_index(k) } ).map {|d| d.strftime('%A, %d %B') }
            booking_form_data[:time_options] = selected_class['times'][booking_form_data[:date_options].first.split(',')[0].downcase]
        # when date select is changed
        elsif params[:update_type] == 'date'
            booking_form_data[:time_options] = selected_class['times'][params[:date].split(',')[0].downcase]
        end
        booking_form_data
    end
end

还有我用来更新表单的javascript:

getBookingFormData = (bodyData={}, successCallback=()=>{}) => {
    $.ajax({
        url: '/booking_form_data',
        method: 'POST',
        beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))},
        data: bodyData,
        success: successCallback
    })
}

createOptions = (values) => {
    let newOptions = [];
    $.each(values, (index, value) => {
        let newOption = $('<option></option>');
        newOption.attr('value', value);
        newOption.text(value);
        newOptions.push(newOption)
    })
    return newOptions
}

appendOptions = (options, element) => {
    $(element).empty();
    $(element).append(options)
}

currentFormValues = () => {
    return {
        class_name: $('#booking_class_name').val(),
        date: $('#booking_date').val(),
        time: $('#booking_time').val(),
        attendees: $('#booking_attendees').val()
    }
}

$('select#booking_class_name').on('change', () => {
    let bodyData = { 
        class_name: $('select#booking_class_name').val(),
        update_type: 'class_name'
    }
    let successCallback = (res) => {
        let dateOptions = createOptions(res.date_options);
        let dateSelect = $('select#booking_date');
        let timeOptions = createOptions(res.time_options);
        let timeSelect = $('select#booking_time');
        appendOptions(dateOptions, dateSelect);
        appendOptions(timeOptions, timeSelect);
    }
    getBookingFormData(bodyData, successCallback)
});

$('select#booking_date').on('change', () => {
    let bodyData = {
        class_name: $('select#booking_class_name').val(),
        date: $('select#booking_date').val(),
        update_type: 'date'
    };
    let successCallback = (res) => {
        let timeOptions = createOptions(res.time_options);
        let timeSelect = $('select#booking_time');
        appendOptions(timeOptions, timeSelect);
    }
    getBookingFormData(bodyData, successCallback)
});

$('select#booking_time').on('change', () => {
    let bodyData = {
        time: $('select#booking_time').val(),
        update_type: 'time'
    };
    getBookingFormData(bodyData);
});

$('select#booking_attendees').on('change', () => {
    let bodyData = {
        attendees: $('select#booking_attendees').val(),
        update_type: 'attendees'
    };
    getBookingFormData(bodyData);
});


$('#create-booking').on('click',(e) => {
    e.preventDefault();
    bookingDefault = false
    const stripe = Stripe(process.env.STRIPE_PUBLIC);
    
    let requestHeaders = new Headers({
        'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content'),
        'Content-Type': 'application/json'
    })

    fetch('/create_checkout_session', { 
        method: 'POST',
        headers: requestHeaders,
        body: JSON.stringify(currentFormValues()) 
    })
    .then((res) => { return res.json() })
    .then((session) => { return stripe.redirectToCheckout({ sessionId: session.id }) })
    .then((result) => { 
        if (result.error) { alert(result.error.message) }
    })
    .catch((error) => { console.error('Error: ', error) })
})

从我读过的内容来看,我认为这可能是与缓存有关的问题,这让我认为这是 turbolinks 的问题,但我可能完全错了。我尝试添加禁用 turbolinks 或强制它重新加载页面的元标记,但它们似乎不起作用。 任何输入都将不胜感激,因为我已经坚持了好几天了。如果您需要更多信息,请告诉我

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-6 turbolinks


    【解决方案1】:

    这与 Stripe 无关,而是与您的表单值管理相关。如果您想保留这些值,则需要以某种方式将其构建到您的前端应用程序中。有很多选择:

    • 使用本地存储
    • 使用查询参数(如果不是敏感信息)
    • 使用 cookie 和服务器会话,您可以使用 default value 重新检索和补充 f.select 选项。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-09-30
      • 1970-01-01
      • 2018-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-16
      相关资源
      最近更新 更多