このトピックには少なくとも10の質問がありますが、この特定の問題に答える質問はありません。質問の多くは、私が持っていない this のようなRails形式、または thisのようなより複雑なjson構造に関連しています。 または this 。
受け入れられた答えと、これが正確な複製ではない理由に関する編集
@CarlosRoqueからの回答のリンクされた質問は、最初は同じ問題のように見えますが、この特定の問題のRails側のみを解決します。
すべてのコメントを読むと、ネストされた属性 "template_items"を "template_items_attributes"でRENAMEまたはREPLACEするためにtemplate_params
メソッドを変更しようとする試みが複数回表示されます。 Rails accepts_nested_attributes_for
には名前に「_attributes」を追加する必要があるため、これが必要です。そうでない場合は表示できません。
その回答でモンキーパッチコードを調べてwrap_parametersを修正し、ネストされた属性に対して機能するようにすると、接尾辞「_attributesがないため、実際には「template_items」(ネストされたオブジェクト)が見つからないという問題があります。 「。
したがって、これを完全に解決するには、ネストされたオブジェクトを「template_items_attributes」として送信するようにクライアントを変更する必要がありました。 JSクライアントの場合、シリアル化中にオブジェクトを変更するtoJSON()メソッドを実装することでこれを実行できます(例 here )。ただし、JSONをデシリアライズするとき、toJSON()が機能するためにそのオブジェクトのインスタンスを手動で作成する必要があることに注意してください(理由 here の説明)。
私は単純なhas_many/belongs_toを持っています:
モデル:
class Template < ApplicationRecord
belongs_to :account
has_many :template_items
accepts_nested_attributes_for :template_items, allow_destroy: true
end
class TemplateItem < ApplicationRecord
belongs_to :template
validates_presence_of :template
enum item_type: {item: 0, heading: 1}
end
クライアントから送信されたJSONは次のようになります。
{
"id": "55e27eb7-1151-439d-87b7-2eba07f3e1f7",
"account_id": "a61151b8-deed-4efa-8cad-da1b143196c9",
"name": "Test",
"info": "INFO1234",
"title": "TITLE1",
"template_items": [
{
"is_completed": false,
"item_type": "item"
},
{
"is_completed": false,
"item_type": "heading"
}
]
}
各template_itemに:id
および:content
属性がある場合があります(たとえば、作成されてユーザーが編集を開始した後)。
template_params
のtemplates_controller
メソッドは次のようになります。
params.require(:template).permit(
:id, :account_id, :name, :title, :info,
template_items: [:id, :is_completed, :content, :item_type]
)
これがRailsフォームの場合、その行は次のようになります。
params.require(:template).permit(
:id, :account_id, :name, :title, :info,
template_items_attributes: [:id, :is_completed, :content, :item_type]
)
ネストされた子オブジェクトを親テンプレート更新アクションの一部として保存するため。
ネストされたパラメーター名を変更してみました:
def template_params
params.require(:template).permit(:id, :account_id, :name, :title, :info, template_items: [:id, :is_completed, :content, :item_type])
params[:template_items_attributes] = params.delete(:template_items) if params[:template_items]
Rails.logger.info params
end
まだ許可されていないことがわかります:
{
"template" =><ActionController::Parameters {
"id" =>"55e27eb7-1151-439d-87b7-2eba07f3e1f7",
"account_id" =>"a61151b8-deed-4efa-8cad-da1b143196c9",
"name" =>"Test",
"info" =>"INFO1234",
"title" =>"TITLE1",
} permitted:false >,
"template_items_attributes" => [
<ActionController::Parameters {
"is_completed" =>false,
"item_type" =>"item"
} permitted:false >,
<ActionController::Parameters {
"is_completed" =>false,
"item_type" =>"item"
} permitted:false >
]
}
私もマージしようとしました:
template_params.merge! ({template_items_attributes:
params[:template_items]}) if params[:template_items].present?
同じ問題。
.permitを行わずに、それらが許可されてtemplate_paramsに含まれていることを確認するにはどうすればよいですか(つまり、すべてを盲目的に許可したくない)?
コントローラーの更新方法:
def update
Rails.logger.info "*******HERE*******"
Rails.logger.info template_params
@template.template_items = template_params[:template_items_attributes]
if @template.update(template_params)
render json: @template
else
render json: ErrorSerializer.serialize(@template.errors), status: :unprocessable_entity
end
end
[〜#〜] udpate [〜#〜]
クライアントからパラメーター内の「template_items」ではなく「template_items_attributes」からRailsに送信し、次のように推奨されるtemplate_paramsを実行する場合:
def template_params
params.require(:template).permit(:id, :account_id, :name, :title, :info, template_items_attributes: [:id, :is_completed, :content, :item_type])
end
テンプレートの新しい子はまだ作成されません!
これを設定したら、次のように前後にパラメーターを出力します。
def update
Rails.logger.info params
Rails.logger.info "*******HERE*******"
Rails.logger.info template_params
if @template.update(template_params)
render json: @template
else
render json: ErrorSerializer.serialize(@template.errors), status: :unprocessable_entity
end
end
そして、このシナリオのログは次のとおりです。Railsは、埋め込み配列を完全に無視します。 HEREの直前のparamsにallowed:falseと表示され、その後template_paramsに子 "template_items_attributes"が含まれなくなり、permitted:trueとマークされることに注意してください。
I, [2017-10-20T21:52:39.886104 #28142] INFO -- : Processing by Api::TemplatesController#update as JSON
I, [2017-10-20T21:52:39.886254 #28142] INFO -- : Parameters: {"id"=>"55e27eb7-1151-439d-87b7-2eba07f3e1f7", "account_id"=>"a61151b8-deed-4efa-8cad-da1b143196c9", "name"=>"Test", "info"=>"INFO12345", "title"=>"TITLE1", "created_at"=>"2017-10-14T19:30:41.450Z", "updated_at"=>"2017-10-20T17:48:24.909Z", "template_items_attributes"=>[{"is_completed"=>false, "item_type"=>"item"}], "template"=>{"id"=>"55e27eb7-1151-439d-87b7-2eba07f3e1f7", "account_id"=>"a61151b8-deed-4efa-8cad-da1b143196c9", "name"=>"Test", "info"=>"INFO12345", "title"=>"TITLE1", "created_at"=>"2017-10-14T19:30:41.450Z", "updated_at"=>"2017-10-20T17:48:24.909Z"}}
D, [2017-10-20T21:52:39.903011 #28142] DEBUG -- : User Load (7.7ms) SELECT "users".* FROM "users" WHERE "users"."uid" = $1 LIMIT $2 [["uid", "[email protected]"], ["LIMIT", 1]]
D, [2017-10-20T21:52:40.072148 #28142] DEBUG -- : Template Load (1.4ms) SELECT "templates".* FROM "templates" WHERE "templates"."id" = $1 ORDER BY name ASC LIMIT $2 [["id", "55e27eb7-1151-439d-87b7-2eba07f3e1f7"], ["LIMIT", 1]]
I, [2017-10-20T21:52:40.083727 #28142] INFO -- : <ActionController::Parameters {"id"=>"55e27eb7-1151-439d-87b7-2eba07f3e1f7", "account_id"=>"a61151b8-deed-4efa-8cad-da1b143196c9", "name"=>"Test", "info"=>"INFO12345", "title"=>"TITLE1", "created_at"=>"2017-10-14T19:30:41.450Z", "updated_at"=>"2017-10-20T17:48:24.909Z", "template_items_attributes"=>[{"is_completed"=>false, "item_type"=>"item"}], "controller"=>"api/templates", "action"=>"update", "template"=>{"id"=>"55e27eb7-1151-439d-87b7-2eba07f3e1f7", "account_id"=>"a61151b8-deed-4efa-8cad-da1b143196c9", "name"=>"Test", "info"=>"INFO12345", "title"=>"TITLE1", "created_at"=>"2017-10-14T19:30:41.450Z", "updated_at"=>"2017-10-20T17:48:24.909Z"}} permitted: false>
I, [2017-10-20T21:52:40.083870 #28142] INFO -- : *******HERE*******
D, [2017-10-20T21:52:40.084550 #28142] DEBUG -- : Unpermitted parameters: :created_at, :updated_at
I, [2017-10-20T21:52:40.084607 #28142] INFO -- : <ActionController::Parameters {"id"=>"55e27eb7-1151-439d-87b7-2eba07f3e1f7", "account_id"=>"a61151b8-deed-4efa-8cad-da1b143196c9", "name"=>"Test", "title"=>"TITLE1", "info"=>"INFO12345"} permitted: true>
D, [2017-10-20T21:52:40.084923 #28142] DEBUG -- : Unpermitted parameters: :created_at, :updated_at
D, [2017-10-20T21:52:40.085375 #28142] DEBUG -- : (0.2ms) BEGIN
D, [2017-10-20T21:52:40.114015 #28142] DEBUG -- : Account Load (1.2ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" = $1 LIMIT $2 [["id", "a61151b8-deed-4efa-8cad-da1b143196c9"], ["LIMIT", 1]]
D, [2017-10-20T21:52:40.131895 #28142] DEBUG -- : Template Exists (0.8ms) SELECT 1 AS one FROM "templates" WHERE "templates"."name" = $1 AND ("templates"."id" != $2) AND "templates"."account_id" = 'a61151b8-deed-4efa-8cad-da1b143196c9' LIMIT $3 [["name", "Test"], ["id", "55e27eb7-1151-439d-87b7-2eba07f3e1f7"], ["LIMIT", 1]]
D, [2017-10-20T21:52:40.133754 #28142] DEBUG -- : (0.3ms) COMMIT
D, [2017-10-20T21:52:40.137763 #28142] DEBUG -- : CACHE Account Load (0.0ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" = $1 LIMIT $2 [["id", "a61151b8-deed-4efa-8cad-da1b143196c9"], ["LIMIT", 1]]
D, [2017-10-20T21:52:40.138714 #28142] DEBUG -- : (0.2ms) BEGIN
D, [2017-10-20T21:52:40.141293 #28142] DEBUG -- : User Load (1.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 FOR UPDATE [["id", "88de3be9-6d18-4687-ab80-d50f78638ca9"], ["LIMIT", 1]]
D, [2017-10-20T21:52:40.235163 #28142] DEBUG -- : Account Load (0.7ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" = $1 LIMIT $2 [["id", "a61151b8-deed-4efa-8cad-da1b143196c9"], ["LIMIT", 1]]
D, [2017-10-20T21:52:40.240997 #28142] DEBUG -- : SQL (1.4ms) UPDATE "users" SET "tokens" = $1, "updated_at" = $2 WHERE "users"."id" = $3 [["tokens", "{\"ryyymFZ7fpH50rMKArjZ2Q\":{\"token\":\"$2a$10$4jkgRe4LBPxJ8fQUOKCSausUi7DbIUD0bE.7ZRoOuTHrRuX6CaWOe\",\"expiry\":1509293414,\"last_token\":\"$2a$10$cpI.mz81JFjQT0J9acCCl.NdrEatI5l17GtrwrAfwyhyN3xRExcaC\",\"updated_at\":\"2017-10-15T17:10:16.996+02:00\"},\"Y2y0maUT5WYSfH6VZeORag\":{\"token\":\"$2a$10$8KERiIwlc3rX.Mdu.CW6wOMLDbVyB2PFCaBIlw7/LUxC3ITpYTISW\",\"expiry\":1509293475,\"last_token\":\"$2a$10$r6Xw6798T1P7UZlTbEaXoeBCl9oK2fMs72ppAtars8Ai/kaE6nE66\",\"updated_at\":\"2017-10-15T17:11:18.066+02:00\"},\"9Cy48CPVj3WhFkEBPUZQ1Q\":{\"token\":\"$2a$10$Qy4JOD8.jIcPhf93MqFCIelnVaA/ssE31w5DlL8MShDuMROsLSNuS\",\"expiry\":1509293942,\"last_token\":\"$2a$10$e6sxklrHRRD1C15Ix/MqQOfACuCMznmzUjF296cpO1ypWVvJ.JFJK\",\"updated_at\":\"2017-10-15T17:19:05.200+02:00\"},\"O5iufW0Gacqs9sIfJ9705w\":{\"token\":\"$2a$10$EkDf7.y3lY9D36lAwNHBGuct97M6/HGDvnrUsD72c8zCsfVd8y9c2\",\"expiry\":1509482450,\"last_token\":\"$2a$10$S0kHEvKxom2Qgdy0r.q0aeTSlSBFkqU4XZeY91n3RkkYkQykmmGVi\",\"updated_at\":\"2017-10-17T21:40:50.300+02:00\"},\"ETOadoEtoxcz6rR6Ced_dA\":{\"token\":\"$2a$10$8t01bWv/PsVojs3cazuSg..FWa9SZwq1/PUDfuN1S4yBxnMFv2zre\",\"expiry\":1509742360,\"last_token\":\"$2a$10$hveuajISXDOjHLm9EkVzvOd3pwKkqE1rQnIFBoojf0vgMLXV2EvVe\",\"updated_at\":\"2017-10-20T21:52:40.233+02:00\"}}"], ["updated_at", "2017-10-20 19:52:40.236607"], ["id", "88de3be9-6d18-4687-ab80-d50f78638ca9"]]
D, [2017-10-20T21:52:40.243960 #28142] DEBUG -- : (1.3ms) COMMIT
I, [2017-10-20T21:52:40.244504 #28142] INFO -- : Completed 200 OK in 358ms (Views: 1.0ms | ActiveRecord: 37.7ms)
Params.require(:template).permit(...は値を返すメソッドであり、後で変更するためにparamsを呼び出すと、まだ許可されていないパラメーターのみを変更していることを忘れていると思います。行うには、パラメーター操作を実行するときの順序を入れ替えます。
def template_params
params[:template][:template_items_attributes] = params[:template_items_attributes]
params.require(:template).permit(:id, :account_id, :name, :title, :info, template_items_attributes: [:id, :is_completed, :content, :item_type])
end
更新:wrap_parametersが原因で、ラップされたparamsにネストされたパラメーターが含まれていませんでした。これにより問題が修正されます
更新:この回答は別のソリューションを実装します JSON経由でネストされた属性を更新しないRails 4
これはgithubでの長いオープンリクエストです!!クレイジー https://github.com/Rails/rails/pull/19254
問題問題は、まだビルドされていない@template
の関連付けを保存しようとしているupdate
アクションにあります。ハッシュには「id」が入っていないため、更新関数はそれらを無視します。
解決策update
アクションに到達する関連付けハッシュの配列を反復処理し、update
onを呼び出す前に@template
でそれらを構築する@template
。
Sudoコードは次のとおりです(試していないので、貼り付けをコピーしないでください)。
モデル
class Template < ApplicationRecord
belongs_to :account
has_many :template_items
accepts_nested_attributes_for :template_items, allow_destroy: true
end
class TemplateItem < ApplicationRecord
belongs_to :template, optional:true # <------ CHANGE
validates_presence_of :template
enum item_type: {item: 0, heading: 1}
end
強力なパラメーター定義
params.require(:template).permit(
:id, :account_id, :name, :title, :info,
template_items_attributes: [:id, :is_completed, :content, :item_type]
)
更新アクション
def update
template_params.template_items.each do |item_hash| # <------ CHANGE
@template.template_items.build(item_hash)
end
if @template.update(template_params)
render json: @template
else
render json: ErrorSerializer.serialize(@template.errors), status: :unprocessable_entity
end
end
def template_params
template_params = params.require(:template).permit(:id, :account_id, :name,:title, :info, template_items: [:id, :is_completed, :content, :item_type])
template_params[:template_items_attributes] = template_params.delete :template_items
template_params.permit!
end