2013-11-04 48 views
3

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

我跟着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.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 

很显然,我只想更新刚提交表单,而不是其他的。 有关如何使用Javascript在create.js.erb和update.js.erb中使用正确方法重新加载表单的任何想法?

非常感谢!编辑~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (参见上面的编辑)

我就做了你的建议,我加入了随机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 ~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 更新操作提交所有表单的事实已被更正。

回答

2

如果我给你的权利... ...

1.作为一个隐藏字段中添加生成的ID到表单
这个ID并不真的要对模型中的一个虚拟属性,但可以。另一种选择是将它放在质量分配数组之外,如e。g 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: {...}) %>');

确保不遗漏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')是页面上的“老大难”的容器,可捕捉第二个参数选择匹配,这里form.rating_ballot > label元素的事件
  • .on('click', 'form.rating_ballot > label'手表click事件。

这允许动态地附加/移除的内部#rating_questions_container DOM节点,而不会丢失事件侦听器。

+0

您好,感谢您的及时答复,我想我的问题不是很清楚,它分为两部分。如果我理解正确,随机ID是为了帮助定义我希望更新的特定表单?这肯定会有帮助,因为我有五种类似的形式。在使用Ajax深入挖掘之后,当它重新载入表单时,它不使用助手方法'rating_ballot',它定义了'rating_questions/1/ratings#create'或'rating_questions/1/ratings/1# update'。我会尝试你的解决方案,看看它是否解决了我的一半问题:) –

+0

是的,这是随机ID的意图。我看到了你的帮手,而且应该可以工作,因为你传递了一个包含两个对象的数组来构建路径。你只需要将你的表单放入一个可以处理'create'和'update'的部分,现在应该是这样。 – pduersteler

+0

所以我遵循你的建议,但我遇到了更多的问题。 1)当我提交一个评级(无论是创建还是更新)时,它会为它们重新加载部分。 2)部分重载后,Coffescript文件中的jQuery不再使用。在我原来的帖子中查看我的编辑。 –