<commit_before>h1. MassAssignment

Copyright (c) 2009 <NAME>, released under the MIT license

h2. What It Is

A robust mass assignment method with a small and obvious syntax.

The normal mass assignment protection comes from attr_protected and attr_accessible. There are a many problems with this approach:

* Often never implemented, leaving a wide-open system. And once implemented, easy to forget when adding new attributes, leading to bugs (in an attr_accessible system) or security holes (in an attr_protected system).
* Restricts coding syntax. You can't easily use update_attributes() or attributes= because your whitelist/blacklist gets in your own way.
* Not contextual. The list of allowed attributes can't change to accomodate different user permissions or situations.

This plugin's solution is to let you specify an obvious list of allowed attributes when you mass assign attributes.

* The list of allowed attributes is in your controller at calltime, so it's easier to remember and update (it's not a hidden, magical system).
* The list of allowed attributes is optional, so it doesn't get in your way.
* Your controller can easily enforce permissions by evaluating the current user (Admin Controller) or the current situation (creates vs updates).

And as a bonus, permission plugins have a much easier time of things. The list of allowed attributes may be pulled from a permissions table without any awkward User.current class or thread variables.

h2. Example

Let's take a very plausible situation where you would want three separate lists of allowed attributes. You have users that sign up to your application. But after they have signed up, they may not change their username. Admins, however, may manually change a username as needed.

  class UsersController < ApplicationController
    def create
      @user = User.new
      # during signup a user may pick a username
      @user.assign(params[:user], [:username, :email, :password, :password_confirmation])
      @user.save!
      ...
    end
    def update
      @user = User.find(params[:id])
      # username is no longer accepted later
      @user.assign(params[:user], [:email, :password, :password_confirmation])
      @user.save!
      ...
    end
  end

  class Admin::UsersController < ApplicationController
    before_filter :admin_required
    def update
      @user = User.find(params[:id])
      # admins, on the other hand, may change the username as needed, but may not set passwords
      @user.assign(:params[:user], [:username, :email])
      @user.save!
      ...
    end
  end

h2. Feedback

I can think of a couple alternate implementations for this API. Consider:

  @user.assign(params[:user], [:username, :email])

vs

  @user.assign(params[:user], :only => [:username, :email])
  @user.assign(params[:user], :except => [:admin])
  
I personally prefer the former because I think that blacklists are inherently less safe than whitelists, with no compensating advantage. But I'd love to hear some other use cases and get feedback on this! Fork this repo and send pull requests or just contact me (github.com/cainlevy). Let's talk.
<commit_msg>playing with textile filters ...<commit_after>h2. MassAssignment

Copyright (c) 2009 <NAME>, released under the MIT license

h3. What It Is

A robust mass assignment method with a small and obvious syntax.

The normal mass assignment protection comes from attr_protected and attr_accessible. There are a many problems with this approach:

* Often never implemented, leaving a wide-open system. And once implemented, easy to forget when adding new attributes, leading to bugs (in an attr_accessible system) or security holes (in an attr_protected system).
* Restricts coding syntax. You can't easily use update_attributes() or attributes= because your whitelist/blacklist gets in your own way.
* Not contextual. The list of allowed attributes can't change to accomodate different user permissions or situations.

This plugin's solution is to let you specify an obvious list of allowed attributes when you mass assign attributes.

* The list of allowed attributes is in your controller at calltime, so it's easier to remember and update (it's not a hidden, magical system).
* The list of allowed attributes is optional, so it doesn't get in your way.
* Your controller can easily enforce permissions by evaluating the current user (Admin Controller) or the current situation (creates vs updates).

And as a bonus, permission plugins have a much easier time of things. The list of allowed attributes may be pulled from a permissions table without any awkward User.current class or thread variables.

h3. Example

Let's take a very plausible situation where you would want three separate lists of allowed attributes. You have users that sign up to your application. But after they have signed up, they may not change their username. Admins, however, may manually change a username as needed.

bc..
  class UsersController < ApplicationController
    def create
      @user = User.new
      # during signup a user may pick a username
      @user.assign(params[:user], [:username, :email, :password, :password_confirmation])
      @user.save!
      ...
    end

    def update
      @user = User.find(params[:id])
      # username is no longer accepted later
      @user.assign(params[:user], [:email, :password, :password_confirmation])
      @user.save!
      ...
    end
  end

  class Admin::UsersController < ApplicationController
    before_filter :admin_required

    def update
      @user = User.find(params[:id])
      # admins, on the other hand, may change the username as needed, but may not set passwords
      @user.assign(:params[:user], [:username, :email])
      @user.save!
      ...
    end
  end

h3. Feedback

I can think of a couple alternate implementations for this API. Consider:

  @user.assign(params[:user], [:username, :email])

vs

  @user.assign(params[:user], :only => [:username, :email])
  @user.assign(params[:user], :except => [:admin])
  
I personally prefer the former because I think that blacklists are inherently less safe than whitelists, with no compensating advantage. But I'd love to hear some other use cases and get feedback on this! Fork this repo and send pull requests or just contact me (github.com/cainlevy). Let's talk.

{'fraction_non_alphanumeric': 0.0705229793977813, 'fraction_numerical': 0.0025356576862123614, 'mean_word_length': 3.934323690383112, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1945715', 'n_tokens_mistral': 1612, 'n_tokens_neox': 1554, 'n_words': 825}