繁体   English   中英

提交前以Rails表单动态加载模型关联

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM