Rails 5:jQuery用户输入数据未保存

时间:2018-10-24 15:41:18

标签: jquery ruby-on-rails ruby-on-rails-5

我在Rails应用程序中有一个表单,该表单正在发布但未保存输入数据。

服务提供商有能力定义不同的酒具,例如,他提供了1,3,6,12以及更多常规信息,这些信息显示在show.html.erb(wine_controller)中。

更新

在show.html.erb中显示一个_form.html.erb,它使用Reservations_controller。

逻辑是,葡萄酒可以有很多保留。

当前,瓶子已保存到数据库,但总数未保存到数据库,因为由于瓶子是未定义的局部变量或方法,所以Reservations Controller给出了NoMethodError。

Wines Controller

class WinesController < ApplicationController
  before_action :set_wine, except: [:index, :new, :create]
  before_action :authenticate_user!, except: [:show]
  before_action :is_authorised, only: [:details, :pricing, :description, :photo_upload, :more_details, :sets, :location, :update]

  def index
    @wines = current_user.wines
  end

  def new
    @wine = current_user.wines.build
  end

  def create
    @wine = current_user.wines.build(wine_params)
    if @wine.save
      redirect_to details_wine_path(@wine), notice: "Saved..."
    else
      flash[:alert] = "Something went wrong..."
      render :new
    end
  end

  def show
    @photos = @wine.photos
    @guest_reviews = @wine.guest_reviews
  end

  def details
  end

  def pricing
  end

  def description
  end

  def photo_upload
    @photos = @wine.photos
  end

  def more_details
  end

  def sets
  end

  def location
  end

  def update

    new_params = wine_params
    new_params = wine_params.merge(active: true) if is_ready_wine

    if @wine.update(wine_params)
      flash[:notice] = "Saved..."
    else
      flash[:alert] = "Something went wrong..."
    end
    redirect_back(fallback_location: request.referer)
  end

  def preload
    today = Date.today
    # Reservations greater than today (upcoming reservations)
    reservations = @wine.reservations.where("start_date >= ?", today)

    render json: reservations
  end


  private
  def set_wine
    @wine = Wine.find(params[:id])
  end
  # Authorize user (current_user == ID 1)
  def is_authorised
    redirect_to root_path, alert: "You don't have permission" unless current_user.id == @wine.user_id
  end

  def is_ready_wine
    !@wine.active && !@wine.price.blank? && !@wine.base_price.blank? && !@wine.wine_name.blank? && !@wine.summary.blank? && !@wine.photos.blank? && !@wine.alcohol.blank? && !@wine.filling.blank? && !@wine.in_stock.blank? && !@wine.address.blank?
  end

  def wine_params
    params.require(:wine).permit(:wine_type, :wine_color, :wine_art, :alcohol, :wine_name, :summary, :address, :is_1, :is_3, :is_6, :is_12, :filling, :base_price, :price, :in_stock, :year, :active)
  end
end

Reservation.rb

class Reservation < ApplicationRecord
  before_save :update_financials

  belongs_to :user
  belongs_to :wine

  def update_financials
    total = wine.price * bottles if wine.present? && bottles.present?
    price = wine.price if wine.present?
  end
end

我的_form.html.erb助手功能

  def wine_quantity(wine)
    case
    when wine.is_1 && wine.is_3 && wine.is_6 && wine.is_12 then [["1 Flasche", 1], ["3 Flaschen", 3], ["6 Flaschen", 6], ["12 Flaschen", 12]]
    when wine.is_1 && wine.is_3 && wine.is_6 then [["1 Flasche", 1], ["3 Flaschen", 3], ["6 Flaschen", 6]]
    when wine.is_1 && wine.is_3 && wine.is_12 then [["1 Flasche", 1], ["3 Flaschen", 3], ["12 Flaschen", 12]]
    when wine.is_1 && wine.is_6 && wine.is_12 then [["1 Flasche", 1], ["6 Flaschen", 6], ["12 Flaschen", 12]]
    when wine.is_1 && wine.is_12 then [["1 Flasche", 1], ["12 Flaschen", 12]]
    when wine.is_1 && wine.is_6 then [["1 Flasche", 1], ["6 Flaschen", 6]]
    when wine.is_1 && wine.is_3 then [["1 Flasche", 1], ["3 Flaschen", 3]]
    else
      end
    end

如果提供商选择提供6瓶和12瓶,则form.html.erb中仅显示6瓶和12瓶

我的_form.html.erb:

<div class="panel-body">
    <%= form_for([@wine, @wine.reservations.new]) do |f| %>
      <div class="panel-body">
        <div class="col-md-12">
          <label>Lieferdatum</label>
          <%= f.text_field :start_date, readonly: true, placeholder: "Lieferdatum", class: "form-control datepicker" %>
        </div>
        <!-- BUY SET? -->
        <div class="col-md-12 select" style="margin-top:10px">
          <div class="form-group">
            <label>Anzahl an Flaschen</label>
            <%= f.select :bottles, wine_quantity(@wine), {}, id: "bottles", prompt: "Auswählen...", class: "form-control" %>
        </div>
      </div>
      </div>

      <div id="preview" style="display:none">
        <table class="reservation-table">
          <tbody>
            <tr>
              <td>Preis pro Flasche</td>
              <td class="text-right"><%= @wine.price %>€</td>
            </tr>
            <tr>
              <td>Anzahl Flaschen</td>
              <td class="text-right">x <span id="reservation_bottles"></span></td>
            </tr>
            <tr>
              <td class="total">Gesamt</td>
              <td class="text-right"><span id="reservation_total"></span>€</td>
            </tr>
          </tbody>
        </table>
      </div>

      <br/>
      <%= f.submit "Bestellen", id: "btn_book", class: "btn btn-normal btn-block", disabled: true %>
    <% end %>
  </div>
</div>

<script>

$(function() {

  $.ajax({
    url: '<%= preload_wine_path(wine_id: @wine.id) %>',
    dataTyp: 'json',
    success: function(data) {

      var bottles = document.getElementById("bottles").value;
      var total = bottles * <%= @wine.price %>
      $('#reservation_bottles').text(bottles);
      $('#reservation_total').text(total.toFixed(2));

      $('#reservation_start_date').datepicker({
        dateFormat: 'dd-mm-yy',
        minDate: 2,
        maxDate: '5d',
        beforeShowDay: $.datepicker.noWeekends,
        onSelect: function(selected) {
          $('#preview').show();
          $('#btn_book').attr('disabled', false);

          $('#bottles').on('click', function() {
          var bottles = $(this).val();
          var total = bottles * <%= @wine.price %>

          $('#reservation_bottles').text(bottles);
          $('#reservation_total').text(total.toFixed(2));

          });
        }
      });
    }
  });
});

</script>

我的预订控制器:

class ReservationsController < ApplicationController
  before_action :authenticate_user!

  def create
    wine = Wine.find(params[:wine_id])

    if current_user == wine.user
      flash[:alert] = "Du kannst nicht deinen eigenen Wein kaufen!"
    else

    start_date = Date.parse(reservation_params[:start_date])

    @reservation = current_user.reservations.build(reservation_params)
    @reservation.wine = wine
    @reservation.price = wine.price
    @reservation.total = wine.price * bottles
    @reservation.save

    flash[:notice] = "Erfolgreich Bestellt!"
  end
    redirect_to wine
  end

  def your_orders
    @orders = current_user.reservations.order(start_date: :asc)
    @today = Date.today
  end

  def your_reservations
    @wines = current_user.wines
  end

  # Each Order Details
  def order_details
    @orders = current_user.reservations.order(start_date: :asc)
  end

  private
  def reservation_params
    params.require(:reservation).permit(:start_date)
  end

end

当我尝试将:bottles实现到Reservations_controller.rb中时,出现了NoMethodError ...我认为我正在将输入数据从form.html.erb解析到Reservations控制器中。

以下是请求:

{"utf8"=>"✓",
 "authenticity_token"=>"3xgM8kSLwa+8JafBZYMoX+BA2XgelWY5bY7yENMrtqAxXCrBb6IabNFa72BG0H6jYnszkzZ/oilOLbka2mmVUA==",
 "reservation"=>{"start_date"=>"26-10-2018", "bottles"=>"3"},
 "commit"=>"Bestellen",
 "wine_id"=>"3"}

1 个答案:

答案 0 :(得分:0)

好像您的ajax正在将数据发送到另一个控制器。它不是将其发送到“葡萄酒”控制器的“预载”操作吗?

<script>
$(function() {

  $.ajax({
    // updated URL
    url: '<%= reservation_path(wine_id: @wine.id) %>',
    // updated datatype field name
    dataType: 'json',
    success: function(data) {

      var bottles = document.getElementById("bottles").value;
      var total = bottles * <%= @wine.price %>
      $('#reservation_bottles').text(bottles);
      $('#reservation_total').text(total);

      $('#reservation_start_date').datepicker({
        dateFormat: 'dd-mm-yy',
        minDate: 2,
        maxDate: '5d',
        beforeShowDay: $.datepicker.noWeekends,
        onSelect: function(selected) {
          $('#preview').show();
          $('#btn_book').attr('disabled', false);

          $('#bottles').on('click', function() {
          var bottles = $(this).val();
          var total = bottles * <%= @wine.price %>

          $('#reservation_bottles').text(bottles);
          $('#reservation_total').text(total.toFixed(2));

          });
        }
      });
    }
  });
});
</script>

还要在表单中为wine_id创建一个隐藏字段;注意:假设您使用的是form_for或form_with

<%= form.hidden_field :wine_id, @wine.id %>

看上去您的控制器还没有接受瓶子数据,因此您可能未正确引用它。我假设您的预订模型具有一个称为Bottles的字段,其中包含整数数据。因此,这是我建议的更改:

class ReservationsController < ApplicationController
  def create
    # you don't need to look up the wine to assign it the reservations; skip this
    # wine = Wine.find(params[:wine_id])

    # TBH, I would move this into a validation check
    if current_user == wine.user
      flash[:alert] = "Du kannst nicht deinen eigenen Wein kaufen!"
      # don't you need to render the original page so the user can edit the choice?  something like:
      # render :new
    else

    # what are you using start_date for?  seems like you should remove it
    # start_date = Date.parse(reservation_params[:start_date])

    @reservation = current_user.reservations.build(reservation_params)
    # The math on reservation is more appropriate within the reservations model

    if @reservations.save
      flash[:notice] = "Erfolgreich Bestellt!"
    else
      # handle errors here
    end
  end

 ...

  private

  # you need to add bottles and wine_id to your permitted params
  def reservation_params
    params.require(:reservation).permit(:start_date, :bottles, :wine_id)
  end
end

然后修改回调的预订模型

class Reservation < ActiveModel
  # use a callback to update the model when fields are changed
  before_save :update_financials
  ...
  def update_financials
    total = wine.price * bottles if wine.present? && bottles.present?
    price = wine.price if wine.present?
  end
end

最后一条评论,我可能会将current_user == wine.user移至预订的有效性检查中。这稍微复杂一点,但是简化了控制器,并使您可以更轻松地在模型中对其进行测试。参见此处:https://guides.rubyonrails.org/active_record_validations.html#custom-methods