具有嵌套属性的Best_In_Place内联编辑

Ray*_*eve 5 ruby-on-rails nested-attributes best-in-place ruby-on-rails-4

我目前正在尝试使用best_in_place gem来在HTML表格中进行内联编辑.我在购物车的展示视图中显示了一个购物车.在购物车的展示视图中,我可以添加lineItems.创建LineItem时,还会使用lineItem_id创建新的可用记录,然后在购物车中显示其lineitem.Cart和LineItem表都来自外部数据库,因此我无法添加列,这就是为什么我不能只为LineItem添加一个可用的布尔属性.

**cart.rb
class Cart << AR::Base
 has many LineItems
end

**line_item.rb
class LineItems <<AR::Base
 belongs_to Cart
 has_one :available 
 accepts_nested_attributes_for :available 
end

**available.rb
class Available<<AR::Base
 belongs_to LineItems
end


**views/cart/show.html.erb
@cart.lineitems.each do |line_items|
    <td><%= line_item.price %></td>
    <td><%=line_item.name %></td>
    <td><%= best_in_place line_item.available.boolean, :boolean, :path => line_items_path, :type =>  type: :checkbox, collection: %w[No Yes] %></td>  
end
Run Code Online (Sandbox Code Playgroud)

我希望能够使用best_in_place编辑html表中的line_item.available.boolean,该表位于购物车展示视图中,但我没有运气..任何帮助都会令人惊叹!=]我知道在阅读之后,使用嵌套属性是不可能的,但是如果我能以某种方式摆脱可用模型并在show table中有一个字段,我可以为line_item编辑以查看lineItem是否可用那也很棒.我对任何想法持开放态度!

Isa*_*esh 5

首先,您的代码中有一些语法问题需要我们解决:

@cart.lineitems.each do |line_item| # changed "line_items" to "line_item"
  <td><%= line_item.price %></td>
  <td><%=line_item.name %></td>
  <td><%= best_in_place line_item.available, :boolean, :path => line_items_path, type: :checkbox, collection: %w[No Yes] %></td>  # changed "line_item.available.boolean" to "line_item.available" and ":type =>  type: :checkbox" to "type: :checkbox"
end
Run Code Online (Sandbox Code Playgroud)

现在,答案是:

正如我在这个Github问题中所解释的那样,您需要将一个param选项和一个url选项(曾经path是v3.0.0中不推荐使用的)传递给best_in_place。

url选项

The default url is the update action of the first argument to best_in_place. Since your code begins with best_in_place line_item.available, this would default to url_for(line_item.available.id). However, you want it to PATCH the update action of the LineItemsController, i.e. url_for(line_item)

The param option

By default, the param option assumes you are PATCH'ing to the AvailablesController, so here are the parameters that Rails conventions require in order to update available.boolean to the value "1":

{"available"=>{"boolean"=>"1"}}
Run Code Online (Sandbox Code Playgroud)

The ID of the Available is in the URL already, so the only extra param you need to pass is the new value for boolean.

In your case, however, you are PATCH'ing to the LineItemsController and the available model accepts nested attributes. This requires two adjustments:

  1. The ID of the LineItem is in the URL already, but the ID of the Available is not. We have two choices here: Either put the ID of the Available into the param option, or make the ID unnecessary by passing update_only: true to accepts_nested_attributes in the model. The update_only approach may not work for you depending on your use case, but I find that it is the simplest approach the vast majority of the time and adds an extra layer of security for free.

  2. The boolean option needs to be nested properly, i.e.:

    line_items[available_attributes][boolean]
    
    Run Code Online (Sandbox Code Playgroud)

    That way, when it gets to the server, the params will be:

    {"line_item"=>{"available_attributes"=>{"id"=>"99","boolean"=>"1"}}}
    # "99" is just an example of line_item.available.id
    
    Run Code Online (Sandbox Code Playgroud)

    Note that you will need to permit these attributes in the controller, i.e.:

    line_item.update(params.require(:line_item).permit(
      available_attributes: [:id, :boolean]))
    # You can remove `:id` if you are using the `update_only` option
    
    Run Code Online (Sandbox Code Playgroud)

Putting it all together, here's your best_in_place method:

best_in_place line_item.available, :boolean, 
  type: :checkbox, 
  url: line_item_path(line_item.id),
  param: "line_item[available_attributes][id]=#{line_item.available.id}&line_item[available_attributes]"
Run Code Online (Sandbox Code Playgroud)

However, if at all possible, use the update_only option.

# line_item.rb
accepts_nested_attributes_for :available, update_only: true
Run Code Online (Sandbox Code Playgroud)

Look how much simpler it becomes now:

best_in_place line_item.available, :boolean, 
  type: :checkbox, 
  url: line_item_path(line_item.id),
  # Note: `url: line_item` might also work.
  # If someone can confirm this in a comment, I can update this answer
  param: "line_item[available_attributes]"
Run Code Online (Sandbox Code Playgroud)