The Pug Automatic

rake accessify

Written October 19, 2007. Tagged Ruby, Ruby on Rails, Rake.

attr_accessible is preferable to attr_protected, but typing out all the attributes to which you want to grant mass-assignment access can be bothersome with big models.

To make this easier, I made a rake accessify task. Run e.g.

rake accessify MODEL=user

for output like

attr_accessible :age, :location, :location_id, :sex

(but presumably longer). The output is in alphabetical order for your culling pleasure.

Some attributes that are very rarely supposed to be accessible (like *_count and created_at – see code for the full list) are not included. It's very important to note, though, that the task is only meant to save typing, not to make security decisions. Some few obvious attributes are left out, but you should read through the generated list of attributes very carefully and remove those that should not be available to mass assignment.

To get this, just put accessify.rake in lib/tasks.

The code:

excluded_setters  = %w[id [] attributes]
excluded_suffixes = %w[count ids]

usage = "Specify model like 'rake accessify MODEL=user'."

desc "Outputs an attr_accessible statement with all setters except for those that typically are not for mass assigment, like *_count, *_ids and {created,updated}_{at,on}. #{usage} Note that this task is only meant to save the effort of typing in attributes manually; it does not make any security decisions for you. Read through the generated list of attributes very carefully and remove those that should not be available to mass assignment."
task :accessify => :environment do

begin
model = ENV['MODEL'].downcase.classify.constantize
rescue
raise "No such model! #{usage}"
end

methods = (model.instance_methods - Object.instance_methods).grep(/=$/).map(&:chop)
columns = model.column_names
setters = methods | columns
setters.reject! do |setter|
setter.match(/_#{ Regexp.union(*excluded_suffixes) }$/) ||
setter.match(/(created|updated)_(at|on)/) ||
excluded_setters.include?(setter)
end
setters = setters.sort.map(&:to_sym).map(&:inspect).join(', ')
puts "attr_accessible #{ setters }"

end

Please point out any other attributes that can be discarded by default, and anything else that can be improved. I'm not at all sure this is the best way to pick out all setters.