簡體   English   中英

Rails 4不更新嵌套屬性

[英]Rails 4 NOT updating nested attributes

問題:當我點擊相關features_controller.rb#update操作時,它們是在現有嵌套屬性的基礎上創建的 ,而不是更新嵌套屬性。

可能的原因:我認為問題在於我在Rails的form_for缺乏理解。 我認為細分在我的視圖中,如何呈現持久的嵌套屬性,和/或我如何指定嵌套屬性的id失敗,導致它只是創建一個新的id

feature.rb

class Feature < ActiveRecord::Base
  ...
  has_many :scenarios
  accepts_nested_attributes_for :scenarios,
    allow_destroy: true,
    reject_if: :all_blank
  ...
end

features_controller.rb

def update
  ...
  project = Project.find(params[:project_id])
  @feature = Feature.find(params[:id])

  if @feature.update_attributes(feature_params)
    # checking feature_params looks good...
    # feature_params['scenarios'] => { <correct object hash> }

    redirect_to project
  else
    render :edit
  end
end

...

private
def feature_params
  params.require(:feature).permit(:title, :narrative, :price, :eta, scenarios_attributes[:description, :_destroy])
end

_form.html.haml(簡體)

= form_for [@project, @feature] do |f|
  ...
  - if @feature.new_record? -# if we are creating new feature
    = f.fields_for :scenarios, @feature.scenarios.build do |builder|
      = builder.label :description, "Scenario"
      = builder.text_area :description, rows: "3", autocomplete: "off"

  - else -# if we are editing an existing feature
    = f.fields_for :scenarios do |builder|
      = builder.label :description, "Scenario"
      = builder.text_area :description, rows: "3", autocomplete: "off"

我確定有更好的方法來實現if @feature.new_record? 校驗。 我也使用一些Javascript鈎子來創建動態嵌套屬性表單(我已經遺漏了),受Railscast#196嵌套模型表(修訂版)的影響很大

我會喜歡一個非常好的Rails-y實現處理這些嵌套的表單。

嘗試將:id添加到feature_params方法的:scenario_attributes部分。 您只有描述字段和允許銷毀的能力。

def feature_params
  # added => before nested attributes
  params.require(:feature).permit(:id, :title, :narrative, :price, :eta, scenarios_attributes => [:id, :description, :_destroy])
end

正如@vinodadhikary建議的那樣,您不再需要檢查功能是否是新記錄,因為Rails(特別是使用form_for方法)將為您執行此操作。

更新:

你不需要定義if @feature.new_record? ... else if @feature.new_record? ... else在你的表格中。 使用form_for時,Rails會對它進行處理。 Rails會根據object.persisted?檢查是否要createupdate object.persisted? ,所以,您可以將表單更新為:

= form_for [@project, @feature] do |f|
  ...
  = f.fields_for :scenarios, @feature.scenarios.build do |builder|
    = builder.label :description, "Scenario"
    = builder.text_area :description, rows: "3", autocomplete: "off"

正如@ Philip7899在接受的答案中提到的那樣,允許用戶設置id意味着他們可以 “竊取”屬於另一個用戶的子記錄。

但是 ,Rails accepts_nested_attributes_for實際檢查id並引發:

ActiveRecord::RecordNotFound:
  Couldn't find Answer with ID=5 for Questionnaire with ID=5

基本上在兒童協會中尋找ids(再次,如@glampr所說)。 因此,找不到屬於另一個用戶的子記錄。

最終, 401是響應狀態(與ActiveRecord::RecordNotFound通常的404不同)

遵循我用來測試行為的一些代碼。

let :params do
  {
    id: questionnaire.id,
    questionnaire: {
      participation_id: participation.id,
      answers_attributes: answers_attributes
    }
  }
end

let :evil_params do
  params.tap do |params|
    params[:questionnaire][:answers_attributes]['0']['id'] = another_participant_s_answer.id.to_s
  end
end

it "doesn't mess with other people's answers" do
  old_value = another_participant_s_answer.value

  put :update, evil_params

  expect(another_participant_s_answer.reload.value).to eq(old_value) # pass
  expect(response.status).to eq(401) # pass
end

總之 ,如上所述將id添加到允許的參數中是正確和安全的

迷人的Rails。

暫無
暫無

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

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