2014-10-01 73 views
4

我正在使用ruby 1.9.3和rails 4.1。
我對ruby非常陌生,沒有以前的javascripting知識。使用Rails 4和JQuery添加刪除嵌套窗體中的項目

我有一對簡單的有很多關係,一個有很多關係。

class Service < ActiveRecord::Base 
    has_many :websites, :dependent => :destroy 
    has_many :timetables, :dependent => :destroy 
    has_many :service_places, :dependent => :destroy 
    has_many :places, through: :service_places 
end 

class ServicePlace < ActiveRecord::Base 
    belongs_to :service 
    belongs_to :place 
end 

class Website < ActiveRecord::Base 
    belongs_to :service 
end 

class Place < ActiveRecord::Base 
    has_many :service_places  
    has_many :services, through: :service_places 
end 

class Timetable < ActiveRecord::Base 
    belongs_to :service 
end 

我已創建的服務形式(_form.html.erb)對於每個渲染罰款協會的嵌套形式,所有的CRUD功能的工作。網站的

<%= form_for(@service, :html => {:class => "form-horizontal", :role => "form"}) do |f| %> 

    <%= render 'wcc_style/layouts/error_messages', object: @service %> 

    <!-- I've skipped some of the html for the service details to just rendering the forms... --> 

    <!-- Adds the Service_Places associations --> 
    <%= f.fields_for :service_places do |service_places| %> 
    <%= render "service_place_fields", :f => service_places %> 
    <%end %> 

    <!-- Adds the website associations via a partial --> 
    <%= f.fields_for :websites do |website| %> 
    <%= render "website_fields", :f => website %> 
    <%end %> 
    <%= link_to_add_fields "Add a website", f, :websites, "btn btn-default", "Add a new website" %> 


    <!-- Adds the timetables associations via a partial --> 
    <%=f.fields_for :timetables do |timetable| %> 
    <%= render "timetable_fields", :f => timetable %> 
    <%end %> 

    <%= f.submit 'Save', :class => 'btn btn-primary' %> 
    <%= link_to 'Cancel', services_path, :class => "btn btn-default", :role =>"button" %> 

<% end %> 

例部分(_website_fields.html.erb)

<!-- This partial holds the websites information for main service form --> 
<div class="form-group"> 
    <%= f.label :website, :class=>'col-sm-2 control-label' %> 
    <div class="col-sm-4"> 
    <%= f.text_field :url, :class => "form-control", :placeholder => "Service Provider Website" %> 
    </div> 
</div> 

什麼我想現在要做的是增加功能,以便能夠添加和刪除的項目(如網站,時間表, service_places)在添加\編輯服務記錄時與服務相關。我見過很多與此有關的帖子,但沒有一個使用jquery和rails 4的良好工作解決方案。

在對此做了一些研究之後,我發現了舊的軌道交通196和197.這些都過時了,並且didn在鐵軌4工作。更多的研究表明貶值的命令。我看到有一個更新版本的railscasts,我還沒有看過。我確實閱讀了修訂版的評論,並表明它使用了coffeescript,儘管我無法證實這一點。

我也看到了使用cocoon gem和nested_form_fields的其他潛在解決方案的鏈接。兩者似乎都使用我不熟悉的HAML。我試圖用jQuery來做到這一點,以幫助我更好地理解javascript過程(因爲我需要在完成時支持開發,我們的標準是儘可能使用JQuery)。

我已經設法得到添加類的工作,它在第一次按下時呈現網站標籤和複選框,但隨後的點擊只是在消失之前再次呈現此消息約一秒。這個位置並不是我期望它在頁面頂部的位置,但我相信這是我們自己的與CSS有關的造型寶石。我認爲JavaScript不應該做一個POST,這看起來是因爲它清除了每個按鈕點擊我的其他領域。

我的第一個問題是,如何在不清除服務表單中的其他項的情況下添加新項目?

我的第二個問題是如何獲得刪除功能的工作。我假設刪除必須位於部分表單生成器中(例如每個項目刪除一個)。

我已經在下面包含了應用程序助手和javascript(從各種帖子拼湊在一起)。

application_helper.rb 模塊ApplicationHelper

#def link_to_remove_fields(name, f) 
    # f.hidden_field(:destroy) + link_to_function(name, "remove_fields(this)") 
    #end 

    # remove link doesn't work!!!!!!!!! 
    def link_to_remove_fields(name, f) 
    f.hidden_field(:_destroy) + link_to_function(name, "remove_fields(this)") 
    end 

    # This now sort of works but the field disappears when it is created after about a second. It also appears at the top of the page. 
    def link_to_add_fields(name, f, association, cssClass, title) 
    new_object = f.object.class.reflect_on_association(association).klass.new 
    fields = f.fields_for(association, new_object, :child_index => "new_#{association}") do |builder| 
     render(association.to_s.singularize + "_fields", :f => builder) 
    end 
    link_to name, "#", :onclick => h("add_fields(this, \"#{association}\", \"#{escape_javascript(fields)}\")"), :class => cssClass, :title => title 
    end 

end 

的application.js

function remove_fields(link) { 
    $(link).prev("input[type=hidden]").val("1"); 
    $(link).closest(".fields").hide(); 
} 

function add_fields(link, association, content) { 
    var new_id = new Date().getTime(); 
    var regexp = new RegExp("new_" + association, "g") 
    $(link).parent().before(content.replace(regexp, new_id)); 
} 

services_controller。RB

class ServicesController < ApplicationController 
    # Set the service record before each action 
    before_action :set_service, only: [:show, :edit, :update, :destroy] 

    ################################################################################ 
    # Create 
    ################################################################################ 
    def create 
    @service = Service.new(service_params) 

    respond_to do |format| 
     if @service.save 
     format.html { redirect_to @service, notice: 'Service was successfully created.' } 
     format.json { render action: 'show', status: :created, location: @service } 
     else 
     @service.websites.build 
     @service.timetables.build 
     @service.service_places.build 
     format.html { render action: 'new' } 
     format.json { render json: @service.errors, status: :unprocessable_entity } 
     end 
    end 

    end 


    ################################################################################ 
    # Delete 
    ################################################################################ 
    def destroy 
    @service.destroy 

    respond_to do |format| 
     format.html { redirect_to services_url , notice: 'Service was successfully deleted.' } 
     format.json { head :no_content } 
    end 
    end 


    ################################################################################ 
    # Edit 
    ################################################################################ 
    def edit 
    @service.websites.build 
    @service.timetables.build 
    @service.service_places.build 
    end 


    ################################################################################ 
    # Index 
    ################################################################################ 
    def index 
    @services = Service.order(:service_number).page params[:page] 
    end 


    ################################################################################ 
    # New 
    ################################################################################ 
    def new 
    @service = Service.new 
    @service.websites.build 
    @service.timetables.build 
    @service.service_places.build 
    end 


    ################################################################################ 
    # Search 
    ################################################################################ 
    def search 
    @search_term = params[:search_term] 
    if @search_term && @search_term.strip.empty? 
     redirect_to root_path 
    else 
     @services = Service.search(@search_term).order(:service_number).page params[:page] 
    end 
    end 


    ################################################################################ 
    # Show 
    ################################################################################ 
    def show 
    end 


    ################################################################################ 
    # Update 
    ################################################################################ 
    def update 
    respond_to do |format| 
     if @service.update(service_params) 
     format.html { redirect_to @service, notice: 'Service was successfully updated.' } 
     format.json { head :no_content } 
     else 
     format.html { render action: 'edit' } 
     format.json { render json: @service.errors, status: :unprocessable_entity } 
     end 
    end 
    end 


    ################################################################################ 
    # Private methods 
    ################################################################################ 
    private 

    # Use callbacks to share common setup or constraints between actions. 
    def set_service 
     @service = Service.find(params[:id]) 
    end 

    # Never trust parameters from the scary internet, only allow the white list through. 
    def service_params 
     params.require(:service).permit(:service_number, :operator, :monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday, :bank_holiday, :search_term, websites_attributes: [:id, :service_id, :url, :_destroy], timetables_attributes: [:id, :service_id, :url, :_destroy], service_places_attributes: [:id, :service_id, :position, :place_id, :_destroy], places_attributes: [:id, :place_name, :active, :_destroy]) 
    end 

end 

走遍了互聯網,我似乎無法找到如何得到這個使用jQuery和標準紅寶石\軌工作的任何鏈接。有沒有人知道任何有助於實現這一目標的鏈接或資源?

我不反對使用寶石像繭或nested_form_fields,假設我可以將HAML轉換爲ERB和咖啡腳本爲JavaScript。作爲ruby \ rails和JavaScript的新手,有建設者在做東西是很好的,但當它出錯時,我不知道如何解決它。

我感謝任何幫助或指導。

回答

4

沒有得到任何快速我跟進了一位同事的建議使用繭。我按照這裏的步驟:cocoon gem on github並設法讓它工作。我知道這並不能回答我的實際問題,但它確實爲我提供了一種做我想做的事情的方法。我注意到其他人的步驟,以防他們發現它有用。我也將HAML轉換爲普通紅寶石,因爲我對此更加舒服。

1)添加下面一行到你的Gemfile:

gem "cocoon" 

2)下方添加行到您的應用程序/資產/ Java腳本/ application.js中文件

//= require cocoon 

3)修改了我的服務表格(_form.html.erb)如下

<%= form_for(@service, :html => {:class => "form-horizontal", :role => "form"}) do |f| %> 

    <%= render 'wcc_style/layouts/error_messages', object: @service %> 

    <div class="form-group"> 
    <%= f.label :service_number, :class=>'col-sm-2 control-label' %> 
    <div class="col-sm-3"> 
     <%= f.text_field :service_number, :class => "form-control", :placeholder => "Service Number" %> 
    </div> 
    </div> 

    <div class="form-group"> 
    <%= f.label :operator, :class=>'col-sm-2 control-label' %> 
    <div class="col-sm-4"> 
     <%= f.text_field :operator, :class => "form-control", :placeholder => "Operator" %> 
    </div> 
    </div> 

    <div class="form-group"> 
    <%= f.label :monday, :class=>'col-sm-2 control-label' %> 
    <div class="col-sm-2"> 
     <%= f.check_box :monday, :class => "form-control, pull-left", :placeholder => "Monday" %> 
    </div> 
    </div> 

    <div class="form-group"> 
    <%= f.label :tuesday, :class=>'col-sm-2 control-label' %> 
    <div class="col-sm-2"> 
     <%= f.check_box :tuesday, :class => "form-control, pull-left", :placeholder => "Tuesday" %> 
    </div> 
    </div> 

    <div class="form-group"> 
    <%= f.label :wednesday, :class=>'col-sm-2 control-label' %> 
    <div class="col-sm-2"> 
     <%= f.check_box :wednesday, :class => "form-control, pull-left", :placeholder => "Wednesday" %> 
    </div> 
    </div> 

    <div class="form-group"> 
    <%= f.label :thursday, :class=>'col-sm-2 control-label' %> 
    <div class="col-sm-2"> 
     <%= f.check_box :thursday, :class => "form-control, pull-left", :placeholder => "thursday" %> 
    </div> 
    </div> 

    <div class="form-group"> 
    <%= f.label :friday, :class=>'col-sm-2 control-label' %> 
    <div class="col-sm-2"> 
     <%= f.check_box :friday, :class => "form-control, pull-left", :placeholder => "Friday" %> 
    </div> 
    </div> 

    <div class="form-group"> 
    <%= f.label :saturday, :class=>'col-sm-2 control-label' %> 
    <div class="col-sm-2"> 
     <%= f.check_box :saturday, :class => "form-control, pull-left", :placeholder => "Saturday" %> 
    </div> 
    </div> 

    <div class="form-group"> 
    <%= f.label :sunday, :class=>'col-sm-2 control-label' %> 
    <div class="col-sm-2"> 
     <%= f.check_box :sunday, :class => "form-control, pull-left", :placeholder => "Sunday" %> 
    </div> 
    </div> 

    <div class="form-group"> 
    <%= f.label :bank_holiday, :class=>'col-sm-2 control-label' %> 
    <div class="col-sm-2"> 
     <%= f.check_box :bank_holiday, :class => "form-control, pull-left", :placeholder => "Bank Holiday" %> 
    </div> 
    </div> 

<h3>Stops</h3> 

    <!-- Adds the Service_Places associations via partial (sort applied in model) --> 
    <div> 
    <%= f.fields_for :service_places do |service_places| %> 
     <%= render 'service_place_fields', :f => service_places %> 
    <% end %> 
    <div class="links"> 
     <%= link_to_add_association 'add service places', f, :service_places, :class => "btn btn-default" %> 
    </div> 
    </div> 


<h3>Websites</h3> 

    <!-- Adds the website associations via a partial --> 
    <div> 
    <%= f.fields_for :websites do |website| %> 
     <%= render "website_fields", :f => website %> 
    <%end %> 
    <div class="links"> 
     <%= link_to_add_association 'add websites', f, :websites, :class => "btn btn-default" %> 
    </div> 
    </div> 

<h3>Timetables</h3> 

    <!-- Adds the timetables associations via a partial --> 
    <div> 
    <%=f.fields_for :timetables do |timetable| %> 
     <%= render "timetable_fields", :f => timetable %> 
    <%end %> 
    <div class="links"> 
     <%= link_to_add_association 'add timetables', f, :timetables, :class => "btn btn-default" %> 
    </div> 
    </div> 

    <br> 

    <%= f.submit 'Save', :class => 'btn btn-primary' %> 
    <%= link_to 'Cancel', services_path, :class => "btn btn-default", :role =>"button" %> 

<% end %> 

4)修改了部分內容,如下所示。它需要class =「嵌套字段」,否則它將無法工作。

<div class="nested-fields"> 

    <%= f.label :website, :class=>'col-sm-2 control-label' %> 

    <div class="col-sm-4"> 
    <%= f.text_field :url, :class => "form-control", :placeholder => "Service Provider Website" %> 
    </div> 

    <div> 
    <%= link_to_remove_association "remove website", f, :class => "btn btn-default" %> 
    </div> 

</div> 

我沒有包括我所有的部分,但他們遵循相同的格式。