Rails 5:jquery用户输入数据不保存
Posted
技术标签:
【中文标题】Rails 5:jquery用户输入数据不保存【英文标题】:Rails 5: jquery user input data not saving 【发布时间】:2019-03-29 02:35:02 【问题描述】:我在 Rails 应用程序中有一个表单正在发布但不保存输入数据。
服务提供商有能力定义不同的葡萄酒套装,他提供例如 1、3、6、12 和更多一般信息,这些信息显示在 show.html.erb (wine_controller) 中。
更新
在 show.html.erb 中显示了一个 _form.html.erb,它使用了 reservations_controller。
逻辑是葡萄酒可以有很多保留。
目前瓶子被保存到数据库,但总数没有保存到数据库,因为 Reservations Controller 给出了 NoMethodError,因为瓶子是未定义的局部变量或方法。
葡萄酒控制器
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
当我尝试在 reservations_controller.rb 中实现 :bottles 时,我得到了 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】:看起来您的 ajax 正在将数据发送到不同的控制器。不是将其发送到“wine”控制器的“预加载”操作吗?
<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 %>
您的控制器似乎还没有接受瓶子数据,然后您可能没有正确引用它。我假设您的预订模型有一个名为瓶子的字段,其中包含整数数据。因此,这是我建议的更改:
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
然后为回调修改您的 Reservations 模型
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
【讨论】:
看起来您的 ajax 正在将数据发送到不同的控制器。不是将其发送到“葡萄酒”控制器的“预加载”操作吗?此外,也许只是将 wine_id 嵌入到预订时提交的 ajax 数据中。我将更新编辑内容 感谢您的回答,但提供的解决方案无法完全发挥作用。 ajax 将数据发送到葡萄酒控制器的预加载操作,没错,因为我也在预订表单中使用日历,因此我在 reservations_controller.rb 中使用 start_date。我将 update_financials 添加到了 Reservation 模型,并做了一些您建议的其他小改动。现在瓶子被保存到数据库中,但问题是我不能在预订控制器中调用 wine.bottles,因此无法计算总价。我收到一个方法错误... 在调用wine控制器时如何调用reservations控制器? 用户从 Wine 控制器看到 show.html.erb,在 show.html.erb 中,_form.html.erb 是从 Reservations Controller 呈现的,wines 控制器显示来自wine(供应商),并且预订控制器显示供应商提供的选项。葡萄酒和预订之间存在关联。我会用更多信息更新我的帖子。 我还是不明白为什么你的 ajax url 会发布到 wine 控制器?它不应该发布到预订控制器吗?你能连同请求数据一起显示整个错误和回溯吗以上是关于Rails 5:jquery用户输入数据不保存的主要内容,如果未能解决你的问题,请参考以下文章