[英]Load model association dynamically in Rails form before submit
因此,我不確定如何實現此目標,或者不確定是否有可能,並且很難尋找類似的示例/答案。 但是,有沒有一種方法可以在提交表單之前在表單中動態加載模型關聯,就像不知道實例變量會提前一樣?
我的模型如下:
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
表單中,我具有選擇框,以選擇一個屬性來創建新訂單的關聯(使用Select2插件):
<%= 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
屬性已經與之關聯的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
是合適的,因為我知道我沒有告訴rails正確的位置。
那有可能嗎?如果可以,我將如何實現呢?
(如果有人想知道表單語法,我會使用bootstrap表單gem。我也為其他表單加載了cocoon,因此,如果有使用方法,我就不會反對。)
更新工作代碼,對無關的條件進行了一些修改。
$("#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.')
}
});
您需要確保它與您的基礎路線和內容相匹配,並可能處理沒有所有者的情況,以便隱藏所有者div。 如果您想做更復雜的事情,可以用.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);
}
});
}
更新:
您可以改用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);
}
});
希望這可以幫助
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.