3

所以我想玩一个星级评分页面,我有 5 个评分问题,您可以评分一次(创建)并在任何给定时间更新您的评分。评分表单是 ajaxified,但问题是表单元素在提交后保留为 Create 方法,而不是 update 方法。

我遵循了80-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.erbupdate.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()

EDIT 2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 更新的事实行动是提交所有的形式更正。

4

1 回答 1

3

如果我说对了...

1. 将生成的 ID 作为隐藏字段添加到表单
中 此 ID 不一定是模型的虚拟属性,但可以。另一种选择是将它放在您的质量分配数组之外,例如params[:controller]也是。

示例:<%= hidden_field_tag :temporary_id, SecureRandom.hex %>。有关创建随机字符串的其他可能性,请查看how-best-to-generate-a-random-string-in-ruby

还要确保您的表单(或在您的表单部分中呈现的第一个元素)具有生成的随机字符串作为iddata-属性,这样您就可以在下一步中访问它而无需使用复杂的选择器。

2. 更新您的 create.js.erb
我假设您format.js在创建操作中传递到create.js.erb. 因此,在那里,您通过搜索提交时传递的临时 id 将整个表单替换为新表单。

例子:$('#<random_id_of_your_form>').replaceWith('<%= j render(partial: 'form', locals: {...}) %>');

确保不要省略帮助j,因为它会编码您呈现的表单以便在 javascript 中保存使用。当您呈现通常的表单时,创建操作会执行其通常的业务,现在还用新的渲染表单替换表单,其中自动调用“更新”操作(路由中通常的轨道“魔术”内容,即是。就像你会呈现另一个通常的编辑表单)。

Javascript

评级表格被替换后,Javascript 不再适用于该部分。

当然不是。您正在将事件绑定到文档加载时的特定元素。之后插入的元素(通过创建/更新)是新添加的,因此没有该事件绑定,因为它们在事件绑定发生时不可用。

由于事件是“冒泡的”,因此您需要将代码绑定到一个容器,该容器在您的 js-modifications 中是持久的。假设您的 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'监视与第二个参数中的选择器匹配的元素上的点击事件,here form.rating_ballot > label

这允许在#rating_questions_container不丢失事件侦听器的情况下动态附加/删除 DOM 节点。

于 2013-11-06T10:18:46.567 回答