2013-11-04 110 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不再使用。在我原來的帖子中查看我的編輯。 –