radiant-banner_rotator-extension 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/.gitmodules +3 -0
  2. data/HELP.textile +87 -0
  3. data/README.textile +68 -0
  4. data/Rakefile +136 -0
  5. data/VERSION +1 -0
  6. data/app/controllers/admin/banners_controller.rb +61 -0
  7. data/app/helpers/admin/banners_helper.rb +62 -0
  8. data/app/models/banner.rb +101 -0
  9. data/app/models/banner_placement.rb +7 -0
  10. data/app/views/admin/banners/_form.html.haml +76 -0
  11. data/app/views/admin/banners/_modify_banner.html.haml +8 -0
  12. data/app/views/admin/banners/deactivate.html.haml +10 -0
  13. data/app/views/admin/banners/edit.html.haml +8 -0
  14. data/app/views/admin/banners/index.html.haml +118 -0
  15. data/app/views/admin/banners/new.html.haml +5 -0
  16. data/app/views/admin/banners/remove.html.haml +12 -0
  17. data/app/views/admin/pages/_banner_info.html.haml +28 -0
  18. data/app/views/admin/pages/_banners_column.html.haml +11 -0
  19. data/app/views/admin/pages/_banners_column_header.html.haml +9 -0
  20. data/banner_rotator_extension.rb +41 -0
  21. data/config/initializers/radiant_config.rb +3 -0
  22. data/config/locales/en.yml +34 -0
  23. data/config/routes.rb +5 -0
  24. data/db/migrate/001_create_banners.rb +31 -0
  25. data/db/migrate/002_change_banners_default.rb +9 -0
  26. data/db/migrate/003_add_description.rb +9 -0
  27. data/lib/banner_rotator/page_extensions.rb +47 -0
  28. data/lib/banner_rotator/tags.rb +67 -0
  29. data/lib/tasks/banner_rotator_extension_tasks.rake +29 -0
  30. data/public/images/admin/deactivate.png +0 -0
  31. data/public/images/admin/pictures.png +0 -0
  32. data/public/images/admin/text_list_numbers.png +0 -0
  33. data/public/javascripts/lowpro.js +320 -0
  34. data/spec/controllers/admin_banners_controller_spec.rb +231 -0
  35. data/spec/datasets/banners_dataset.rb +26 -0
  36. data/spec/helpers/admin/banners_helper_spec.rb +9 -0
  37. data/spec/models/banner_placement_spec.rb +44 -0
  38. data/spec/models/banner_spec.rb +47 -0
  39. data/spec/models/page_extensions_spec.rb +25 -0
  40. data/spec/models/tags_spec.rb +69 -0
  41. data/spec/spec.opts +6 -0
  42. data/spec/spec_helper.rb +36 -0
  43. metadata +124 -0
data/.gitmodules ADDED
@@ -0,0 +1,3 @@
1
+ [submodule "vendor/plugins/make_resourceful"]
2
+ path = vendor/plugins/make_resourceful
3
+ url = git://github.com/hcatlin/make_resourceful.git
data/HELP.textile ADDED
@@ -0,0 +1,87 @@
1
+ The *Banner Rotator* extension, as its name implies, enables rotating banners on pages. Banners can be enabled and disabled for specific pages via the page-edit admin interface. One banner can be assigned to any number of pages. Banners are randomly selected based on weights you assign, between 1 and 10 - 1 being least likely, 10 most likely to appear. Banner rotation is enabled for a page in the "meta" drawer on the page-edit screen. When not directly associated with a page with banner rotator enabled, banners are inherited from the nearest ancestor page. Banners work by specifying a background image, with optional foreground image and link.
2
+
3
+ This extension does not support file uploads, and therefore should be used in concert with an asset management extension if direct file upload access is not available.
4
+
5
+ h2. Usage
6
+
7
+ h3. Viewing Banners
8
+
9
+ The banner tab appears under *Content*, to the right of Pages. Clicking that tab takes you to the Banners Index view. You may filter the listed banners by showing All, Active only, or Inactive only (controls upper left).
10
+
11
+ Default sorting is in alphabetical order by name, but you may also sort by the names of the pages to which they are assigned (upper right).
12
+
13
+ The default index view filter and sorting also includes pagination.
14
+
15
+ h4. Index View Actions
16
+
17
+ * Edit a banner - click on the banner thumbnail or Name
18
+ * Remove a banner - click 'Remove'. You will see a warning page advising you that deletion is permanent, and will remove the banner from all pages to which it is assigned.
19
+ * Deactivate a banner - click 'Deactivate'. You will see a warning page advising you that the banner will not be deleted, but it will be removed from all pages to which it is assigned.
20
+
21
+ h3. Creating or Editing a Banner
22
+
23
+ * To create a new banner, click the New Banner button at the lower left of the Index page.
24
+ * To edit an existing banner, click the banner thumbnail or name.
25
+
26
+ h4. Banner Fields
27
+
28
+ * Required fields are _Name_ and _Background Image_
29
+ * You may optionally add _Description_, _Foreground Image_, _Link URL_, and _Image Style_
30
+ * You may specify the target for the link as the default '_blank' for a new window, or '_top' for the same window
31
+
32
+ h3. Assigning Banners to pages
33
+
34
+ Use the 'Assigned Pages' control to add a banner to specific page(s). Assign a selection weight of 1-10 (1 is low, 10 is high). 1 is the default. Statistically a banner with a weight of 10 will appear approximately 10 times more often than a banner with a weight of one.
35
+
36
+ h4. Enabling Banner rotation on a page
37
+
38
+ * On the Page edit screen for a specific page, check the "Enable Banner Rotator" checkbox.
39
+ * If banners have been assigned to this page, their thumbnails will be displayed after "Banners Assigned". Each thumbnail is also a link to the Edit page for that banner.
40
+ * If no banners have been assigned, then thumbnails from the inherited banners will be displayed after "Banners Inherited". These are also link to banner-edit.
41
+
42
+ h4. Disabling Banner rotation
43
+
44
+ * Simply uncheck the "Enable Banner Rotation" checkbox on the Page edit screen.
45
+ * You can leave all existing banner assignments in place. If you re-enable banner rotation, these will all be in the rotation again.
46
+
47
+ h3. Using the Radius tags to display your banners
48
+
49
+ In your Layout, Snippet, or Page, you use the <r:banner> Radius tags to set up your rotating banners.
50
+
51
+ Within the @<r:banner>@ tag, you do need to prefix your tags, e.g. you can use @<r:background_image />@ instead of @<r:banner:background_image />@
52
+
53
+ h4. Simple banner rotator using a link
54
+
55
+ Clicking on the banner links to the link_url defined with the banner.
56
+
57
+ <pre><code>
58
+ <div class="banner_rotator"
59
+ <r:banner>
60
+ <a href='<r:link_url />'> <img src='<r:background_image />'/> </a>
61
+ </r:banner>
62
+ </div>
63
+ </code></pre>
64
+
65
+
66
+ h4. Banner rotator using a link, which will display banners with foreground image, if present
67
+
68
+ Note the that image style is applied to the foreground image. This way you position the foreground image relative to the background image, e.g. by defining the banner with image style "left: 100px" the foreground image is superimposed 100 pixel from the left border of the background image.
69
+
70
+ <pre><code>
71
+ <div class="banner_rotator"
72
+ <r:banner>
73
+ <r:if_foreground_image>
74
+ <div style="background: url(<r:background_image />) top left no-repeat;">
75
+ <a href="<r:link_url />" target="<r:link_target/>">
76
+ <img src="<r:foreground_image />" alt="" style="<r:image_style />" />
77
+ </a>
78
+ </div>
79
+ </r:if_foreground_image>
80
+ <r:unless_foreground_image>
81
+ <a href="<r:link_url />" target="<r:link_target/>" >
82
+ <img src="<r:background_image />" alt="" />
83
+ </a>
84
+ </r:unless_foreground_image>
85
+ </r:banner>
86
+ </div>
87
+ </code></pre>
data/README.textile ADDED
@@ -0,0 +1,68 @@
1
+ h1. Banner Rotator
2
+
3
+ The *Banner Rotator* extension, as its name implies, enables rotating banners on pages. Banners can be enabled and disabled for specific pages via the page-edit admin interface. One banner can be assigned to any number of pages. Banners are randomly selected based on weights you assign, between 1 and 10 - 1 being least likely, 10 most likely to appear. Banner rotation is enabled for a page in the "meta" drawer on the page-edit screen. When not directly associated with a page with banner rotator enabled, banners are inherited from the nearest ancestor page. Banners work by specifying a background image, with optional foreground image and link.
4
+
5
+ This extension does not support file uploads, and therefore should be used in concert with an asset management extension if direct file upload access is not available.
6
+
7
+ h2. History
8
+
9
+ * 2011-04-06 - add help doc, expand README, move banner list out of drawer, add pagination to index, other UI tweaks, gemify 1.0.0 release
10
+ * 2010-12-30 - 0.9 compatibility, blade UI, i18n
11
+ * 2010-11-17 - enabled admin ability to protect certain banners from deletion, by adding comma-delimited banner names to Radiant::Config['admin.protected_banners']
12
+ * 2009-06-22 - Deactivate banner functionality removes a banner from all pages
13
+ * 2009-02-07 - 0.7 compatible
14
+ * 2008-10-01 - First release
15
+
16
+ h2. Installation
17
+
18
+ h3. From the Radiant Extension Registry
19
+
20
+ # From your RAILS_ROOT run:
21
+ <pre>script/extension install banner_rotator</pre>
22
+ # Restart your app
23
+ NOTE: In some earlier versions of Radiant, the migrations may not run, and the assets may not be copied and you may therefore need to run:
24
+ <pre>rake radiant:extensions:banner_rotator:migrate
25
+ rake radiant:extensions:banner_rotator:update</pre>
26
+
27
+ h3. From Github
28
+
29
+ # From your RAILS_ROOT run:
30
+ <pre>cd vendor/extensions
31
+ git clone git://github.com/avonderluft/radiant-banner_rotator-extension.git ./banner_rotator
32
+ cd ../../
33
+ rake radiant:extensions:banner_rotator:migrate
34
+ rake radiant:extensions:banner_rotator:update
35
+ </pre>
36
+ # Restart your app
37
+
38
+ h3. Using the gem
39
+
40
+ # Install the gem
41
+ <pre>gem install radiant-banner_rotator-extension</pre>
42
+ # Update your Radiant config: add to environment.rb with other gem.configs
43
+ <pre>config.gem 'radiant-banner_rotator-extension', :lib => false</pre>
44
+ # Run database migrations
45
+ <pre>rake db:migrate:extensions</pre>
46
+ # Copy assets
47
+ <pre>rake radiant:extensions:update_all</pre>
48
+ # Restart your app
49
+
50
+ h2. Usage
51
+
52
+ See HELP doc
53
+
54
+ h2. To do
55
+
56
+ * Extend pagination to other index views
57
+ * javascript image popup in index view
58
+ * Make banners and banner placements draftable via the concurrent_draft extension
59
+
60
+ h2. Contributors
61
+
62
+ * Sean Cribbs
63
+ * Andrew vonderLuft
64
+ * Jeffrey Jones
65
+
66
+ h2. Acknowledgments
67
+
68
+ Thanks to "Con-way":http://www.con-way.com for funding the initial development of this extension.
data/Rakefile ADDED
@@ -0,0 +1,136 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gem|
4
+ gem.name = "radiant-banner_rotator-extension"
5
+ gem.summary = %Q{Banner Rotator Extension for Radiant CMS}
6
+ gem.description = %Q{Allows addition and independent management of rotating banners on pages.}
7
+ gem.email = "avonderluft@avlux.net"
8
+ gem.homepage = "https://github.com/avonderluft/radiant-banner_rotator-extension"
9
+ gem.authors = ['Andrew vonderLuft','Sean Cribbs']
10
+ gem.add_dependency 'radiant', ">=0.9.1"
11
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
12
+ end
13
+ rescue LoadError
14
+ puts "Jeweler (or a dependency) not available. This is only required if you plan to package banner_rotator as a gem."
15
+ end
16
+
17
+ # I think this is the one that should be moved to the extension Rakefile template
18
+
19
+ # In rails 1.2, plugins aren't available in the path until they're loaded.
20
+ # Check to see if the rspec plugin is installed first and require
21
+ # it if it is. If not, use the gem version.
22
+
23
+ # Determine where the RSpec plugin is by loading the boot
24
+ unless defined? RADIANT_ROOT
25
+ ENV["RAILS_ENV"] = "test"
26
+ case
27
+ when ENV["RADIANT_ENV_FILE"]
28
+ require File.dirname(ENV["RADIANT_ENV_FILE"]) + "/boot"
29
+ when File.dirname(__FILE__) =~ %r{vendor/radiant/vendor/extensions}
30
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../")}/config/boot"
31
+ else
32
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../")}/config/boot"
33
+ end
34
+ end
35
+
36
+ require 'rake'
37
+ require 'rake/rdoctask'
38
+ require 'rake/testtask'
39
+
40
+ rspec_base = File.expand_path(RADIANT_ROOT + '/vendor/plugins/rspec/lib')
41
+ $LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base)
42
+ require 'spec/rake/spectask'
43
+ # require 'spec/translator'
44
+
45
+ # Cleanup the RADIANT_ROOT constant so specs will load the environment
46
+ Object.send(:remove_const, :RADIANT_ROOT)
47
+
48
+ extension_root = File.expand_path(File.dirname(__FILE__))
49
+
50
+ task :default => :spec
51
+ task :stats => "spec:statsetup"
52
+
53
+ desc "Run all specs in spec directory"
54
+ Spec::Rake::SpecTask.new(:spec) do |t|
55
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
56
+ t.spec_files = FileList['spec/**/*_spec.rb']
57
+ end
58
+
59
+ namespace :spec do
60
+ desc "Run all specs in spec directory with RCov"
61
+ Spec::Rake::SpecTask.new(:rcov) do |t|
62
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
63
+ t.spec_files = FileList['spec/**/*_spec.rb']
64
+ t.rcov = true
65
+ t.rcov_opts = ['--exclude', 'spec', '--rails']
66
+ end
67
+
68
+ desc "Print Specdoc for all specs"
69
+ Spec::Rake::SpecTask.new(:doc) do |t|
70
+ t.spec_opts = ["--format", "specdoc", "--dry-run"]
71
+ t.spec_files = FileList['spec/**/*_spec.rb']
72
+ end
73
+
74
+ [:models, :controllers, :views, :helpers].each do |sub|
75
+ desc "Run the specs under spec/#{sub}"
76
+ Spec::Rake::SpecTask.new(sub) do |t|
77
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
78
+ t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"]
79
+ end
80
+ end
81
+
82
+ # Hopefully no one has written their extensions in pre-0.9 style
83
+ # desc "Translate specs from pre-0.9 to 0.9 style"
84
+ # task :translate do
85
+ # translator = ::Spec::Translator.new
86
+ # dir = RAILS_ROOT + '/spec'
87
+ # translator.translate(dir, dir)
88
+ # end
89
+
90
+ # Setup specs for stats
91
+ task :statsetup do
92
+ require 'code_statistics'
93
+ ::STATS_DIRECTORIES << %w(Model\ specs spec/models)
94
+ ::STATS_DIRECTORIES << %w(View\ specs spec/views)
95
+ ::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers)
96
+ ::STATS_DIRECTORIES << %w(Helper\ specs spec/views)
97
+ ::CodeStatistics::TEST_TYPES << "Model specs"
98
+ ::CodeStatistics::TEST_TYPES << "View specs"
99
+ ::CodeStatistics::TEST_TYPES << "Controller specs"
100
+ ::CodeStatistics::TEST_TYPES << "Helper specs"
101
+ ::STATS_DIRECTORIES.delete_if {|a| a[0] =~ /test/}
102
+ end
103
+
104
+ namespace :db do
105
+ namespace :fixtures do
106
+ desc "Load fixtures (from spec/fixtures) into the current environment's database. Load specific fixtures using FIXTURES=x,y"
107
+ task :load => :environment do
108
+ require 'active_record/fixtures'
109
+ ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
110
+ (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(RAILS_ROOT, 'spec', 'fixtures', '*.{yml,csv}'))).each do |fixture_file|
111
+ Fixtures.create_fixtures('spec/fixtures', File.basename(fixture_file, '.*'))
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ desc 'Generate documentation for the banner_rotator extension.'
119
+ Rake::RDocTask.new(:rdoc) do |rdoc|
120
+ rdoc.rdoc_dir = 'rdoc'
121
+ rdoc.title = 'BannerRotatorExtension'
122
+ rdoc.options << '--line-numbers' << '--inline-source'
123
+ rdoc.rdoc_files.include('README')
124
+ rdoc.rdoc_files.include('lib/**/*.rb')
125
+ end
126
+
127
+ # For extensions that are in transition
128
+ desc 'Test the banner_rotator extension.'
129
+ Rake::TestTask.new(:test) do |t|
130
+ t.libs << 'lib'
131
+ t.pattern = 'test/**/*_test.rb'
132
+ t.verbose = true
133
+ end
134
+
135
+ # Load any custom rakefiles for extension
136
+ Dir[File.dirname(__FILE__) + '/tasks/*.rake'].sort.each { |f| require f }
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,61 @@
1
+ class Admin::BannersController < Admin::ResourceController
2
+ model_class Banner
3
+ # TODO: Find out why the banner_placements are only updated when one is added.
4
+ paginate_models
5
+ login_required
6
+ only_allow_access_to :index, :show, :new, :create, :edit, :update, :remove, :destroy, :deactivate, :remove_all_placements!,
7
+ :when => [:designer, :admin],
8
+ :denied_url => { :controller => 'admin/pages', :action => 'index' },
9
+ :denied_message => 'You must have designer privileges to perform this action.'
10
+
11
+ before_filter :check_cookie, :only => [:index]
12
+ skip_after_filter :clear_model_cache, :only => [:destroy]
13
+
14
+ def check_cookie
15
+ unless params[:sort]
16
+ params[:sort] = cookies['banner_sort'] ? cookies['banner_sort'] : 'name'
17
+ end
18
+ %w(active inactive).each do |view|
19
+ if cookies['banner_view'] == view && params[:view] != view
20
+ flash.keep
21
+ redirect_to :view => view and return
22
+ end
23
+ end
24
+ end
25
+
26
+ def deactivate
27
+ @banner = Banner.find(params[:id])
28
+ case true
29
+ when request.post? && @banner.unprotected?
30
+ @banner.remove_all_placements!
31
+ redirect_to admin_banners_url
32
+ when @banner.protected?
33
+ flash[:error] = @banner.cannot_be_deactivated_msg
34
+ redirect_to admin_banners_url
35
+ else
36
+ response_for :deactivate
37
+ end
38
+ end
39
+
40
+ def remove
41
+ @banner = Banner.find(params[:id])
42
+ if @banner.unprotected?
43
+ response_for :remove
44
+ else
45
+ flash[:error] = @banner.cannot_be_removed_msg
46
+ redirect_to admin_banners_url
47
+ end
48
+ end
49
+
50
+ def destroy
51
+ @banner = Banner.find(params[:id])
52
+ if @banner.unprotected?
53
+ super
54
+ clear_model_cache
55
+ else
56
+ flash[:error] = @banner.cannot_be_removed_msg
57
+ redirect_to admin_banners_url
58
+ end
59
+ end
60
+
61
+ end
@@ -0,0 +1,62 @@
1
+ module Admin::BannersHelper
2
+
3
+ def link_or_span_unless_current(params, text, url, options)
4
+ if options[:id] == params[options[:param]]
5
+ content_tag(:span, text)
6
+ else
7
+ link_to text, url, options
8
+ end
9
+ end
10
+
11
+ def pages_for_select
12
+ @pages_for_select ||= begin
13
+ collect_children = lambda do |page|
14
+ [page] + (page.children.any? ? page.children.map(&collect_children) : [])
15
+ end
16
+ collect_children[Page.find_by_parent_id(nil)].flatten.uniq.map do |page|
17
+ name = page.parent ? "#{'--' * page.ancestors.size} #{page.title}" : page.title
18
+ [name, page.id]
19
+ end
20
+ end
21
+ end
22
+
23
+ def updated_stamp(model)
24
+ unless model.new_record?
25
+ updated_by = (model.updated_by || model.created_by) if model.respond_to?(:updated_by)
26
+ login = updated_by ? updated_by.login : nil
27
+ time = (model.updated_at || model.created_at)
28
+ # promoted_at = model.draft_promoted_at if model.respond_to?(:draft_promoted_at)
29
+ html = %{<p style="clear: left"><small>}
30
+ if login or time
31
+ html << 'Last updated '
32
+ html << %{by #{login} } if login
33
+ html << %{at #{ timestamp(time) }} if time
34
+ html << '. '
35
+ end
36
+ # if promoted_at
37
+ # html << %{Last promoted at #{ timestamp(promoted_at) }.}
38
+ # end
39
+ html << %{</small></p>}
40
+ html
41
+ else
42
+ %{<p class="clear">&nbsp;</p>}
43
+ end
44
+ end
45
+
46
+ def banner_edit_javascripts
47
+ <<-CODE
48
+ var AddSelector = Behavior.create({
49
+ initialize: function(type){
50
+ this.template = $(type + '_select_template');
51
+ },
52
+ onclick: function(event) {
53
+ event.stop();
54
+ var newField = new Element("p").update(this.template.innerHTML);
55
+ this.element.up("div").insert(newField);
56
+ }
57
+ });
58
+ Event.addBehavior({ '#add-page-link': AddSelector('placement')});
59
+ CODE
60
+ end
61
+
62
+ end
@@ -0,0 +1,101 @@
1
+ class Banner < ActiveRecord::Base
2
+
3
+ # Default Order & Custome scopes
4
+ default_scope :order => "name"
5
+
6
+ # Associations
7
+ has_many :banner_placements, :dependent => :destroy
8
+ has_many :pages, :through => :banner_placements
9
+
10
+ # Validations
11
+ validates_presence_of :name, :background_image
12
+
13
+ attr_writer :placements
14
+ after_save :create_placements
15
+
16
+ %w(removed deactivated).each do |action|
17
+ method_name = "cannot_be_#{action}_msg".to_sym
18
+ send :define_method, method_name do
19
+ "Foot-shooting protection enabled: The '#{name}' banner cannot be #{action}. Contact a site administrator if you have questions."
20
+ end
21
+ end
22
+
23
+ def placements
24
+ @placements || banner_placements
25
+ end
26
+
27
+ def active?
28
+ banner_placements.size > 0
29
+ end
30
+
31
+ def inactive?
32
+ ! active?
33
+ end
34
+
35
+ def protected?
36
+ if name.downcase.include?('protected')
37
+ true
38
+ else
39
+ protected_banners = []
40
+ if Radiant::Config['admin.protected_banners']
41
+ protected_banners = Radiant::Config['admin.protected_banners'].split(',').map { |b| b.downcase.strip }
42
+ end
43
+ protected_banners.include?(name.downcase)
44
+ end
45
+ end
46
+
47
+ def unprotected?
48
+ ! protected?
49
+ end
50
+
51
+ def self.find_all_by_pages
52
+ self.find_active_by_pages.concat(self.find_inactive)
53
+ end
54
+
55
+ def self.find_active
56
+ @banners = []
57
+ self.find(:all, :order => "name asc").each do |banner|
58
+ @banners << banner if banner.active?
59
+ end
60
+ @banners
61
+ end
62
+
63
+ def self.find_active_by_pages
64
+ self.find_active.sort { |a,b| a.pages[0].breadcrumb <=> b.pages[0].breadcrumb }
65
+ end
66
+
67
+ def self.find_inactive
68
+ @banners = []
69
+ self.find(:all, :order => "name asc").each do |banner|
70
+ @banners << banner if banner.inactive?
71
+ end
72
+ @banners
73
+ end
74
+
75
+ def self.total_count
76
+ self.find(:all).size
77
+ end
78
+
79
+ def self.total_active_count
80
+ self.find_active.size
81
+ end
82
+
83
+ def self.total_inactive_count
84
+ self.find_inactive.size
85
+ end
86
+
87
+ def remove_all_placements!
88
+ banner_placements.each { |placement| placement.destroy }
89
+ end
90
+
91
+ private
92
+ def create_placements
93
+ self.banner_placements.clear
94
+ if @placements
95
+ @placements.each do |hash|
96
+ self.banner_placements.create(hash)
97
+ end
98
+ end
99
+ @placements = nil
100
+ end
101
+ end