Rails/Ajax 在提交后将表单从创建更改为更新
Posted
技术标签:
【中文标题】Rails/Ajax 在提交后将表单从创建更改为更新【英文标题】:Rails/Ajax change form from create to update after submission 【发布时间】:2013-11-14 22:13:33 【问题描述】:所以我想玩一个星级评分页面,其中有 5 个评分问题,您可以评分一次(创建)并在任何给定时间更新您的评分。评分表单是 ajaxified,但问题是表单元素在提交后保持为 Create 方法而不是 update 方法。
我遵循了eighty-b 的一个非常酷的教程,但是缺少关于将表单更新为正确方法的部分。
这里是代码
我在部分rating_questions/_quick_form.html.erb
中有一个表格,每个评级表格都有一个嵌套表格。请注意,表单路由使用帮助器来定义它是否应该是创建或更新操作
<div class="rating_questions">
<% @rating_questions.each do |rating_question| %>
<%= render partial: "rating_questions/rating_form", :locals => :rating_question => rating_question %>
<% end %>
</div>
rating_form.html.erb
部分
# EDIT: I added the temporary random id in an instance variable to make sure the form id and hidden_field have the same reference
<% @rand_id = SecureRandom.hex %>
<%= form_for(rating_ballot(rating_question), :remote => true, :html => :class => 'rating_ballot', :id => @rand_id) do |f| %>
<div class="rq"><%= rating_question.title %></div>
<%= hidden_field_tag :temp_id, @rand_id %>
<%= f.label("value_#rating_question.id_1", content_tag(:span, '1'), :class => "rating", :id => "1") %>
<%= radio_button_tag("rating[value]", 1, current_user_rating(rating_question) == 1, :class => 'radio_button', :id => "rating_value_#rating_question.id_1") %>
... (the other rating radio buttons) ...
<%= f.hidden_field("rating_question_id", :value => rating_question.id) %>
<%= f.submit :Submit, :id => "rating_submit" %>
<% end %>
然后在我的create.js.erb
中添加了用部分替换表单的行
$('#<%= params[:temp_id] %>').replaceWith("<%= j render(partial: 'rating_questions/rating_form', locals: :rating_question => @rating_question) %>");
如果存在现有记录,则用于定义表单是创建还是更新的辅助方法
def rating_ballot(rating_question)
if @rating = current_user.ratings.find_by_rating_question_id(rating_question.id)
[rating_question, @rating]
else
[rating_question, current_user.ratings.new]
end
end
def current_user_rating(rating_question)
if @rating = current_user.ratings.find_by_rating_question_id(rating_question.id)
@rating.value
else
"N/A"
end
end
还有我的ratings_controller.rb
需要create.js.erb
和update.js.erb
def create
@rating_question = RatingQuestion.find_by_id(params[:rating_question_id])
@rating = Rating.new(params[:rating])
@rating.user_id = current_user.id
if @rating.save
respond_to do |format|
format.html redirect_to rating_questions_path, :notice => "Your rating has been saved"
format.js
end
end
end
def update
@rating_question = RatingQuestion.find_by_id(params[:rating_question_id])
@rating = current_user.ratings.find_by_rating_question_id(@rating_question.id)
if @rating.update_attributes(params[:rating])
respond_to do |format|
format.html redirect_to rating_questions_path, :notice => "Your rating has been updated"
format.js
end
end
end
显然我只想更新刚刚提交的表单,而不是其他表单。 关于如何在 create.js.erb 和 update.js.erb 中使用 javascript 以正确的方法重新加载表单的任何想法?
非常感谢!
编辑~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (参见上面的编辑)
我按照你的建议继续,我在表单中添加了随机 id 并更改了 create.js.erb,但我遇到了问题:
1) 评级表格被替换后,Javascript 不再适用于该部分。
这里也是星星动态交互的咖啡脚本(其实就是单选标签的形式)
$ ->
# Add the "Bright class" to the stars for each checked radio button before the document is ready.
$("form.rating_ballot").each ->
checkedId = undefined
checkedId = $(this).find("input:checked").attr("id")
$(this).find("label[for=" + checkedId + "]").prevAll().andSelf().addClass "bright"
$(document).ready ->
# makes stars glow on hover.
$("form.rating_ballot > label").hover (-> # mouseover
$(this).prevAll().andSelf().addClass "glow"
), -> # mouseout
$(this).siblings().andSelf().removeClass "glow"
# makes stars stay glowing after click.
$("form.rating_ballot > label").click ->
$(this).siblings().removeClass "bright"
$(this).prevAll().andSelf().addClass "bright"
# Submits the form (saves data) after user makes a change.
$(".rating_ballot").change ->
$(this).submit()
编辑2~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~ 更正了更新操作提交所有表单的事实。
【问题讨论】:
【参考方案1】:如果我没听错的话……
1.将生成的 ID 作为隐藏字段添加到表单中
此 ID 不一定是模型的虚拟属性,但可以。另一种选择是将它放在您的质量分配数组之外,例如 params[:controller]
也是。
例如:<%= hidden_field_tag :temporary_id, SecureRandom.hex %>
。有关创建随机字符串的其他可能性,请查看how-best-to-generate-a-random-string-in-ruby 。
还要确保您的表单(或在您的表单中呈现的第一个元素)具有生成的随机字符串作为id
或data-
属性,因此您可以在不使用复杂选择器的情况下访问它一步。
2。更新您的 create.js.erb
我假设您在创建操作中的format.js
传递给create.js.erb
。因此,在那里,您通过搜索提交时传递的临时 id 将整个表单替换为新表单。
示例:$('#<random_id_of_your_form>').replaceWith('<%= j render(partial: 'form', locals: ...) %>');
请确保不要省略 the j
helper,因为它会编码您呈现的表单以便在 javascript 中保存使用。当您呈现通常的表单时,创建操作会执行其通常的业务,现在还用新的渲染表单替换表单,其中自动调用“更新”操作(路由中通常的轨道“魔术”内容,即是。就像你会呈现另一个通常的编辑表单)。
Javascript
评级表格被替换后,Javascript 不再适用于该部分。
当然不是。您正在将事件绑定到文档加载时的特定元素。之后插入的元素(通过创建/更新)是新添加的,因此没有该事件绑定,因为它们在事件绑定发生时不可用。
由于events are "bubbling",您需要将您的代码绑定到一个容器,该容器在您的 js 修改中是持久的。假设您的 create.js 仅更新/替换 #rating_questions_container
中的元素,您需要将 js 重写为例如
$('#rating_questions_container').on('click', 'form.rating_ballot > label', function(e)
# code
);
$('#rating_questions_container')
是您页面上的“持久”容器,可以捕获事件
.on('click', 'form.rating_ballot > label'
监视与第二个参数中的选择器匹配的元素上的点击事件,此处为 form.rating_ballot > label
。
这允许在#rating_questions_container
内动态追加/删除 DOM 节点,而不会丢失事件侦听器。
【讨论】:
您好,谢谢您的及时回答,我想我的问题不是很清楚,分为两部分。如果我理解正确,随机 id 是为了帮助定义我希望更新的特定表单?这肯定会有所帮助,因为我有 5 个类似的表格。在用 Ajax 深入挖掘之后,当它重新加载表单时,它并没有使用辅助方法rating_ballot
,它定义了表单rating_questions/1/ratings # create
或rating_questions/1/ratings/1 # update
的路由。我会试试你的解决方案,看看它是否能解决我一半的问题:)
是的,这就是随机 id 的意图。我看到了你的助手,这应该可以工作,因为你传递了一个包含两个对象的数组来构建路径。您只需要将您的表单放入一个可以同时处理create
和update
的部分,现在应该是这种情况。
所以我听从了您的建议,但遇到了更多问题。 1)当我提交一个评级(无论是创建还是更新)时,它会为他们重新加载部分。 2)重新加载partial后不再使用Coffescript文件中的jQuery。在我的原始帖子中查看我的编辑。
更新了我的答案以解决您的 javascript 问题。但我没有得到你的第一个问题;你想更新部分,不是吗?因为这会更新表单标签和其中的所有内容,这是正常工作的更新表单所必需的。
好吧,这有点疯狂,但我结束了到处添加 .on() 函数。现在一切正常!非常感谢 pduersteler! (出于某种原因,我必须等待 1 小时才能给予赏金-.-)以上是关于Rails/Ajax 在提交后将表单从创建更改为更新的主要内容,如果未能解决你的问题,请参考以下文章
是否可以在创建后将 Express Session 更改为不同的商店
magnific popup:以编程方式将内容从弹出表单更改为模态微调器,然后返回表单