簡體   English   中英

Rails:如何在一個視圖中將項目逐步添加到排序列表中

[英]Rails: How can I incrementally add items to a sorted list in one view

我正在嘗試為音樂家創建一個清單應用程序。 用戶可以上載歌曲曲目,並從這些歌曲列表中選擇歌曲,以填充特定表演的設置列表。

參見圖片: setlist_screenshot 單擊左側歌曲上的箭頭圖標,應將歌曲添加到右側的可排序列表中。

有問題的模型:

class Setlist < ActiveRecord::Base
  belongs_to :organization
  # join between Set Lists & Arrangements(songs)
  has_many :items, -> { order(position: :asc) }
  has_many :arrangements, through: :items
end

-

class Item < ActiveRecord::Base
  # join between Set Lists & Arrangements(songs)
  belongs_to :arrangement
  belongs_to :setlist
  acts_as_list scope: :setlist
end

-

class Arrangement < ActiveRecord::Base
  belongs_to :song
  belongs_to :organization
  has_many :attachments     
  # join between Set Lists & Arrangements(songs)
  has_many :items
  has_many :setlists, through: :items
end

基本上,一個清單有很多安排(通過歌曲)到項目(聯接表),而且安排(歌曲)當然可以在許多清單上。

我在視圖中用於添加歌曲的按鈕的代碼是:

<%= link_to(organization_setlists_path(:arrangement_id => song.arrangements.first.id, setlist_id: @new_set.id, remote: true), method: "post", class: "secondary-content" )

這是對setlists控制器的create動作的發布請求(包括針對歌曲的編曲ID和Setlist.new的歌曲的參數,在新動作中進行),如下所示:

class SetlistsController < ApplicationController
before_action :authenticate_user!

def new
    if @new_set.nil?
        @new_set = Setlist.create
        @new_item = Item.new 
    end
end

def create
    @arrangement = Arrangement.find(params[:arrangement_id])
    @new_item = Item.new 
    @new_item.setlist_id = Setlist.find(params[:setlist_id])
    @new_item.arrangement_id = @arrangement.id
    if @new_item.save
        flash[:message] = "Song Sucessfully Added!"
    else
        flash[:message] = "Something Went Wrong"
    end
end  

理想情況下,在每次單擊添加/箭頭按鈕之后,我希望為相同的列表創建(遠程)新項,直到用戶完成創建該列表為止。 為了顯示在右側,我有:

<% if @new_set && @new_set.items.count >=1 %>
    <ul>
    <% @new_set.items.each do |item| %>
        <li class="center-align"><%= item.arrangement.title %></li>
    <% end %>
    </ul>
<% else %>
    <p class="center-align">Add Songs From The List On The Left</p>
<% end %>

最終,用戶應該能夠完成該操作,並根據需要繼續創建另一個設置列表。

除了我在這里沒有做的事情之外,我真的不知道該怎么做。 問題是:

首先,創建動作實際上是在創建一個項目,並為新項目分配外鍵用於安排,而不是出於某些原因而不是設置列表,即使從鏈接名稱正確傳遞了設置列表ID也是如此。

另外,每次刷新頁面時,我在新操作中所擁有的內容都會生成一個新的設置列表,因此添加的每個項目都將進入一個設置列表,然后生成一個空白的設置列表,因此右側不會出現任何內容。

最后,這看起來似乎一團糟。 任何人都有更好的設計策略來實現這一目標? 任何幫助將不勝感激!!!

這里的主要問題是您的控制器違反了約定。

當用戶POST到/setlists時,您的SetlistController應該創建一個Setlist

如果要創建新的子記錄,則可以發布到/setlists/:setlist_id/items 這將由ItemsController處理。

# routes.rb
resources :setlists, shallow: true do
  resources :items
end

class ItemsController < ApplicationController

  respond_to :html
  before_action :find_setlist!, only: [:create, :index]

  def create
    @item = @setlist.items.build(item_params)
    @item.save
    respond_with @item
  end

  # ...

  private
    def find_setlist!
      @setlist = Setlist.includes(:items).find!(params[:setlist_id])
    end

    def items_params
       params.require(:item)
             .permit(
                :arrangement_id
             )
    end
end

<% @arrangements.each do |a| %>
  <%= button_to 'Add to set', setlist_items_path(@setlist), 
      arrangement_id: a.id, remote: true 
  %>
<% end %>

一種替代方法是使用accepts_nested_attibutes_for :items來使Setlist也接受項目的參數。

此處的主要區別在於,當將其他項目添加到現有清單時,將使用以下示例:

PATCH /setlist/:id
params: {
  item_attributes: [
    {
      arrangement_id: 2
    },
    {
      arrangement_id: 3
    }
  ]
} 

真正的好處是用戶可以執行多個操作(例如添加/刪除),而您只需要將單個setlist推送到數據庫以更新狀態,而不是對每個子記錄使用多個POST / DELETE調用。

class Setlist < ActiveRecord::Base
  belongs_to :organization
  # join between Set Lists & Arrangements(songs)
  has_many :items, -> { order(position: :asc) }
  has_many :arrangements, through: :items
  accepts_nested_attributes_for :items, allow_destroy: true
end

class SetlistsController < ApplicationController

  respond_to :html
  before_action :set_setlist, only: [:show, :edit, :update, :destroy]

  def new
    @setlist = Setlist.new
    @setlist.items.build 
  end

  def create
    @setlist = Setlist.new(setlist_params)
    @setlist.save
    respond_with @setlist
  end

  def update
    @setlist.update(setlist_params)
    @setlist.items.build
    respond_with @setlist
  end

  # ...

  private
    def set_setlist
      @setlist = Setlist.includes(:items).find(params[:id])
    end

    def setlist_params
      params.require(:setlist)
            .permit(
              :foo, :bar # attributes for the list
              items_attributes: [ :position, :arrangement_id, :_destroy ]
            )
    end
end

支持此操作的基本表單設置如下所示:

<%= form_for(@setlist) do |f| %>
  <%= fields_for :items do |item| %>
    <%= item.number_field :postition %>
    <%= item.collection_select(:arrangement_id, @setlist.organization.arrangements, :id, :name) %>
    <%= item.checkbox :_destroy, label: 'Delete?' %>
  <% end %>
<% end %>

當然,這只是一個普通的舊式同步HTML表單-添加AJAX功能和拖放重新排序等有點超出范圍。

請注意,這些解決方案不是排他性的。 您可以輕松地在應用程序中同時擁有兩個選項(嵌套屬性和指定的控制器),這取決於您的要求是否既需要單獨處理子記錄,又或者希望將其作為API的一部分提供。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM