├── .gitignore ├── .travis.yml ├── Appraisals ├── Gemfile ├── MIT-LICENSE ├── README.markdown ├── Rakefile ├── gemfiles ├── rails_30.gemfile ├── rails_30.gemfile.lock ├── rails_31.gemfile ├── rails_31.gemfile.lock ├── rails_32.gemfile ├── rails_32.gemfile.lock ├── rails_40.gemfile ├── rails_40.gemfile.lock ├── rails_41.gemfile └── rails_41.gemfile.lock ├── lib ├── serialize_with_options.rb └── serialize_with_options │ ├── railtie.rb │ └── version.rb ├── serialize_with_options.gemspec └── test ├── serialize_with_options_test.rb └── test_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | test.db 2 | *.gem 3 | .bundle 4 | Gemfile.lock 5 | pkg/* 6 | .rvmrc 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - "1.9.3" 4 | - "2.0.0" 5 | - "2.1.0" 6 | - "2.1.1" 7 | - "2.1.2" 8 | - "2.1.3" 9 | gemfile: 10 | - gemfiles/rails_30.gemfile 11 | - gemfiles/rails_31.gemfile 12 | - gemfiles/rails_32.gemfile 13 | - gemfiles/rails_40.gemfile 14 | - gemfiles/rails_41.gemfile 15 | -------------------------------------------------------------------------------- /Appraisals: -------------------------------------------------------------------------------- 1 | appraise "rails-30" do 2 | gem "rails", "~> 3.0.20" 3 | end 4 | 5 | appraise "rails-31" do 6 | gem "rails", "~> 3.1.12" 7 | end 8 | 9 | appraise "rails-32" do 10 | gem "rails", "~> 3.2.19" 11 | end 12 | 13 | appraise "rails-40" do 14 | gem "rails", "~> 4.0.10" 15 | end 16 | 17 | appraise "rails-41" do 18 | gem "rails", "~> 4.1.6" 19 | end 20 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | # Specify your gem's dependencies in serialize_with_options.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 [name of plugin creator] 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | SerializeWithOptions 2 | ==================== 3 | 4 | [![Code Climate](https://codeclimate.com/github/vigetlabs/serialize_with_options.png)](https://codeclimate.com/github/vigetlabs/serialize_with_options) [![Build Status](https://travis-ci.org/vigetlabs/serialize_with_options.png?branch=master)](https://travis-ci.org/vigetlabs/serialize_with_options) 5 | 6 | This plugin is designed to make creating XML and JSON APIs for your Rails apps dead simple. We noticed a lot of repetition when creating API responses in our controllers. With this plugin, you can set the serialization options for a model with a simple DSL, rather than repeating them in every controller that includes it. 7 | 8 | 9 | Example 10 | ------- 11 | 12 | Here is a simple example of SerializeWithOptions in action: 13 | 14 | class User < ActiveRecord::Base 15 | has_many :posts 16 | 17 | serialize_with_options do 18 | methods :post_count 19 | includes :posts 20 | except :email 21 | end 22 | 23 | serialize_with_options(:with_email) do 24 | methods :post_count 25 | includes :posts 26 | end 27 | 28 | def post_count 29 | self.posts.count 30 | end 31 | end 32 | 33 | class Post < ActiveRecord::Base 34 | has_many :comments 35 | belongs_to :user 36 | 37 | serialize_with_options do 38 | only :title 39 | includes :user, :comments 40 | end 41 | end 42 | 43 | class Comment < ActiveRecord::Base 44 | belongs_to :post 45 | end 46 | 47 | With these directives in place, we can call `@post.to_xml` (or `@post.to_json`) and it's as if we entered: 48 | 49 | @post.to_xml(:include => { :user => { :methods => :post_count, :except => :email }, :comments => { } }) 50 | 51 | In our controller, we can just say: 52 | 53 | def show 54 | @post = Post.find(params[:id]) 55 | 56 | respond_to do |format| 57 | format.html 58 | format.xml { render :xml => @post } 59 | format.json { render :json => @post } 60 | end 61 | end 62 | 63 | All serialization options are enclosed in a `serialize_with_options` block. There are four options, lifted directly from ActiveRecord's [serialization API][ser]: `methods` are the methods to add to the default attributes, `only` are the attributes to include, excluding all others, `except` are the attributes to leave out, and `includes` are the associated models. 64 | 65 | If an included model has its own `serialize_with_options` block, its `methods`, `only`, and `except` will be respected. However, the included model's `includes` directive will be ignored (only one level of nesting is supported). If you need more than one level of nesting, you can use a hash to set your included models, rather than an array. 66 | 67 | The `serialize_with_options` class method takes an optional argument for naming a configuration set (see the User model above). This is useful if you need to multiple serialization configuration sets. You can access these secondary configuration sets by passing the set name to the serialization method, e.g., `@post.to_xml(:with_email)`. 68 | 69 | 70 | Installation 71 | ------------ 72 | 73 | Simply add "`serialize_with_options`" to your Gemfile: 74 | 75 | gem "serialize_with_options" 76 | 77 | And run "`bundle install`" 78 | 79 | * * * 80 | 81 | Copyright (c) 2009-2014 David Eisinger & Zachary Porter ([Viget Labs][vgt]), released under the MIT license. 82 | 83 | [ser]: http://api.rubyonrails.org/classes/ActiveRecord/Serialization.html 84 | [vgt]: http://www.viget.com/ 85 | 86 | *** 87 | 88 | 89 | Code At Viget 90 | 91 | 92 | Visit [code.viget.com](http://code.viget.com) to see more projects from [Viget.](https://viget.com) 93 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler' 2 | require 'rake/testtask' 3 | Bundler::GemHelper.install_tasks 4 | 5 | Rake::TestTask.new(:test) do |test| 6 | test.libs << 'lib' << 'test' 7 | test.pattern = 'test/*.rb' 8 | test.verbose = true 9 | end 10 | 11 | task :default => :test 12 | -------------------------------------------------------------------------------- /gemfiles/rails_30.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "rails", "~> 3.0.20" 6 | 7 | gemspec :path => "../" 8 | -------------------------------------------------------------------------------- /gemfiles/rails_30.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: ../ 3 | specs: 4 | serialize_with_options (0.3.0) 5 | activerecord (>= 3.0) 6 | 7 | GEM 8 | remote: http://rubygems.org/ 9 | specs: 10 | abstract (1.0.0) 11 | actionmailer (3.0.20) 12 | actionpack (= 3.0.20) 13 | mail (~> 2.2.19) 14 | actionpack (3.0.20) 15 | activemodel (= 3.0.20) 16 | activesupport (= 3.0.20) 17 | builder (~> 2.1.2) 18 | erubis (~> 2.6.6) 19 | i18n (~> 0.5.0) 20 | rack (~> 1.2.5) 21 | rack-mount (~> 0.6.14) 22 | rack-test (~> 0.5.7) 23 | tzinfo (~> 0.3.23) 24 | activemodel (3.0.20) 25 | activesupport (= 3.0.20) 26 | builder (~> 2.1.2) 27 | i18n (~> 0.5.0) 28 | activerecord (3.0.20) 29 | activemodel (= 3.0.20) 30 | activesupport (= 3.0.20) 31 | arel (~> 2.0.10) 32 | tzinfo (~> 0.3.23) 33 | activeresource (3.0.20) 34 | activemodel (= 3.0.20) 35 | activesupport (= 3.0.20) 36 | activesupport (3.0.20) 37 | appraisal (1.0.2) 38 | bundler 39 | rake 40 | thor (>= 0.14.0) 41 | arel (2.0.10) 42 | builder (2.1.2) 43 | erubis (2.6.6) 44 | abstract (>= 1.0.0) 45 | i18n (0.5.4) 46 | json (1.8.1) 47 | mail (2.2.20) 48 | activesupport (>= 2.3.6) 49 | i18n (>= 0.4.0) 50 | mime-types (~> 1.16) 51 | treetop (~> 1.4.8) 52 | mime-types (1.25.1) 53 | polyglot (0.3.5) 54 | rack (1.2.8) 55 | rack-mount (0.6.14) 56 | rack (>= 1.0.0) 57 | rack-test (0.5.7) 58 | rack (>= 1.0) 59 | rails (3.0.20) 60 | actionmailer (= 3.0.20) 61 | actionpack (= 3.0.20) 62 | activerecord (= 3.0.20) 63 | activeresource (= 3.0.20) 64 | activesupport (= 3.0.20) 65 | bundler (~> 1.0) 66 | railties (= 3.0.20) 67 | railties (3.0.20) 68 | actionpack (= 3.0.20) 69 | activesupport (= 3.0.20) 70 | rake (>= 0.8.7) 71 | rdoc (~> 3.4) 72 | thor (~> 0.14.4) 73 | rake (10.3.2) 74 | rdoc (3.12.2) 75 | json (~> 1.4) 76 | shoulda (3.5.0) 77 | shoulda-context (~> 1.0, >= 1.0.1) 78 | shoulda-matchers (>= 1.4.1, < 3.0) 79 | shoulda-context (1.2.1) 80 | shoulda-matchers (2.7.0) 81 | activesupport (>= 3.0.0) 82 | sqlite3 (1.3.9) 83 | thor (0.14.6) 84 | treetop (1.4.15) 85 | polyglot 86 | polyglot (>= 0.3.1) 87 | tzinfo (0.3.41) 88 | 89 | PLATFORMS 90 | ruby 91 | 92 | DEPENDENCIES 93 | appraisal 94 | rails (~> 3.0.20) 95 | serialize_with_options! 96 | shoulda 97 | sqlite3 98 | -------------------------------------------------------------------------------- /gemfiles/rails_31.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "rails", "~> 3.1.12" 6 | 7 | gemspec :path => "../" 8 | -------------------------------------------------------------------------------- /gemfiles/rails_31.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: ../ 3 | specs: 4 | serialize_with_options (0.3.0) 5 | activerecord (>= 3.0) 6 | 7 | GEM 8 | remote: http://rubygems.org/ 9 | specs: 10 | actionmailer (3.1.12) 11 | actionpack (= 3.1.12) 12 | mail (~> 2.4.4) 13 | actionpack (3.1.12) 14 | activemodel (= 3.1.12) 15 | activesupport (= 3.1.12) 16 | builder (~> 3.0.0) 17 | erubis (~> 2.7.0) 18 | i18n (~> 0.6) 19 | rack (~> 1.3.6) 20 | rack-cache (~> 1.2) 21 | rack-mount (~> 0.8.2) 22 | rack-test (~> 0.6.1) 23 | sprockets (~> 2.0.4) 24 | activemodel (3.1.12) 25 | activesupport (= 3.1.12) 26 | builder (~> 3.0.0) 27 | i18n (~> 0.6) 28 | activerecord (3.1.12) 29 | activemodel (= 3.1.12) 30 | activesupport (= 3.1.12) 31 | arel (~> 2.2.3) 32 | tzinfo (~> 0.3.29) 33 | activeresource (3.1.12) 34 | activemodel (= 3.1.12) 35 | activesupport (= 3.1.12) 36 | activesupport (3.1.12) 37 | multi_json (~> 1.0) 38 | appraisal (1.0.2) 39 | bundler 40 | rake 41 | thor (>= 0.14.0) 42 | arel (2.2.3) 43 | builder (3.0.4) 44 | erubis (2.7.0) 45 | hike (1.2.3) 46 | i18n (0.6.11) 47 | json (1.8.1) 48 | mail (2.4.4) 49 | i18n (>= 0.4.0) 50 | mime-types (~> 1.16) 51 | treetop (~> 1.4.8) 52 | mime-types (1.25.1) 53 | multi_json (1.10.1) 54 | polyglot (0.3.5) 55 | rack (1.3.10) 56 | rack-cache (1.2) 57 | rack (>= 0.4) 58 | rack-mount (0.8.3) 59 | rack (>= 1.0.0) 60 | rack-ssl (1.3.4) 61 | rack 62 | rack-test (0.6.2) 63 | rack (>= 1.0) 64 | rails (3.1.12) 65 | actionmailer (= 3.1.12) 66 | actionpack (= 3.1.12) 67 | activerecord (= 3.1.12) 68 | activeresource (= 3.1.12) 69 | activesupport (= 3.1.12) 70 | bundler (~> 1.0) 71 | railties (= 3.1.12) 72 | railties (3.1.12) 73 | actionpack (= 3.1.12) 74 | activesupport (= 3.1.12) 75 | rack-ssl (~> 1.3.2) 76 | rake (>= 0.8.7) 77 | rdoc (~> 3.4) 78 | thor (~> 0.14.6) 79 | rake (10.3.2) 80 | rdoc (3.12.2) 81 | json (~> 1.4) 82 | shoulda (3.5.0) 83 | shoulda-context (~> 1.0, >= 1.0.1) 84 | shoulda-matchers (>= 1.4.1, < 3.0) 85 | shoulda-context (1.2.1) 86 | shoulda-matchers (2.7.0) 87 | activesupport (>= 3.0.0) 88 | sprockets (2.0.4) 89 | hike (~> 1.2) 90 | rack (~> 1.0) 91 | tilt (~> 1.1, != 1.3.0) 92 | sqlite3 (1.3.9) 93 | thor (0.14.6) 94 | tilt (1.4.1) 95 | treetop (1.4.15) 96 | polyglot 97 | polyglot (>= 0.3.1) 98 | tzinfo (0.3.41) 99 | 100 | PLATFORMS 101 | ruby 102 | 103 | DEPENDENCIES 104 | appraisal 105 | rails (~> 3.1.12) 106 | serialize_with_options! 107 | shoulda 108 | sqlite3 109 | -------------------------------------------------------------------------------- /gemfiles/rails_32.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "rails", "~> 3.2.19" 6 | 7 | gemspec :path => "../" 8 | -------------------------------------------------------------------------------- /gemfiles/rails_32.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: ../ 3 | specs: 4 | serialize_with_options (0.3.0) 5 | activerecord (>= 3.0) 6 | 7 | GEM 8 | remote: http://rubygems.org/ 9 | specs: 10 | actionmailer (3.2.19) 11 | actionpack (= 3.2.19) 12 | mail (~> 2.5.4) 13 | actionpack (3.2.19) 14 | activemodel (= 3.2.19) 15 | activesupport (= 3.2.19) 16 | builder (~> 3.0.0) 17 | erubis (~> 2.7.0) 18 | journey (~> 1.0.4) 19 | rack (~> 1.4.5) 20 | rack-cache (~> 1.2) 21 | rack-test (~> 0.6.1) 22 | sprockets (~> 2.2.1) 23 | activemodel (3.2.19) 24 | activesupport (= 3.2.19) 25 | builder (~> 3.0.0) 26 | activerecord (3.2.19) 27 | activemodel (= 3.2.19) 28 | activesupport (= 3.2.19) 29 | arel (~> 3.0.2) 30 | tzinfo (~> 0.3.29) 31 | activeresource (3.2.19) 32 | activemodel (= 3.2.19) 33 | activesupport (= 3.2.19) 34 | activesupport (3.2.19) 35 | i18n (~> 0.6, >= 0.6.4) 36 | multi_json (~> 1.0) 37 | appraisal (1.0.2) 38 | bundler 39 | rake 40 | thor (>= 0.14.0) 41 | arel (3.0.3) 42 | builder (3.0.4) 43 | erubis (2.7.0) 44 | hike (1.2.3) 45 | i18n (0.6.11) 46 | journey (1.0.4) 47 | json (1.8.1) 48 | mail (2.5.4) 49 | mime-types (~> 1.16) 50 | treetop (~> 1.4.8) 51 | mime-types (1.25.1) 52 | multi_json (1.10.1) 53 | polyglot (0.3.5) 54 | rack (1.4.5) 55 | rack-cache (1.2) 56 | rack (>= 0.4) 57 | rack-ssl (1.3.4) 58 | rack 59 | rack-test (0.6.2) 60 | rack (>= 1.0) 61 | rails (3.2.19) 62 | actionmailer (= 3.2.19) 63 | actionpack (= 3.2.19) 64 | activerecord (= 3.2.19) 65 | activeresource (= 3.2.19) 66 | activesupport (= 3.2.19) 67 | bundler (~> 1.0) 68 | railties (= 3.2.19) 69 | railties (3.2.19) 70 | actionpack (= 3.2.19) 71 | activesupport (= 3.2.19) 72 | rack-ssl (~> 1.3.2) 73 | rake (>= 0.8.7) 74 | rdoc (~> 3.4) 75 | thor (>= 0.14.6, < 2.0) 76 | rake (10.3.2) 77 | rdoc (3.12.2) 78 | json (~> 1.4) 79 | shoulda (3.5.0) 80 | shoulda-context (~> 1.0, >= 1.0.1) 81 | shoulda-matchers (>= 1.4.1, < 3.0) 82 | shoulda-context (1.2.1) 83 | shoulda-matchers (2.7.0) 84 | activesupport (>= 3.0.0) 85 | sprockets (2.2.2) 86 | hike (~> 1.2) 87 | multi_json (~> 1.0) 88 | rack (~> 1.0) 89 | tilt (~> 1.1, != 1.3.0) 90 | sqlite3 (1.3.9) 91 | thor (0.19.1) 92 | tilt (1.4.1) 93 | treetop (1.4.15) 94 | polyglot 95 | polyglot (>= 0.3.1) 96 | tzinfo (0.3.41) 97 | 98 | PLATFORMS 99 | ruby 100 | 101 | DEPENDENCIES 102 | appraisal 103 | rails (~> 3.2.19) 104 | serialize_with_options! 105 | shoulda 106 | sqlite3 107 | -------------------------------------------------------------------------------- /gemfiles/rails_40.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "rails", "~> 4.0.10" 6 | 7 | gemspec :path => "../" 8 | -------------------------------------------------------------------------------- /gemfiles/rails_40.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: ../ 3 | specs: 4 | serialize_with_options (0.3.0) 5 | activerecord (>= 3.0) 6 | 7 | GEM 8 | remote: http://rubygems.org/ 9 | specs: 10 | actionmailer (4.0.10) 11 | actionpack (= 4.0.10) 12 | mail (~> 2.5, >= 2.5.4) 13 | actionpack (4.0.10) 14 | activesupport (= 4.0.10) 15 | builder (~> 3.1.0) 16 | erubis (~> 2.7.0) 17 | rack (~> 1.5.2) 18 | rack-test (~> 0.6.2) 19 | activemodel (4.0.10) 20 | activesupport (= 4.0.10) 21 | builder (~> 3.1.0) 22 | activerecord (4.0.10) 23 | activemodel (= 4.0.10) 24 | activerecord-deprecated_finders (~> 1.0.2) 25 | activesupport (= 4.0.10) 26 | arel (~> 4.0.0) 27 | activerecord-deprecated_finders (1.0.3) 28 | activesupport (4.0.10) 29 | i18n (~> 0.6, >= 0.6.9) 30 | minitest (~> 4.2) 31 | multi_json (~> 1.3) 32 | thread_safe (~> 0.1) 33 | tzinfo (~> 0.3.37) 34 | appraisal (1.0.2) 35 | bundler 36 | rake 37 | thor (>= 0.14.0) 38 | arel (4.0.2) 39 | builder (3.1.4) 40 | erubis (2.7.0) 41 | hike (1.2.3) 42 | i18n (0.6.11) 43 | mail (2.6.1) 44 | mime-types (>= 1.16, < 3) 45 | mime-types (2.3) 46 | minitest (4.7.5) 47 | multi_json (1.10.1) 48 | rack (1.5.2) 49 | rack-test (0.6.2) 50 | rack (>= 1.0) 51 | rails (4.0.10) 52 | actionmailer (= 4.0.10) 53 | actionpack (= 4.0.10) 54 | activerecord (= 4.0.10) 55 | activesupport (= 4.0.10) 56 | bundler (>= 1.3.0, < 2.0) 57 | railties (= 4.0.10) 58 | sprockets-rails (~> 2.0) 59 | railties (4.0.10) 60 | actionpack (= 4.0.10) 61 | activesupport (= 4.0.10) 62 | rake (>= 0.8.7) 63 | thor (>= 0.18.1, < 2.0) 64 | rake (10.3.2) 65 | shoulda (3.5.0) 66 | shoulda-context (~> 1.0, >= 1.0.1) 67 | shoulda-matchers (>= 1.4.1, < 3.0) 68 | shoulda-context (1.2.1) 69 | shoulda-matchers (2.7.0) 70 | activesupport (>= 3.0.0) 71 | sprockets (2.12.2) 72 | hike (~> 1.2) 73 | multi_json (~> 1.0) 74 | rack (~> 1.0) 75 | tilt (~> 1.1, != 1.3.0) 76 | sprockets-rails (2.1.4) 77 | actionpack (>= 3.0) 78 | activesupport (>= 3.0) 79 | sprockets (~> 2.8) 80 | sqlite3 (1.3.9) 81 | thor (0.19.1) 82 | thread_safe (0.3.4) 83 | tilt (1.4.1) 84 | tzinfo (0.3.41) 85 | 86 | PLATFORMS 87 | ruby 88 | 89 | DEPENDENCIES 90 | appraisal 91 | rails (~> 4.0.10) 92 | serialize_with_options! 93 | shoulda 94 | sqlite3 95 | -------------------------------------------------------------------------------- /gemfiles/rails_41.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "rails", "~> 4.1.6" 6 | 7 | gemspec :path => "../" 8 | -------------------------------------------------------------------------------- /gemfiles/rails_41.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: ../ 3 | specs: 4 | serialize_with_options (0.3.0) 5 | activerecord (>= 3.0) 6 | 7 | GEM 8 | remote: http://rubygems.org/ 9 | specs: 10 | actionmailer (4.1.6) 11 | actionpack (= 4.1.6) 12 | actionview (= 4.1.6) 13 | mail (~> 2.5, >= 2.5.4) 14 | actionpack (4.1.6) 15 | actionview (= 4.1.6) 16 | activesupport (= 4.1.6) 17 | rack (~> 1.5.2) 18 | rack-test (~> 0.6.2) 19 | actionview (4.1.6) 20 | activesupport (= 4.1.6) 21 | builder (~> 3.1) 22 | erubis (~> 2.7.0) 23 | activemodel (4.1.6) 24 | activesupport (= 4.1.6) 25 | builder (~> 3.1) 26 | activerecord (4.1.6) 27 | activemodel (= 4.1.6) 28 | activesupport (= 4.1.6) 29 | arel (~> 5.0.0) 30 | activesupport (4.1.6) 31 | i18n (~> 0.6, >= 0.6.9) 32 | json (~> 1.7, >= 1.7.7) 33 | minitest (~> 5.1) 34 | thread_safe (~> 0.1) 35 | tzinfo (~> 1.1) 36 | appraisal (1.0.2) 37 | bundler 38 | rake 39 | thor (>= 0.14.0) 40 | arel (5.0.1.20140414130214) 41 | builder (3.2.2) 42 | erubis (2.7.0) 43 | hike (1.2.3) 44 | i18n (0.6.11) 45 | json (1.8.1) 46 | mail (2.6.1) 47 | mime-types (>= 1.16, < 3) 48 | mime-types (2.3) 49 | minitest (5.4.1) 50 | multi_json (1.10.1) 51 | rack (1.5.2) 52 | rack-test (0.6.2) 53 | rack (>= 1.0) 54 | rails (4.1.6) 55 | actionmailer (= 4.1.6) 56 | actionpack (= 4.1.6) 57 | actionview (= 4.1.6) 58 | activemodel (= 4.1.6) 59 | activerecord (= 4.1.6) 60 | activesupport (= 4.1.6) 61 | bundler (>= 1.3.0, < 2.0) 62 | railties (= 4.1.6) 63 | sprockets-rails (~> 2.0) 64 | railties (4.1.6) 65 | actionpack (= 4.1.6) 66 | activesupport (= 4.1.6) 67 | rake (>= 0.8.7) 68 | thor (>= 0.18.1, < 2.0) 69 | rake (10.3.2) 70 | shoulda (3.5.0) 71 | shoulda-context (~> 1.0, >= 1.0.1) 72 | shoulda-matchers (>= 1.4.1, < 3.0) 73 | shoulda-context (1.2.1) 74 | shoulda-matchers (2.7.0) 75 | activesupport (>= 3.0.0) 76 | sprockets (2.12.2) 77 | hike (~> 1.2) 78 | multi_json (~> 1.0) 79 | rack (~> 1.0) 80 | tilt (~> 1.1, != 1.3.0) 81 | sprockets-rails (2.1.4) 82 | actionpack (>= 3.0) 83 | activesupport (>= 3.0) 84 | sprockets (~> 2.8) 85 | sqlite3 (1.3.9) 86 | thor (0.19.1) 87 | thread_safe (0.3.4) 88 | tilt (1.4.1) 89 | tzinfo (1.2.2) 90 | thread_safe (~> 0.1) 91 | 92 | PLATFORMS 93 | ruby 94 | 95 | DEPENDENCIES 96 | appraisal 97 | rails (~> 4.1.6) 98 | serialize_with_options! 99 | shoulda 100 | sqlite3 101 | -------------------------------------------------------------------------------- /lib/serialize_with_options.rb: -------------------------------------------------------------------------------- 1 | require 'serialize_with_options/railtie' if defined?(Rails) 2 | 3 | module SerializeWithOptions 4 | def self.extended(base) 5 | base.class_attribute :serialization_conf 6 | base.class_attribute :serialization_opts 7 | end 8 | 9 | def serialize_with_options(set = :default, &block) 10 | conf = self.serialization_conf || {} 11 | opts = self.serialization_opts || {} 12 | 13 | conf[set] = Config.new.instance_eval(&block) 14 | 15 | self.serialization_conf = conf 16 | self.serialization_opts = opts 17 | 18 | include InstanceMethods 19 | end 20 | 21 | def serialization_configuration(set) 22 | conf = self.serialization_conf 23 | conf &&= conf[set] || conf[:default] 24 | conf.try(:dup) || { :methods => nil, :only => nil, :except => nil } 25 | end 26 | 27 | def serialization_options(set) 28 | options = self.serialization_opts 29 | 30 | options[set] ||= serialization_configuration(set).tap do |opts| 31 | includes = opts.delete(:includes) 32 | 33 | if includes 34 | opts[:include] = includes.inject({}) do |hash, class_name| 35 | if class_name.is_a? Hash 36 | hash.merge(class_name) 37 | else 38 | begin 39 | klass = class_name.to_s.classify.constantize 40 | hash[class_name] = klass.serialization_configuration(set) 41 | hash[class_name][:include] = nil if hash[class_name].delete(:includes) 42 | hash 43 | rescue NameError 44 | hash.merge(class_name => { :include => nil }) 45 | end 46 | end 47 | end 48 | end 49 | end 50 | 51 | self.serialization_opts = options 52 | options[set] 53 | end 54 | 55 | class Config 56 | undef_method :methods 57 | Instructions = [:skip_instruct, :dasherize, :skip_types, :root_in_json].freeze 58 | 59 | def initialize 60 | @data = { :methods => nil, :only => nil, :except => nil } 61 | end 62 | 63 | def method_missing(method, *args) 64 | @data[method] = Instructions.include?(method) ? args.first : args 65 | @data 66 | end 67 | end 68 | 69 | module InstanceMethods 70 | %w(to_xml to_json as_json).each do |method_name| 71 | define_method method_name do |*args| 72 | set, opts = parse_serialization_options(args) 73 | super self.class.serialization_options(set).deep_merge(opts) 74 | end 75 | end 76 | 77 | private 78 | 79 | def parse_serialization_options(args) 80 | opts = args.extract_options! 81 | set = args.shift || :default 82 | 83 | [set, opts] 84 | end 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /lib/serialize_with_options/railtie.rb: -------------------------------------------------------------------------------- 1 | module SerializeWithOptions 2 | class Railtie < Rails::Railtie 3 | initializer 'serialize_with_options.extend_active_record', :after => 'active_record.initialize_database' do |app| 4 | ActiveSupport.on_load(:active_record) do 5 | self.extend SerializeWithOptions 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/serialize_with_options/version.rb: -------------------------------------------------------------------------------- 1 | module SerializeWithOptions 2 | VERSION = "0.3.0" 3 | end 4 | -------------------------------------------------------------------------------- /serialize_with_options.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.push File.expand_path("../lib", __FILE__) 3 | require "serialize_with_options/version" 4 | 5 | Gem::Specification.new do |s| 6 | s.name = "serialize_with_options" 7 | s.version = SerializeWithOptions::VERSION 8 | s.platform = Gem::Platform::RUBY 9 | s.authors = ["David Eisinger"] 10 | s.email = ["david.eisinger@gmail.com"] 11 | s.homepage = "http://www.viget.com/extend/simple-apis-using-serializewithoptions" 12 | s.summary = %q{Simple XML and JSON APIs for your Rails app} 13 | s.description = %q{Simple XML and JSON APIs for your Rails app} 14 | 15 | s.rubyforge_project = "serialize_with_options" 16 | 17 | s.files = `git ls-files`.split("\n") 18 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 19 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 20 | s.require_paths = ["lib"] 21 | 22 | s.add_dependency "activerecord", ">= 3.0" 23 | 24 | s.add_development_dependency "shoulda" 25 | s.add_development_dependency "sqlite3" 26 | s.add_development_dependency 'appraisal' 27 | end 28 | -------------------------------------------------------------------------------- /test/serialize_with_options_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class User < ActiveRecord::Base 4 | has_many :posts 5 | has_many :blog_posts 6 | has_many :check_ins 7 | has_many :reviews, :as => :reviewable 8 | 9 | serialize_with_options do 10 | methods :post_count 11 | includes :posts 12 | except :email 13 | end 14 | 15 | serialize_with_options(:with_email) do 16 | methods :post_count 17 | includes :posts 18 | end 19 | 20 | serialize_with_options(:with_comments) do 21 | includes :posts => { :include => :comments } 22 | end 23 | 24 | serialize_with_options(:with_check_ins) do 25 | includes :check_ins 26 | dasherize false 27 | skip_types true 28 | end 29 | 30 | serialize_with_options(:with_reviews) do 31 | includes :reviews 32 | end 33 | 34 | def post_count 35 | self.posts.count 36 | end 37 | end 38 | 39 | class Post < ActiveRecord::Base 40 | belongs_to :user 41 | has_many :comments 42 | has_many :reviews, :as => :reviewable 43 | 44 | serialize_with_options do 45 | only :title 46 | includes :user, :comments 47 | end 48 | 49 | serialize_with_options(:with_email) do 50 | includes :user, :comments 51 | end 52 | end 53 | 54 | class BlogPost < Post 55 | serialize_with_options(:with_email) do 56 | includes :user 57 | end 58 | end 59 | 60 | class Comment < ActiveRecord::Base 61 | belongs_to :post 62 | end 63 | 64 | class CheckIn < ActiveRecord::Base 65 | belongs_to :user 66 | 67 | serialize_with_options do 68 | only :code_name 69 | includes :user 70 | end 71 | end 72 | 73 | class Review < ActiveRecord::Base 74 | belongs_to :reviewable, :polymorphic => true 75 | 76 | serialize_with_options do 77 | includes :reviewable 78 | end 79 | end 80 | 81 | class SerializeWithOptionsTest < ActiveSupport::TestCase 82 | def self.should_serialize_with_options 83 | should "include active_record attributes" do 84 | assert_equal @user.name, @user_hash["name"] 85 | end 86 | 87 | should "include specified methods" do 88 | assert_equal @user.post_count, @user_hash["post_count"] 89 | end 90 | 91 | should "exclude specified attributes" do 92 | assert_equal nil, @user_hash["email"] 93 | end 94 | 95 | should "exclude attributes not in :only list" do 96 | assert_equal nil, @post_hash["content"] 97 | end 98 | 99 | should "include specified associations" do 100 | assert_equal @post.title, @user_hash["posts"].first["title"] 101 | end 102 | 103 | should "be identical in inherited model" do 104 | assert_equal @post_hash["title"], @blog_post_hash["title"] 105 | end 106 | 107 | should "include specified methods on associations" do 108 | assert_equal @user.post_count, @post_hash["user"]["post_count"] 109 | end 110 | 111 | should "exclude specified methods on associations" do 112 | assert_equal nil, @post_hash["user"]["email"] 113 | end 114 | 115 | should "not include associations of associations" do 116 | assert_equal nil, @user_hash["posts"].first["comments"] 117 | end 118 | 119 | should "include association without serialization options properly" do 120 | assert_equal @comment.content, @post_hash["comments"].first["content"] 121 | end 122 | 123 | should "override sets on inherited models" do 124 | assert_equal nil, @blog_post_hash["comments"].first 125 | end 126 | end 127 | 128 | context "An instance of a class with serialization options" do 129 | setup do 130 | @user = User.create(:name => "John User", :email => "john@example.com") 131 | @post = @user.posts.create(:title => "Hello World!", :content => "Welcome to my blog.") 132 | @blog_post = @user.blog_posts.create(:title => "Hello World!", :content => "Welcome to my blog.") 133 | @comment = @post.comments.create(:content => "Great blog!") 134 | end 135 | 136 | context "being converted to XML" do 137 | setup do 138 | @user_hash = Hash.from_xml(@user.to_xml)["user"] 139 | @post_hash = Hash.from_xml(@post.to_xml)["post"] 140 | @blog_post_hash = Hash.from_xml(@blog_post.to_xml)["blog_post"] 141 | end 142 | 143 | should_serialize_with_options 144 | end 145 | 146 | 147 | should "accept additional properties w/o overwriting defaults" do 148 | xml = @post.to_xml(:include => { :user => { :except => nil } }) 149 | post_hash = Hash.from_xml(xml)["post"] 150 | 151 | assert_equal @user.email, post_hash["user"]["email"] 152 | assert_equal @user.post_count, post_hash["user"]["post_count"] 153 | end 154 | 155 | should "accept a hash for includes directive" do 156 | user_hash = Hash.from_xml(@user.to_xml(:with_comments))["user"] 157 | assert_equal @comment.content, user_hash["posts"].first["comments"].first["content"] 158 | end 159 | 160 | context "with a secondary configuration" do 161 | should "use it" do 162 | user_hash = Hash.from_xml(@user.to_xml(:with_email))["user"] 163 | assert_equal @user.email, user_hash["email"] 164 | end 165 | 166 | should "pass it through to included models" do 167 | post_hash = Hash.from_xml(@post.to_xml(:with_email))["post"] 168 | assert_equal @user.email, post_hash["user"]["email"] 169 | end 170 | end 171 | 172 | context "with a polymorphic relationship" do 173 | setup do 174 | @review = Review.create(:reviewable => @user, :content => "troll") 175 | end 176 | 177 | should "include the associated object" do 178 | user_hash = Hash.from_xml(@user.to_xml(:with_reviews)) 179 | assert_equal @review.content, user_hash["user"]["reviews"].first["content"] 180 | end 181 | 182 | should "serialize the associated object properly" do 183 | review_hash = Hash.from_xml(@review.to_xml) 184 | assert_equal @user.name, review_hash["review"]["reviewable"]["name"] 185 | end 186 | end 187 | 188 | context "being converted to JSON" do 189 | setup do 190 | @user_hash = JSON.parse(@user.to_json) 191 | @post_hash = JSON.parse(@post.to_json) 192 | @blog_post_hash = JSON.parse(@blog_post.to_json) 193 | end 194 | 195 | should_serialize_with_options 196 | end 197 | 198 | context 'passing options to the serializer' do 199 | setup do 200 | if ActiveSupport::VERSION::MAJOR == 3 && ActiveSupport::VERSION::MINOR < 2 201 | ActiveRecord::Base.include_root_in_json = true 202 | end 203 | @user_hash = @user.as_json(:with_email, :root => 'custom_root')['custom_root'] 204 | end 205 | 206 | teardown do 207 | ActiveRecord::Base.include_root_in_json = false 208 | end 209 | 210 | should "include active_record attributes" do 211 | assert_equal @user.name, @user_hash["name"] 212 | end 213 | 214 | should "exclude specified attributes" do 215 | assert_equal @user.email, @user_hash["email"] 216 | end 217 | end 218 | 219 | context "serializing associated models" do 220 | setup do 221 | @user = User.create(:name => "John User", :email => "john@example.com") 222 | @check_in = @user.check_ins.create(:code_name => "Hello World") 223 | end 224 | 225 | should "find associations with multi-word names" do 226 | user_hash = JSON.parse(@user.to_json(:with_check_ins)) 227 | assert_equal @check_in.code_name, user_hash['check_ins'].first['code_name'] 228 | end 229 | 230 | should "respect xml formatting options" do 231 | assert !@user.to_xml(:with_check_ins).include?('check-ins') 232 | assert !@user.to_xml(:with_check_ins).include?('type=') 233 | end 234 | end 235 | end 236 | end 237 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | $:.unshift(File.dirname(__FILE__) + '/..') 2 | $:.unshift(File.dirname(__FILE__) + '/../lib') 3 | 4 | require 'rubygems' 5 | require 'bundler' 6 | begin 7 | Bundler.setup(:default, :development) 8 | rescue Bundler::BundlerError => e 9 | $stderr.puts e.message 10 | $stderr.puts "Run `bundle install` to install missing gems" 11 | exit e.status_code 12 | end 13 | 14 | require 'active_support/version' 15 | if ActiveSupport::VERSION::MAJOR >= 4 16 | require 'minitest/autorun' 17 | else 18 | require 'test/unit' 19 | end 20 | 21 | require 'sqlite3' 22 | require 'active_record' 23 | 24 | if ActiveSupport::VERSION::MAJOR == 3 25 | ActiveSupport.on_load(:active_record) do 26 | self.include_root_in_json = false 27 | end 28 | end 29 | 30 | require 'shoulda' 31 | require 'json' 32 | require 'serialize_with_options' 33 | ActiveRecord::Base.extend SerializeWithOptions 34 | 35 | ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:') 36 | 37 | [:users, :posts, :comments, :check_ins, :reviews].each do |table| 38 | ActiveRecord::Base.connection.drop_table table rescue nil 39 | end 40 | 41 | ActiveRecord::Base.connection.create_table :users do |t| 42 | t.string :name 43 | t.string :email 44 | end 45 | 46 | ActiveRecord::Base.connection.create_table :posts do |t| 47 | t.string :title 48 | t.text :content 49 | t.integer :user_id 50 | t.string :type 51 | end 52 | 53 | ActiveRecord::Base.connection.create_table :comments do |t| 54 | t.text :content 55 | t.integer :post_id 56 | end 57 | 58 | ActiveRecord::Base.connection.create_table :check_ins do |t| 59 | t.integer :user_id 60 | t.string :code_name 61 | end 62 | 63 | ActiveRecord::Base.connection.create_table :reviews do |t| 64 | t.string :content 65 | t.integer :reviewable_id 66 | t.string :reviewable_type 67 | end 68 | 69 | --------------------------------------------------------------------------------