Last active
March 26, 2018 15:11
-
-
Save vmakoed/7eadd4eb4c81e6b99b145f3f0c50eebe to your computer and use it in GitHub Desktop.
Strong Parameters Generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#TODO: delete after protected attributes migration to strong params is complete | |
module StrongParams | |
module Tools | |
# use #model_params method from this module to get a nice hash of params ready to be | |
# injected into a params filter of a Rails controller. | |
# Works with nested_attributes. Takes reflections into account. | |
module Generator | |
module_function | |
# | |
# Example: | |
# | |
# model_params(User) | |
# => [ :email, :password, address: [ :street, :zipcode ] ] | |
# | |
def model_params(model) | |
decorated_params(model_attributes(model) + nested_params(model)) | |
end | |
def decorated_params(params) | |
params.map(&method(:decorate_param)) | |
end | |
def decorate_param(param) | |
return { param => [] } if is_array_param?(param) | |
return { param.key => decorated_params(param.value) } if is_nested_param?(param) | |
param | |
end | |
def is_array_param?(param) | |
param.to_s.end_with?('_ids') | |
end | |
def is_nested_param?(param) | |
param.is_a?(Array) && param.present? | |
end | |
def nested_params(model) | |
model.nested_attributes_options.keys.reduce([]) do |attributes, attribute_key| | |
nested_model = attribute_key.to_s.classify.safe_constantize | |
nested_model ||= model.reflections[attribute_key.to_s].options[:class_name].try(:constantize) | |
next attributes unless nested_model | |
attributes << { "#{attribute_key}_attributes".to_sym => model_params(nested_model) } | |
end | |
end | |
def model_attributes(model) | |
(model.accessible_attributes - nested_keys(model)).map(&:to_sym) | |
end | |
def nested_keys(model) | |
model.nested_attributes_options.keys.map { |key| "#{key}_attributes" } | |
end | |
def print_attributes(attributes) | |
array_attributes = attributes.select { |attr| attr.to_s.include?('_ids') } | |
(attributes - array_attributes).each { |attr| puts ":#{attr}," } | |
array_attributes.each { |attr| puts "#{attr}: []," } | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#TODO: delete after protected attributes migration to strong params is complete | |
module StrongParams | |
module Tools | |
module Printer | |
# use #print_methods and #print_for_controllers methods from this module. | |
# Depends on StrongParams::Tools::Generator. | |
# See detailed description below. | |
# Defines a path to a folder with strong params. Used when you generate params as a module. | |
PATH_TO_FILE = 'app/params_whitelists/strong_params'.freeze | |
module_function | |
# | |
# Prints into console strong params filtering method withoud indentation. | |
# | |
# Example: | |
# | |
# print_methods(User) | |
# | |
# => def user_params | |
# params.require(:user).permit([ | |
# :email, | |
# :password, | |
# address: [ | |
# :street, | |
# :zipcode | |
# ] | |
# )] | |
# end | |
# | |
def print_methods(model) | |
Array.wrap(model).each(&method(:print_method)) | |
end | |
# | |
# For ALL controllers that have corresponding models prints strong params method | |
# to the end of controller file without indentation. | |
# | |
def print_for_controllers | |
Rails.application.eager_load! | |
ApplicationController.descendants.map(&:name).each do |controller| | |
next if controller.include?('Api') | |
model = controller.gsub('Controller', '').singularize.safe_constantize | |
next unless (model && (model < ApplicationRecord)) | |
controller_path = "#{Rails.root}/app/controllers/#{controller.underscore}.rb" | |
print_to_controller(model, controller_path) | |
end | |
$stdout = old_stdout | |
end | |
# | |
# Prints into console strong params helper module without indentation. | |
# | |
# Example: | |
# | |
# print_module(User) | |
# | |
# => module StrongParams | |
# module UserParams | |
# PARAMS = [ | |
# :email, | |
# :password, | |
# address: [ | |
# :street, | |
# :zipcode | |
# ] | |
# )] | |
# end | |
# end | |
# | |
def print_module(model, submodule = nil) | |
puts 'module StrongParams' | |
puts "module #{submodule}" if submodule | |
puts "module #{model}Params" | |
print_params_array(model, 'PARAMS') | |
puts 'end' | |
puts 'end' if submodule | |
puts 'end' | |
end | |
# | |
# Prints into file strong params helper module without indentation. Accepts singular classes and arrays. | |
# | |
def print_module_to_file(models = [], submodule = nil) | |
old_stdout = $stdout | |
Array.wrap(models).each do |model| | |
File.open("#{path_to_file(submodule)}#{model.name.underscore}_params.rb", 'w') do |output| | |
$stdout = output | |
print_module(model, submodule) | |
end | |
end | |
$stdout = old_stdout | |
end | |
def print_to_controller(model, controller_path) | |
old_stdout = $stdout | |
File.open(controller_path, 'r+') do |output| | |
last_line = 0 | |
output.each {last_line = output.pos unless output.eof?} | |
output.seek(last_line, IO::SEEK_SET) | |
$stdout = output | |
print_method(model) | |
end | |
$stdout = old_stdout | |
end | |
def print_method(model) | |
puts "def #{model.name.underscore}_params" | |
print_params_array(model) | |
puts 'end' | |
puts | |
end | |
def print_constants(models) | |
models.map(&:name).sort.each { |model| puts "#{model.underscore.upcase}_PARAMS" } | |
end | |
def print_methods_to_file(models = [], submodule = nil) | |
old_stdout = $stdout | |
File.open(path_to_file(submodule), 'w') do |output| | |
$stdout = output | |
print_methods(models) | |
end | |
$stdout = old_stdout | |
end | |
def path_to_file(submodule) | |
submodule_path(submodule).tap { |full_path| Dir.mkdir(full_path) unless Dir.exist?(full_path) } | |
end | |
def submodule_path(submodule) | |
"#{PATH_TO_FILE}/#{submodule ? "#{submodule.underscore}/" : ''}" | |
end | |
def print_params(model) | |
Array.wrap(model).each(&method(:print_params_array)) | |
end | |
def print_params_array(model, variable = nil) | |
puts variable ? "#{variable} = [" : '[' | |
print_generated_params(model) | |
puts ']' | |
end | |
def print_generated_params(model) | |
StrongParams::Tools::Generator.model_params(model).tap do |params| | |
print_params_hash(params) | |
end | |
end | |
def print_params_hash(params) | |
plain_params = params.select { |param| param.is_a? Symbol } | |
plain_params.each(&method(:print_plain_param)) | |
(params.without(*plain_params)).each { |param| print_nested_param(param) } | |
end | |
def print_plain_param(param) | |
puts ":#{param}," | |
end | |
def print_nested_param(param) | |
param.values.flatten.present? ? print_hash(param) : print_array(param) | |
end | |
def print_hash(param) | |
puts "#{param.keys.first}: [" | |
print_params_hash(param.values.first) | |
puts '],' | |
end | |
def print_array(param) | |
puts "#{param.keys.first}: []," | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This code may be helpful when migrating from Protected Attributes to Strong Parameters (one of the common problems when migrating from Rails 3 to 4).