在Rails 4.1.6应用程序中:
简短说明:_destroy属性设置为true或1时,不能删除has_many中的关联。
详细说明: 按照https://github.com/nathanvda/cocoon/wiki/A-guide-to-doing-nested-model-forms关于设置has_many通过关系的描述,我最终得到了这段代码:
deck.rb:
class Deck < ActiveRecord::Base
belongs_to :beacon_owner
# Beacon relationship.
has_many :deck_pointers, dependent: :destroy
has_many :beacons, through: :deck_pointers
accepts_nested_attributes_for :deck_pointers, allow_destroy: true
# Card relationship.
has_many :card_pointers, dependent: :destroy
has_many :cards, through: :card_pointers
accepts_nested_attributes_for :cards
accepts_nested_attributes_for :card_pointers, allow_destroy: true
validates :name, presence: true, uniqueness: true
end
card.rb:
class Card < ActiveRecord::Base
belongs_to :beacon_owner
belongs_to :template
# Deck relationship.
has_many :card_pointers, dependent: :destroy
has_many :decks, through: :card_pointers
...
end
card_pointer.rb:
class CardPointer < ActiveRecord::Base
belongs_to :card
belongs_to :deck
accepts_nested_attributes_for :card, reject_if: :all_blank
end
甲板和信标之间有类似的has_many关系:
beacon.rb:
class Beacon < ActiveRecord::Base
belongs_to :beacon_owner
has_many :deck_pointers, dependent: :destroy
has_many :decks, through: :deck_pointers
accepts_nested_attributes_for :deck_pointers, allow_destroy: true
...
end
deck_pointer.rb:
class DeckPointer < ActiveRecord::Base
belongs_to :beacon
belongs_to :deck
accepts_nested_attributes_for :beacon, reject_if: :all_blank
end
在decks_controller的RSpec测试中,POST和PUT似乎正确更新 - 但是当我尝试删除关联时PUT失败。阅读http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html,我知道使用_destroy属性,但它不起作用。
我的decks_controller中的强大参数 - deck_params
- 可能有误,但我不确定可能需要更改的内容:
class API::V1::DecksController < API::BaseController
before_filter :authenticate_user_from_token!, except: [:show]
before_action :set_deck, only: [:show, :update, :destroy]
...
def create
@deck = Deck.new(deck_params)
@deck.beacon_owner_id = current_beacon_owner.id
@deck.save
respond_with(@deck)
end
def update
@deck.update(deck_params)
respond_with(@deck)
end
...
private
def set_deck
@deck = Deck.find(params[:id])
end
def deck_params
params.require(:deck).permit(:name,
deck_pointers_attributes: [:id, :beacon_id, :deck_id, :_destroy],
card_pointers_attributes: [:id, :card_id, :deck_id, :_destroy])
# {deck_pointers_attributes: [:id, :beacon_id, :deck_id, :_destroy]},
# {card_pointers_attributes: [:id, :card_id, :deck_id, :_destroy]})
end
end
我的测试是这样写的:
it "updates the deck with fewer cards and beacons, deleting card/deck pointers" do
deck = FactoryGirl.create :deck, name: 'Deck 1', beacon_owner_id: current_beacon_owner.id
beacon1 = FactoryGirl.create :beacon, name: 'Beacon 1', uuid: 'abcd', beacon_owner_id: current_beacon_owner.id
beacon2 = FactoryGirl.create :beacon, name: 'Beacon 2', uuid: 'efgh', beacon_owner_id: current_beacon_owner.id
card1 = FactoryGirl.create :card, title: 'Card 1', beacon_owner_id: current_beacon_owner.id
card2 = FactoryGirl.create :card, title: 'Card 2', beacon_owner_id: current_beacon_owner.id
FactoryGirl.create :deck_pointer, deck_id: deck.id, beacon_id: beacon1.id
FactoryGirl.create :deck_pointer, deck_id: deck.id, beacon_id: beacon2.id
FactoryGirl.create :card_pointer, deck_id: deck.id, card_id: card1.id
FactoryGirl.create :card_pointer, deck_id: deck.id, card_id: card2.id
assert Deck.find_by_id(deck.id).cards.count == 2
assert Deck.find_by_id(deck.id).beacons.count == 2
assert CardPointer.count == 2
assert DeckPointer.count == 2
# TODO - why doesn't this change?
puts '-----------------------------------------'
puts "card pointer count: #{CardPointer.count}"
puts "deck pointer count: #{DeckPointer.count}"
puts "deck.cards.count: #{Deck.find_by_id(deck.id).cards.count}"
puts "deck.beacons.count: #{Deck.find_by_id(deck.id).beacons.count}"
puts '-----------------------------------------'
put :update, format: :json, id: deck.id, deck: {
name: "Updated Deck",
card_pointers_attributes: [
{ card_id: card1.id, _destroy: true },
],
deck_pointers_attributes: [
{ beacon_id: beacon1.id, _destroy: true },
{ beacon_id: beacon2.id, _destroy: true }
]
}
puts '-----------------------------------------'
puts "card pointer count: #{CardPointer.count}"
puts "deck pointer count: #{DeckPointer.count}"
puts "deck.cards.count: #{Deck.find_by_id(deck.id).cards.count}"
puts "deck.beacons.count: #{Deck.find_by_id(deck.id).beacons.count}"
puts '-----------------------------------------'
assert Deck.find_by_id(deck.id).cards.count == 1
assert Deck.find_by_id(deck.id).beacons.count == 0
assert CardPointer.count == 1
assert DeckPointer.count == 0
end
我是否在概念上误解了什么?我认为我有allow_destroy和强参数正确...但也许不是,因为这是我能想到的唯一不正确的东西。
答案 0 :(得分:0)
你可以直接删除父母,以便孩子也被删除。你可以直接删除孩子......比如
@user=User.first
//get any random client
client=Client.find 20
//delete child directly
@user.clients.delete(client)
此外......您需要检查父/子是否存在,因为测试数据库在每次测试完成后都会重置。