2017-08-08 77 views
0

所以我不確定如何實現這一點,或者如果它甚至可能並且難以搜索類似的示例/答案。但是有沒有辦法在你提交它之前動態加載模型關聯,如之前,就像不知道實例變量會提前?在提交之前動態地在Rails表單中加載模型關聯

我的產品型號如下:

Property 
    has_many :owners, inverse_of: :property 
    has_many :orders 

Owners 
    belongs_to :property 

Orders 
    belongs_to :property 
    has_many :owners, through: :property 

在我orders.new形式我有選擇框,選擇屬性,以創建新秩序的關聯(通過選擇二插件):

<%= bootstrap_form_for(@orders, ...) do |f| %> 
    ... 
    <%= f.select :property_id, options_from_collection_for_select(Property.all, "id", "full_address"), 
      { label: "Property:", include_blank: true }, { id: "orderPropSelect", data: { placeholder: "Select a Property"} } %> 
    ... 
<% end %> 

所以當有人選擇property作爲新訂單時,有沒有什麼方法可以在表單提交之前加載屬性已經關聯的owners?即使只是能夠看到什麼業主已經在那裏沒關係(能夠編輯它們會更好,但我認識到這可能更復雜)

下面的代碼當然不工作,但尋找沿着行:

<%= f.static_control label: "Property Owners" do %> 
    <% :property_id.owners.each do |owner| %> 
    <%= owner.name %> 
    <% end %> 
<% end %> 

我試過的fields_for的變化,但我不知道如何告訴嵌套字段是基於什麼關選擇在上述select(當然加載不同的業主基於什麼property我得到的錯誤是undefined method owners for nil:NilClass這是適當的,因爲我知道我不告訴鐵路在哪裏看正確。

所以這是可能的,如果是這樣,我將如何實現這一目標?

(我用的自舉形式寶石櫃面你想知道關於形式的語法。我也有裝繭其他形式的所以如果有使用該那麼我不反對的方式。)

更新工作代碼,針對外部條件稍作修改。

$("#orderPropSelect").off().on('change', function() { 
    var id = $(this).val(); 
    console.log(id); 
    if (id !== '') { 
     $.ajax({ 
      url: '/properties/' + id + '/owners', 
      dataType: "json", 
      success: function (data) { 
       owners_html = ''; 
       $.each(data['owners'], function() { 
        owners_html += '<p>' + this + '</p>'; 
       }); 
       if (owners_html === '') { 
        $("#propOwnersShow").html('<p>No owner added yet.</p>'); 
       } else { 
        $("#propOwnersShow").html($(owners_html)); 
       } 
      }, 
      error: function (XMLHttpRequest, textStatus, errorThrown) { 
       console.log(errorThrown); 
      } 
     }); 
    } else { 
     $('#propOwnersShow').html('Please select a Property below to view its associated owners.') 
    } 

}); 
+0

是的,你會使用Ajax和JavaScript做的正是這一點。你會給form_field一個ID,然後當用戶觸發該元素上的事件時,使用jquery觸發對服務器的ajax調用。 – bkunzi01

+0

任何機會,你可以寫一個答案與例如如何做到這一點?如果我能得到它的工作,我會接受它,預先感謝! –

+0

也許有人可以爲你做一個完整的答案,但我超時,所以我會發佈一個答案,讓你走上正軌。 – bkunzi01

回答

1

你需要確保它的根本途徑&的東西相匹配,並可能處理那裏並沒有業主的情況下,使隱藏業主股利。如果你想要做更復雜的東西,你可以代替.pluck建立與ID的一個更好的數組/哈希,然後可以也用它來構建你可以交互元素(例如,從列表中刪除它們)

# your property controller 

before_action :allowed, only [:owners] 

def owners 
    owners = Property.find(params[:id]).owners.pluck(:name) 
    respond_to |format| 
    format.json { render json: { owners: owners, success: true } } 
    end 
end 

def allowed 
    # logic to define if this user is allowed to request this data, if you have devise, it could be 
    user_signed_in? && request.xhr? 
end 

# your routes.rb 

get "properties/:id/owners", to: "properties#owners", as: "property_owners" 

# or if you have resources 
resources :properties do 
    member do 
    get :owners 
    end 
end 

# js file 

$("#property_id").off().on('change', function() { 
    var id = $(this).val(); 
    $.ajax({ 
    url: '/properties/'+id+'/owners', 
    dataType: "json", 
    success: function(data) { 
     owners_html = ''; 
     $.each(data['owners'], function() { 
     owners_html += '<p>'+this+'</p>'; 
     }); 
     $("selector_where_you_want_to_show_owners").html($(owners_html)); 
    }, 
    error: function(XMLHttpRequest, textStatus, errorThrown) { 
     console.log(errorThrown); 
    } 
    }); 
} 

UPDATE:

您可以防止沒有業主的問題,通過使用find_by代替,並確保您始終返回[],這樣簡化了對正面的邏輯。

# on your controller instead use: 

def owners 
    # .find_by will return "nil" if no properties are found, which 
    # then we can leverage with .try. .try will "try" calling those 
    # chained methods without raising an error. It usually returns 
    # "nil" if the parent is "nil" but .try with .pluck though will 
    # always return an [] no matter what the ancestors returned. 

    owners = Property.find_by(id: params[:id]).try(:owners).try(:pluck, :name] 

    # actually looking at your relationships it seems you could instead 
    # .where, since that will return an empty array, like so: 

    # owners = Owner.where(property_id: params[:id]).pluck(:name) 

    # this only does one database query where the other one does 2 

    # here we're simply making sure we add something to the array so 
    # that then on the front-end you can always deal with an array 
    # without worrying with the "no properties found". .blank? will 
    # return "true" if the value is nil, empty string, empty hash or 
    # empty array which works fine for this. So if there's no value in 
    # the array we add the "no owners" string. 

    owners << 'No owner added yet.' if owners.blank? 

    respond_to |format| 
    format.json { render json: { owners: owners, success: true } } 
    end 
end 

# And then since you'll always be returning an array you no longer 
# have to worry about an empty array and your ajax function will 
# look like this: 

$.ajax({ 
    url: '/properties/' + id + '/owners', 
    dataType: "json", 
    success: function (data) { 
    owners_html = ''; 
    $.each(data['owners'], function() { 
     owners_html += '<p>' + this + '</p>'; 
    }); 
    $("#propOwnersShow").html($(owners_html)); 
    }, 
    error: function (XMLHttpRequest, textStatus, errorThrown) { 
    console.log(errorThrown); 
    } 
}); 

希望這有助於

+0

非常感謝您的回覆!我很感激你花時間寫出所有這些。我會深入研究它,看看我能否實現它! –

+1

不客氣。 –

+0

這工作得很好!非常感謝你!我遇到的唯一問題是處理一個罕見的情況,在這種情況下,'property'還沒有添加'所有者',本質上這個關聯返回'nil'。任何想法如何做到這一點?我剛剛開始使用rails的'JSON'功能,所以我仍在研究這種性質的事情。 –