Rails 4.2 strong parameters and parsing changed attributes in json put / update

Background

I have several models with approximately 40 attributes. They are normalized, simply that the models we are dealing with must have several attributes. In addition, this is a fairly standard application for rails 4.2 (update from rails 3.2). The application is used both to serve dynamic pages sprinkled with ajax calls, and for json, so they can be used by various json clients.

So, the call: http://example.com/products/1.json - returns json and http://example.com/products/1 returns haml-parsed view.

Problem

The JavaScript library I'm using (KendoUI) returns the entire record when updated, not just the updated fields. There is currently no way to avoid it if I don't want to rewrite the KendoUi Grid according to their support forum.

Thus, the user can search for all products, and I show her all the attributes of the product, and then, based on her access level, she can update certain fields (several points and price descriptions), however the ajax request contains ALL attributes, Thus, I I get ActiveModel :: ForbiddenAttributesError

Question

Part 1

How can I correctly (rails, so to speak) filter out the parameters that have been updated? I am currently doing a hash comparison @ product.attributes && & & params [: product] to find out if there are any updated / new attributes .. diff is deprecated from Rails 4.0.2

Part 2

My administrators are allowed to change almost all the attributes on these large models (except for timestamps, id and some others). What is the best way to do this and not do params [: product] .require (: base_cost) .permit (: vendor_cost ,: client_cost) for 30 odd attributes? It quickly becomes a problem to maintain these lists if the application is under development and attribute changes. I think I could use some CONSTANT - ALLOWED_ATTRIBUTES or ADMIN_ATTRIBUTES and USER_ATTRIBUTES, and pass this to allow. But something like un-Railsy?

+5
source share
1 answer

Part 1

Even if the function is deprecated, you can still use this function. Using what you are trying to do a few may be useful here.

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 

Test

 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} 

One thing to keep in mind is apparently params that cannot be present as a hash, so you might need to call .to_hash

Part 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 

You could add some other useful features quite easily by default to this, but at least in the beginning, this should do it for you.

Please keep in mind that not all of this has been carefully checked, there may be errors!

+1
source

Source: https://habr.com/ru/post/1204773/


All Articles