Permalink
Browse files

Initial implementation.

  • Loading branch information...
rubiety committed Jan 6, 2009
1 parent 91591f1 commit 8faeed8b7e5c00ae35f2c4b953ab4221fd2e94ad
Showing with 226 additions and 19 deletions.
  1. +2 −0 .gitignore
  2. +0 −13 README
  3. +34 −0 README.rdoc
  4. +3 −1 init.rb
  5. +46 −1 lib/nilify_blanks.rb
  6. +18 −0 test/config/database.yml
  7. +5 −0 test/models/except_post.rb
  8. +5 −0 test/models/only_post.rb
  9. +3 −0 test/models/post.rb
  10. +84 −4 test/nilify_blanks_test.rb
  11. +12 −0 test/schema.rb
  12. +14 −0 test/test_helper.rb
View
@@ -0,0 +1,2 @@
+*.sqlite3
+*.sqlite
View
13 README
@@ -1,13 +0,0 @@
-NilifyBlanks
-============
-
-Introduction goes here.
-
-
-Example
-=======
-
-Example goes here.
-
-
-Copyright (c) 2008 [name of plugin creator], released under the MIT license
View
@@ -0,0 +1,34 @@
+== Nilify Blanks
+
+In Rails when you use a form and, for text fields, the user does not provide a value, the database field becomes an empty string and not NULL as many would prefer. This plugin allows you to specify a list of attributes (or exceptions from all the attributes) that will be converted to nil if they are blank before a model is saved.
+
+Only fields who have values that respond to empty? with a value of true will be converted to nil. Therefore, this does not work with integer fields with the value of 0, for example. Usage is best shown through examples:
+
+== Basic Examples
+
+ # Checks and converts all fields in the model
+ class Post < ActiveRecord::Base
+ nilify_blanks
+ end
+
+ # Checks and converts only the title and author fields
+ class Post < ActiveRecord::Base
+ nilify_blanks :only => [:author, :title]
+ end
+
+ # Checks and converts all fields except for title and author
+ class Post < ActiveRecord::Base
+ nilify_blanks :except => [:author, :title]
+ end
+
+== Specifying a Callback
+
+Checking uses an ActiveRecord before_save filter by default, but you can specify a different filter with the :before option. Any filter will work - just first remove the "before_" prefix from the name.
+
+ class Post < ActiveRecord::Base
+ nilify_blanks :before => :create
+ end
+
+ class Post < ActiveRecord::Before
+ nilify_blanks :before => :validation_on_update
+ end
View
@@ -1 +1,3 @@
-# Include hook code here
+require 'nilify_blanks'
+
+ActiveRecord::Base.send(:include, Rubiety::NilifyBlanks)
View
@@ -1 +1,46 @@
-# NilifyBlanks
+module Rubiety
+ module NilifyBlanks
+ def self.included(base)
+ base.extend ClassMethods
+ end
+
+ module ClassMethods
+ def nilify_blanks(options = {})
+ return if self.included_modules.include?(NilifyBlanks::InstanceMethods)
+ include NilifyBlanks::InstanceMethods
+
+ if options[:only]
+ options[:only] = [options[:only]] unless options[:only].is_a?(Array)
+ options[:only] = options[:only].map(&:to_s)
+ end
+
+ if options[:except]
+ options[:except] = [options[:except]] unless options[:except].is_a?(Array)
+ options[:except] = options[:except].map(&:to_s)
+ end
+
+ cattr_accessor :nilify_blanks_columns
+
+ self.nilify_blanks_columns = self.content_columns.reject {|c| !c.null }.map {|c| c.name.to_s }
+ self.nilify_blanks_columns = self.nilify_blanks_columns.select {|c| options[:only].include?(c) } if options[:only]
+ self.nilify_blanks_columns -= options[:except] if options[:except]
+ self.nilify_blanks_columns = self.nilify_blanks_columns.map(&:to_s)
+
+ options[:before] ||= :save
+ class_eval "before_#{options[:before]} :nilify_blanks"
+ end
+ end
+
+ module InstanceMethods
+ def nilify_blanks
+ (self.nilify_blanks_columns || []).each do |column|
+ value = read_attribute(column)
+ next unless value.is_a?(String)
+ next unless value.nil? or !value.respond_to?(:blank)
+
+ write_attribute(column, nil) if value.blank?
+ end
+ end
+ end
+ end
+end
View
@@ -0,0 +1,18 @@
+sqlite:
+ :adapter: sqlite
+ :dbfile: nilify_blanks_plugin.sqlite
+sqlite3:
+ :adapter: sqlite3
+ :dbfile: nilify_blanks_plugin.sqlite3
+postgresql:
+ :adapter: postgresql
+ :username: postgres
+ :password: postgres
+ :database: nilify_blanks_plugin_test
+ :min_messages: ERROR
+mysql:
+ :adapter: mysql
+ :host: localhost
+ :username: root
+ :password:
+ :database: nilify_blanks_plugin_test
@@ -0,0 +1,5 @@
+class ExceptPost < ActiveRecord::Base
+ set_table_name :posts
+
+ nilify_blanks :except => [:first_name, :title]
+end
View
@@ -0,0 +1,5 @@
+class OnlyPost < ActiveRecord::Base
+ set_table_name :posts
+
+ nilify_blanks :only => [:first_name, :title]
+end
View
@@ -0,0 +1,3 @@
+class Post < ActiveRecord::Base
+ nilify_blanks
+end
View
@@ -1,8 +1,88 @@
-require 'test/unit'
+require File.join(File.dirname(__FILE__), 'test_helper')
+require File.join(File.dirname(__FILE__), 'models/post')
+require File.join(File.dirname(__FILE__), 'models/only_post')
+require File.join(File.dirname(__FILE__), 'models/except_post')
class NilifyBlanksTest < Test::Unit::TestCase
- # Replace this with your real tests.
- def test_this_plugin
- flunk
+ context "Model with nilify_blanks" do
+ setup do
+ class Post < ActiveRecord::Base
+ nilify_blanks
+ end
+
+ @post = Post.new(:first_name => '', :last_name => '', :title => '', :summary => '', :body => '', :views => 0)
+ @post.save
+ end
+
+ should "recognize all non-null columns" do
+ assert_equal ['first_name', 'title', 'summary', 'body', 'views'], Post.nilify_blanks_columns
+ end
+
+ should "convert all blanks to nils" do
+ assert_equal nil, @post.first_name
+ assert_equal nil, @post.title
+ assert_equal nil, @post.summary
+ assert_equal nil, @post.body
+ end
+
+ should "leave not-null last name field alone" do
+ assert_equal '', @post.last_name
+ end
+
+ should "leave integer views field alone" do
+ assert_equal 0, @post.views
+ end
+ end
+
+ context "Model with nilify_blanks :only => [:first_name, :title]" do
+ setup do
+ class PostOnlyFirstNameAndTitle < ActiveRecord::Base
+ set_table_name :posts
+ nilify_blanks :only => [:first_name, :title]
+ end
+
+ @post = PostOnlyFirstNameAndTitle.new(:first_name => '', :last_name => '', :title => '', :summary => '', :body => '', :views => 0)
+ @post.save
+ end
+
+ should "recognize only first_name and title" do
+ assert_equal ['first_name', 'title'], PostOnlyFirstNameAndTitle.nilify_blanks_columns
+ end
+
+ should "convert first_name and title blanks to nils" do
+ assert_equal nil, @post.first_name
+ assert_equal nil, @post.title
+ end
+
+ should "leave other fields alone" do
+ assert_equal '', @post.summary
+ assert_equal '', @post.body
+ end
+ end
+
+ context "Model with nilify_blanks :except => [:first_name, :title]" do
+ setup do
+ class PostExceptFirstNameAndTitle < ActiveRecord::Base
+ set_table_name :posts
+ nilify_blanks :except => [:first_name, :title]
+ end
+
+ @post = PostExceptFirstNameAndTitle.new(:first_name => '', :last_name => '', :title => '', :summary => '', :body => '', :views => 0)
+ @post.save
+ end
+
+ should "recognize only summary, body, and views" do
+ assert_equal ['summary', 'body', 'views'], PostExceptFirstNameAndTitle.nilify_blanks_columns
+ end
+
+ should "convert summary and body blanks to nils" do
+ assert_equal nil, @post.summary
+ assert_equal nil, @post.body
+ end
+
+ should "leave other fields alone" do
+ assert_equal '', @post.first_name
+ assert_equal '', @post.title
+ end
end
end
View
@@ -0,0 +1,12 @@
+ActiveRecord::Schema.define(:version => 0) do
+
+ create_table :posts, :force => true do |t|
+ t.string :first_name
+ t.string :last_name, :null => false
+ t.string :title
+ t.text :summary
+ t.text :body
+ t.integer :views
+ end
+
+end
View
@@ -0,0 +1,14 @@
+require 'test/unit'
+require 'rubygems'
+require 'active_record'
+require 'active_record/fixtures'
+require 'shoulda/rails'
+require File.expand_path(File.join(File.dirname(__FILE__), '../lib/nilify_blanks'))
+
+config = YAML::load(IO.read(File.join(File.dirname(__FILE__), 'config', '/database.yml')))
+ActiveRecord::Base.configurations = {'test' => config[ENV['DB'] || 'sqlite3']}
+ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
+
+load(File.dirname(__FILE__) + "/schema.rb")
+
+require File.expand_path(File.join(File.dirname(__FILE__), '../init'))

0 comments on commit 8faeed8

Please sign in to comment.