Rails 4.2 强参数和解析 json put/update 上的更改属性
Posted
技术标签:
【中文标题】Rails 4.2 强参数和解析 json put/update 上的更改属性【英文标题】:Rails 4.2 strong params and parsing changed attributes on a json put / update 【发布时间】:2014-12-11 02:56:06 【问题描述】:背景
我有几个模型,每个模型大约有 40 个属性。它们是标准化的,只是我们正在处理的模型必须具有多个属性。除此之外,它是一个非常标准的 rails 4.2 应用程序(从 rails 3.2 升级)。该应用程序既用于提供带有 ajax 调用的动态页面,也用于提供 json,因此它可以被各种 json 客户端使用。
所以调用:http://example.com/products/1.json - 返回 json 并且 http://example.com/products/1 返回经过haml解析的视图。
问题
我正在使用的 javascript 库 (KendoUI) 在更新时返回整条记录,而不仅仅是更新的字段。目前没有办法避免,除非我想根据他们的支持论坛重写 KendoUi Grid。
所以用户可以搜索所有产品,我向她显示产品的所有属性,然后根据她的访问级别,她可以更新某些字段(几个定价点和描述),但是 ajax 请求包含所有属性.因此,我得到 ActiveModel::ForbiddenAttributesError
问题
第 1 部分
我怎样才能正确地(可以说是 rails 方式)过滤掉更新的参数?现在我正在对@product.attributes && params[:product] 进行哈希比较,以确定是否传递了更新/新属性。 .diff 自 Rails 4.0.2 起已弃用
第 2 部分
我的管理员可以更改这些大型模型的几乎所有属性(时间戳、id 和其他一些属性除外)。最好的方法是什么,而不是为 30 个奇怪的属性做 params[:product].require(:base_cost).permit(:vendor_cost, :client_cost) ?如果应用程序正在开发并且属性发生变化,那么维护这些列表很快就会成为一个问题。我想我可以使用某种 CONSTANT - ALLOWED_ATTRIBUTES 或 ADMIN_ATTRIBUTES 和 USER_ATTRIBUTES,并将其传递给许可。但是感觉有点不像Railsy?
【问题讨论】:
【参考方案1】:第 1 部分
即使该功能已被弃用,您仍然可以使用该功能。您尝试做的一些可能在这里有用。
class Hash
def diff h2
self.dup.delete_if |k, v| h2[k] == v .merge(h2.dup.delete_if |k, v| self.has_key?(k) )
end
def only *args
h =
args.each do |a|
h[a] = self[a]
end
h
end
def except *args
h =
(self.keys - args).each do |a|
h[a] = self[a]
end
h
end
end
测试
2.0.0-p247 :001 > h1 = a: 1, b: 2, c: 3 #=> :a=>1, :b=>2, :c=>3
2.0.0-p247 :002 > h2 = a: 3, b: 2, c: 1 #=> :a=>3, :b=>2, :c=>1
2.0.0-p247 :003 > h1.except(:a) #=> :b=>2, :c=>3
2.0.0-p247 :004 > h1.except(:c) #=> :a=>1, :b=>2
2.0.0-p247 :005 > h1.except(:c, :a) #=> :b=>2
2.0.0-p247 :006 > h1.only(:c, :a) #=> :c=>3, :a=>1
要记住的一点是,参数可能不会真正以哈希的形式出现,因此您可能必须调用 .to_hash
第 2 部分
class FooBar < ActiveRecord::Base
#this controls access restriction, assuming you keep this setup:
#delete this part and all fields are update-able (leave it undefined)
#no fields can be updated if UPDATABLE_FIELDS[type].nil? or UPDATABLE_FIELDS[type][0].nil?
UPDATABLE_FIELDS =
admin: [:except, :id, :timestamp],
user: [:only, :name]
end
class ActiveRecord::Base
def fields_for_user_type type
return true unless defined?(UPDATABLE_FIELDS)
return nil if !UPDATABLE_FIELDS[type] || !UPDATABLE_FIELDS[type].first
return UPDATABLE_FIELDS[type].first, UPDATABLE_FIELDS[type][1..-1]
end
end
class ApplicationController < ActionController::Base
def filter_params data, cls
method, restriction = cls.fields_for_user_type(current_user.type)
return data if method === true
return if method.nil?
return data.except(restriction) if method == :except
return data.only(restriction) if method == :only
end
end
class FunController < ApplicationController
def update
record = FooBar.find(params[:id])
record.update(filter_params(params[:data], FooBar))
end
end
您可以很容易地为此添加默认值以及其他一些漂亮的功能,但至少作为开始,这应该为您完成。
请记住,并非所有这些都经过彻底测试,可能存在错误!
【讨论】:
以上是关于Rails 4.2 强参数和解析 json put/update 上的更改属性的主要内容,如果未能解决你的问题,请参考以下文章
AFNetworking 使用 Rails 进行 PUT 和删除
Rails:Webpacker 4.2 在 /app/public/packs/manifest.json heroku 中找不到应用程序
Rails 4.2 - url helper 引发“ArgumentError:错误数量的参数(3 for 1..2)”