activeadmin 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activeadmin might be problematic. Click here for more details.

Files changed (117) hide show
  1. data/.travis.yml +1 -1
  2. data/CHANGELOG.md +92 -1
  3. data/CONTRIBUTING.md +3 -3
  4. data/Gemfile +6 -5
  5. data/README.rdoc +6 -1
  6. data/Rakefile +2 -2
  7. data/app/assets/stylesheets/active_admin/_forms.css.scss +13 -2
  8. data/app/assets/stylesheets/active_admin/components/_comments.css.scss +1 -0
  9. data/app/assets/stylesheets/active_admin/components/_table_tools.css.scss +2 -1
  10. data/app/views/active_admin/resource/index.csv.erb +4 -1
  11. data/app/views/layouts/active_admin_logged_out.html.erb +3 -3
  12. data/docs/0-installation.md +0 -7
  13. data/docs/1-general-configuration.md +37 -0
  14. data/docs/11-decorators.md +48 -0
  15. data/docs/12-arbre-components.md +145 -0
  16. data/docs/2-resource-customization.md +23 -6
  17. data/docs/3-index-pages.md +5 -0
  18. data/docs/4-csv-format.md +11 -2
  19. data/docs/8-custom-actions.md +2 -2
  20. data/features/breadcrumb.feature +27 -0
  21. data/features/decorators.feature +41 -0
  22. data/features/i18n.feature +7 -0
  23. data/features/index/format_as_csv.feature +40 -3
  24. data/features/index/index_as_table.feature +6 -6
  25. data/features/step_definitions/format_steps.rb +6 -1
  26. data/lib/active_admin.rb +1 -1
  27. data/lib/active_admin/application.rb +15 -7
  28. data/lib/active_admin/comments/comment.rb +4 -2
  29. data/lib/active_admin/csv_builder.rb +2 -1
  30. data/lib/active_admin/devise.rb +1 -0
  31. data/lib/active_admin/dsl.rb +25 -0
  32. data/lib/active_admin/filters/dsl.rb +9 -0
  33. data/lib/active_admin/filters/forms.rb +2 -0
  34. data/lib/active_admin/filters/resource_extension.rb +32 -2
  35. data/lib/active_admin/form_builder.rb +29 -12
  36. data/lib/active_admin/inputs.rb +1 -0
  37. data/lib/active_admin/inputs/filter_boolean_input.rb +40 -0
  38. data/lib/active_admin/inputs/filter_select_input.rb +5 -1
  39. data/lib/active_admin/locales/bg.yml +1 -0
  40. data/lib/active_admin/locales/ca.yml +1 -0
  41. data/lib/active_admin/locales/cs.yml +9 -1
  42. data/lib/active_admin/locales/da.yml +1 -0
  43. data/lib/active_admin/locales/de.yml +16 -3
  44. data/lib/active_admin/locales/en.yml +1 -0
  45. data/lib/active_admin/locales/es.yml +1 -0
  46. data/lib/active_admin/locales/fr.yml +5 -1
  47. data/lib/active_admin/locales/he.yml +3 -2
  48. data/lib/active_admin/locales/hr.yml +1 -0
  49. data/lib/active_admin/locales/hu.yml +1 -0
  50. data/lib/active_admin/locales/it.yml +5 -4
  51. data/lib/active_admin/locales/ja.yml +12 -12
  52. data/lib/active_admin/locales/ko.yml +1 -0
  53. data/lib/active_admin/locales/lt.yml +81 -0
  54. data/lib/active_admin/locales/lv.yml +2 -1
  55. data/lib/active_admin/locales/nl.yml +1 -0
  56. data/lib/active_admin/locales/no-NB.yml +1 -0
  57. data/lib/active_admin/locales/pl.yml +1 -0
  58. data/lib/active_admin/locales/pt-BR.yml +3 -2
  59. data/lib/active_admin/locales/ro.yml +1 -0
  60. data/lib/active_admin/locales/ru.yml +7 -6
  61. data/lib/active_admin/locales/sv-SE.yml +1 -0
  62. data/lib/active_admin/locales/tr.yml +3 -2
  63. data/lib/active_admin/locales/vi.yml +1 -0
  64. data/lib/active_admin/locales/zh-CN.yml +1 -0
  65. data/lib/active_admin/locales/zh-TW.yml +1 -0
  66. data/lib/active_admin/menu_item.rb +6 -0
  67. data/lib/active_admin/page.rb +3 -0
  68. data/lib/active_admin/page_presenter.rb +2 -0
  69. data/lib/active_admin/resource.rb +12 -1
  70. data/lib/active_admin/resource/menu.rb +8 -1
  71. data/lib/active_admin/resource_controller.rb +3 -1
  72. data/lib/active_admin/resource_controller/collection.rb +1 -1
  73. data/lib/active_admin/resource_controller/decorators.rb +19 -0
  74. data/lib/active_admin/resource_dsl.rb +1 -1
  75. data/lib/active_admin/version.rb +1 -1
  76. data/lib/active_admin/view_helpers.rb +1 -0
  77. data/lib/active_admin/view_helpers/breadcrumb_helper.rb +1 -1
  78. data/lib/active_admin/view_helpers/download_format_links_helper.rb +50 -0
  79. data/lib/active_admin/view_helpers/fields_for.rb +4 -0
  80. data/lib/active_admin/view_helpers/flash_helper.rb +13 -0
  81. data/lib/active_admin/views/components/paginated_collection.rb +2 -11
  82. data/lib/active_admin/views/components/table_for.rb +21 -27
  83. data/lib/active_admin/views/footer.rb +3 -1
  84. data/lib/active_admin/views/index_as_block.rb +1 -1
  85. data/lib/active_admin/views/index_as_grid.rb +1 -1
  86. data/lib/active_admin/views/pages/base.rb +3 -3
  87. data/lib/active_admin/views/pages/index.rb +1 -7
  88. data/lib/active_admin/views/title_bar.rb +6 -3
  89. data/lib/generators/active_admin/devise/devise_generator.rb +1 -1
  90. data/lib/generators/active_admin/install/templates/active_admin.rb.erb +6 -3
  91. data/lib/generators/active_admin/install/templates/admin_user.rb.erb +1 -1
  92. data/lib/generators/active_admin/install/templates/dashboard.rb +2 -2
  93. data/lib/generators/active_admin/install/templates/migrations/2_move_admin_notes_to_comments.rb +2 -1
  94. data/spec/integration/memory_spec.rb +1 -1
  95. data/spec/support/rails_template.rb +41 -2
  96. data/spec/support/rails_template_with_data.rb +2 -1
  97. data/spec/support/templates/en.yml +2 -0
  98. data/spec/support/templates/post_decorator.rb +53 -0
  99. data/spec/unit/application_spec.rb +17 -4
  100. data/spec/unit/belongs_to_spec.rb +1 -1
  101. data/spec/unit/config_shared_examples.rb +15 -7
  102. data/spec/unit/controller_filters_spec.rb +8 -8
  103. data/spec/unit/csv_builder_spec.rb +10 -0
  104. data/spec/unit/devise_spec.rb +28 -7
  105. data/spec/unit/filters/filter_form_builder_spec.rb +24 -0
  106. data/spec/unit/filters/resource_spec.rb +15 -1
  107. data/spec/unit/form_builder_spec.rb +4 -0
  108. data/spec/unit/resource_controller_spec.rb +67 -3
  109. data/spec/unit/resource_spec.rb +17 -0
  110. data/spec/unit/view_helpers/download_format_links_helper_spec.rb +39 -0
  111. data/spec/unit/view_helpers/fields_for_spec.rb +5 -0
  112. data/spec/unit/views/components/table_for_spec.rb +31 -0
  113. data/spec/unit/views/pages/layout_spec.rb +1 -1
  114. data/spec/unit/views/pages/show_spec.rb +21 -0
  115. data/tasks/parallel_tests.rake +60 -0
  116. data/tasks/test.rake +2 -1
  117. metadata +44 -26
@@ -0,0 +1,50 @@
1
+ module ActiveAdmin
2
+ module ViewHelpers
3
+ module DownloadFormatLinksHelper
4
+
5
+ module ClassMethods
6
+
7
+ # A ready only of formats to make available in index/paginated
8
+ # collection view.
9
+ # @return [Array]
10
+ # @see add_format for information on adding custom download link
11
+ # formats
12
+ def formats
13
+ @formats ||= [:csv, :xml, :json]
14
+ @formats.clone
15
+ end
16
+
17
+ # Adds a mime type extension to the list of available formats.
18
+ # You must register the extension prior to adding it to the list
19
+ # of avilable formats. This should be used by plugins that want
20
+ # to add additional formats to the download format links.
21
+ # @param [Symbol] extension the mime extension to add
22
+ # @return [Array] A copy of the updated formats array.
23
+ def add_format extension
24
+ unless formats.include?(extension)
25
+ if Mime::Type.lookup_by_extension(extension).nil?
26
+ raise ArgumentError, "The mime extension you defined: #{extension} is not registered. Please register it via Mime::Type.register before adding it to the available formats."
27
+ end
28
+ @formats << extension
29
+ end
30
+ formats
31
+ end
32
+ end
33
+
34
+ # TODO: Refactor to new HTML DSL
35
+ def build_download_format_links(formats = self.class.formats)
36
+ links = formats.collect do |format|
37
+ link_to format.to_s.upcase, { :format => format}.merge(request.query_parameters.except(:commit, :format))
38
+ end
39
+ div :class => "download_links" do
40
+ text_node [I18n.t('active_admin.download'), links].flatten.join("&nbsp;").html_safe
41
+ end
42
+ end
43
+
44
+ def self.included base
45
+ base.extend ClassMethods
46
+ end
47
+ end
48
+ end
49
+ end
50
+
@@ -28,12 +28,16 @@ module ActiveAdmin
28
28
  case v
29
29
  when String
30
30
  { k => v }
31
+ when Symbol
32
+ { k => v.to_s }
31
33
  when Hash
32
34
  fields_for_params(v, :namespace => k)
33
35
  when Array
34
36
  v.map do |v|
35
37
  { "#{k}[]" => v }
36
38
  end
39
+ when nil
40
+ { k => '' }
37
41
  else
38
42
  raise "I don't know what to do with #{v.class} params: #{v.inspect}"
39
43
  end
@@ -0,0 +1,13 @@
1
+ module ActiveAdmin
2
+ module ViewHelpers
3
+ module FlashHelper
4
+
5
+ # Returns all the flash keys to display in any Active Admin view.
6
+ # This method removes the :timedout key that Devise uses by default
7
+ def active_admin_flash_messages
8
+ @active_admin_flash_messages ||= flash.to_hash.except(:timedout)
9
+ end
10
+
11
+ end
12
+ end
13
+ end
@@ -77,18 +77,9 @@ module ActiveAdmin
77
77
  text_node paginate(collection, options.symbolize_keys)
78
78
  end
79
79
 
80
- # TODO: Refactor to new HTML DSL
81
- def build_download_format_links(formats = [:csv, :xml, :json])
82
- links = formats.collect do |format|
83
- link_to format.to_s.upcase, { :format => format}.merge(request.query_parameters.except(:commit, :format))
84
- end
85
- div :class => "download_links" do
86
- text_node [I18n.t('active_admin.download'), links].flatten.join("&nbsp;").html_safe
87
- end
88
- end
89
-
90
80
  include ::ActiveAdmin::Helpers::Collection
91
-
81
+ include ::ActiveAdmin::ViewHelpers::DownloadFormatLinksHelper
82
+
92
83
  # modified from will_paginate
93
84
  def page_entries_info(options = {})
94
85
  if options[:entry_name]
@@ -60,25 +60,19 @@ module ActiveAdmin
60
60
  end
61
61
 
62
62
  def build_table_header(col)
63
- if sortable? && col.sortable?
64
- build_sortable_header_for(col.title, col.sort_key)
65
- else
66
- th(col.title, :class => (col.data.to_s.downcase.underscore if col.data.is_a?(Symbol)))
67
- end
68
- end
69
-
70
- def build_sortable_header_for(title, sort_key)
71
- classes = Arbre::HTML::ClassList.new(["sortable"])
72
- if current_sort[0] == sort_key
73
- classes << "sorted-#{current_sort[1]}"
74
- end
63
+ classes = Arbre::HTML::ClassList.new
64
+ sort_key = sortable? && col.sortable? && col.sort_key
75
65
 
76
- header_class = title.downcase.underscore
66
+ classes << 'sortable' if sort_key
67
+ classes << "sorted-#{current_sort[1]}" if sort_key && current_sort[0] == sort_key
68
+ classes << col.html_class
77
69
 
78
- classes << header_class
79
-
80
- th :class => classes do
81
- link_to(title, params.merge(:order => "#{sort_key}_#{order_for_sort_key(sort_key)}").except(:page))
70
+ if sort_key
71
+ th :class => classes do
72
+ link_to(col.pretty_title, params.merge(:order => "#{sort_key}_#{order_for_sort_key(sort_key)}").except(:page))
73
+ end
74
+ else
75
+ th(col.pretty_title, :class => classes)
82
76
  end
83
77
  end
84
78
 
@@ -90,7 +84,7 @@ module ActiveAdmin
90
84
  end
91
85
 
92
86
  def build_table_cell(col, item)
93
- td(:class => (col.data.to_s.downcase if col.data.is_a?(Symbol))) do
87
+ td(:class => col.html_class) do
94
88
  rvalue = call_method_or_proc_on(item, col.data, :exec => false)
95
89
  if col.data.is_a?(Symbol)
96
90
  rvalue = pretty_format(rvalue)
@@ -128,12 +122,13 @@ module ActiveAdmin
128
122
 
129
123
  class Column
130
124
 
131
- attr_accessor :title, :data
125
+ attr_accessor :title, :data , :html_class
132
126
 
133
127
  def initialize(*args, &block)
134
128
  @options = args.extract_options!
135
129
 
136
- @title = pretty_title args[0]
130
+ @title = args[0]
131
+ @html_class = @options.delete(:class) || @title.to_s.downcase.underscore.gsub(/ +/,'_')
137
132
  @data = args[1] || args[0]
138
133
  @data = block if block
139
134
  @resource_class = args[2]
@@ -178,17 +173,16 @@ module ActiveAdmin
178
173
  end
179
174
  end
180
175
 
181
- private
182
-
183
- def pretty_title(raw)
184
- if raw.is_a?(Symbol)
176
+ def pretty_title
177
+ if @title.is_a?(Symbol)
178
+ default_title = @title.to_s.titleize
185
179
  if @options[:i18n] && @options[:i18n].respond_to?(:human_attribute_name)
186
- raw = @options[:i18n].human_attribute_name(raw, :default => raw.to_s.titleize)
180
+ @title = @options[:i18n].human_attribute_name(@title, :default => default_title)
187
181
  else
188
- raw.to_s.titleize
182
+ default_title
189
183
  end
190
184
  else
191
- raw
185
+ @title
192
186
  end
193
187
  end
194
188
  end
@@ -10,7 +10,9 @@ module ActiveAdmin
10
10
  private
11
11
 
12
12
  def powered_by_message
13
- para "Powered by #{link_to("Active Admin", "http://www.activeadmin.info")} #{ActiveAdmin::VERSION}".html_safe
13
+ para t('active_admin.powered_by',
14
+ :active_admin => link_to("Active Admin", "http://www.activeadmin.info"),
15
+ :version => ActiveAdmin::VERSION).html_safe
14
16
  end
15
17
 
16
18
  end
@@ -21,7 +21,7 @@ module ActiveAdmin
21
21
 
22
22
  def build(page_presenter, collection)
23
23
  add_class "index"
24
- resource_selection_toggle_panel
24
+ resource_selection_toggle_panel if active_admin_config.batch_actions.any?
25
25
  collection.each do |obj|
26
26
  instance_exec(obj, &page_presenter.block)
27
27
  end
@@ -37,7 +37,7 @@ module ActiveAdmin
37
37
  protected
38
38
 
39
39
  def build_table
40
- resource_selection_toggle_panel
40
+ resource_selection_toggle_panel if active_admin_config.batch_actions.any?
41
41
  table :class => "index_grid" do
42
42
  collection.in_groups_of(number_of_columns).each do |group|
43
43
  build_row(group)
@@ -24,7 +24,7 @@ module ActiveAdmin
24
24
  within @head do
25
25
  insert_tag Arbre::HTML::Title, [title, render_or_call_method_or_proc_on(self, active_admin_application.site_title)].join(" | ")
26
26
  active_admin_application.stylesheets.each do |style|
27
- text_node(stylesheet_link_tag(style.path, style.options).html_safe)
27
+ text_node(stylesheet_link_tag(style.path, style.options.dup).html_safe)
28
28
  end
29
29
 
30
30
  active_admin_application.javascripts.each do |path|
@@ -63,9 +63,9 @@ module ActiveAdmin
63
63
  end
64
64
 
65
65
  def build_flash_messages
66
- if flash.keys.any?
66
+ if active_admin_flash_messages.any?
67
67
  div :class => 'flashes' do
68
- flash.each do |type, message|
68
+ active_admin_flash_messages.each do |type, message|
69
69
  div message, :class => "flash flash_#{type}"
70
70
  end
71
71
  end
@@ -55,13 +55,7 @@ module ActiveAdmin
55
55
  end
56
56
  end
57
57
 
58
- # TODO: Refactor to new HTML DSL
59
- def build_download_format_links(formats = [:csv, :xml, :json])
60
- links = formats.collect do |format|
61
- link_to format.to_s.upcase, { :format => format}.merge(request.query_parameters.except(:commit, :format))
62
- end
63
- text_node [I18n.t('active_admin.download'), links].flatten.join("&nbsp;").html_safe
64
- end
58
+ include ::ActiveAdmin::ViewHelpers::DownloadFormatLinksHelper
65
59
 
66
60
  def build_table_tools
67
61
  div :class => "table_tools" do
@@ -6,7 +6,6 @@ module ActiveAdmin
6
6
  super(:id => "title_bar")
7
7
  @title = title
8
8
  @action_items = action_items
9
-
10
9
  build_titlebar_left
11
10
  build_titlebar_right
12
11
  end
@@ -27,8 +26,12 @@ module ActiveAdmin
27
26
  end
28
27
 
29
28
  def build_breadcrumb(separator = "/")
30
- links = breadcrumb_links
31
- return if links.empty?
29
+ links = if active_admin_config && active_admin_config.breadcrumb.present?
30
+ instance_exec(controller, &active_admin_config.breadcrumb)
31
+ else
32
+ breadcrumb_links
33
+ end
34
+ return unless links.present? && links.is_a?(::Array)
32
35
  span :class => "breadcrumb" do
33
36
  links.each do |link|
34
37
  text_node link
@@ -42,7 +42,7 @@ module ActiveAdmin
42
42
 
43
43
  if devise_migration_content["def change"]
44
44
  inject_into_file devise_migration_file,
45
- "def migrate(direction)\n super\n # Create a default user\n AdminUser.create!(:email => 'admin@example.com', :password => 'password', :password_confirmation => 'password') if direction == :up\n end\n\n ",
45
+ "def migrate(direction)\n super\n # Create a default user\n #{class_name}.create!(:email => 'admin@example.com', :password => 'password', :password_confirmation => 'password') if direction == :up\n end\n\n ",
46
46
  :before => "def change"
47
47
  elsif devise_migration_content[/def (self.)?up/]
48
48
  inject_into_file devise_migration_file,
@@ -116,12 +116,12 @@ ActiveAdmin.setup do |config|
116
116
  # Enable and disable Batch Actions
117
117
  #
118
118
  config.batch_actions = true
119
-
119
+
120
120
 
121
121
  # == Controller Filters
122
122
  #
123
123
  # You can add before, after and around filters to all of your
124
- # Active Admin resources from here.
124
+ # Active Admin resources and pages from here.
125
125
  #
126
126
  # config.before_filter :do_something_awesome
127
127
 
@@ -134,7 +134,7 @@ ActiveAdmin.setup do |config|
134
134
  #
135
135
  # To load a stylesheet:
136
136
  # config.register_stylesheet 'my_stylesheet.css'
137
-
137
+
138
138
  # You can provide an options hash for more control, which is passed along to stylesheet_link_tag():
139
139
  # config.register_stylesheet 'my_print_stylesheet.css', :media => :print
140
140
  #
@@ -146,4 +146,7 @@ ActiveAdmin.setup do |config|
146
146
  #
147
147
  # Set the CSV builder separator (default is ",")
148
148
  # config.csv_column_separator = ','
149
+ #
150
+ # Set the CSV builder options (default is {})
151
+ # config.csv_options = {}
149
152
  end
@@ -15,6 +15,6 @@ ActiveAdmin.register <%= @user_class %> do
15
15
  f.input :password
16
16
  f.input :password_confirmation
17
17
  end
18
- f.buttons
18
+ f.actions
19
19
  end
20
20
  end
@@ -5,8 +5,8 @@ ActiveAdmin.register_page "Dashboard" do
5
5
  content :title => proc{ I18n.t("active_admin.dashboard") } do
6
6
  div :class => "blank_slate_container", :id => "dashboard_default_message" do
7
7
  span :class => "blank_slate" do
8
- span "Welcome to Active Admin. This is the default dashboard page."
9
- small "To add dashboard sections, checkout 'app/admin/dashboards.rb'"
8
+ span I18n.t("active_admin.dashboard_welcome.welcome")
9
+ small I18n.t("active_admin.dashboard_welcome.call_to_action")
10
10
  end
11
11
  end
12
12
 
@@ -10,7 +10,8 @@ class MoveAdminNotesToComments < ActiveRecord::Migration
10
10
 
11
11
  # Update all the existing comments to the default namespace
12
12
  say "Updating any existing comments to the #{ActiveAdmin.application.default_namespace} namespace."
13
- execute "UPDATE active_admin_comments SET namespace='#{ActiveAdmin.application.default_namespace}'"
13
+ comments_table_name = ActiveRecord::Migrator.proper_table_name("active_admin_comments")
14
+ execute "UPDATE #{comments_table_name} SET namespace='#{ActiveAdmin.application.default_namespace}'"
14
15
  end
15
16
 
16
17
  def self.down
@@ -18,7 +18,7 @@ describe "Memory Leak" do
18
18
  load_defaults!
19
19
  GC.start
20
20
 
21
- count_instances_of(klass).should == count
21
+ count_instances_of(klass).should <= count
22
22
  end
23
23
  end
24
24
 
@@ -9,8 +9,12 @@ gsub_file 'config/database.yml', /\z/, "\ncucumber:\n <<: *test\n database: db
9
9
  gsub_file 'config/database.yml', /\z/, "\ncucumber_with_reloading:\n <<: *test\n database: db/cucumber.sqlite3"
10
10
 
11
11
  # Generate some test models
12
- generate :model, "post title:string body:text published_at:datetime author_id:integer category_id:integer"
12
+ generate :model, "post title:string body:text published_at:datetime author_id:integer category_id:integer starred:boolean"
13
13
  inject_into_file 'app/models/post.rb', " belongs_to :author, :class_name => 'User'\n belongs_to :category\n accepts_nested_attributes_for :author\n", :after => "class Post < ActiveRecord::Base\n"
14
+
15
+ # We'll put this basic delegator in app/models in order to simplify auto-loading.
16
+ copy_file File.expand_path('../templates/post_decorator.rb', __FILE__), "app/models/post_decorator.rb"
17
+
14
18
  # Rails 3.2.3 model generator declare attr_accessible
15
19
  inject_into_file 'app/models/post.rb', " attr_accessible :author\n", :before => "end" if Rails::VERSION::STRING >= '3.2.3'
16
20
  generate :model, "user type:string first_name:string last_name:string username:string age:integer"
@@ -22,7 +26,7 @@ generate :model, 'store name:string'
22
26
 
23
27
  # Generate a model with string ids
24
28
  generate :model, "tag name:string"
25
- gsub_file(Dir['db/migrate/*_create_tags.rb'][0], /\:tags\sdo\s.*/, ":tags, :id => false, :primary_key => :id do |t|\n\t\t\tt.string :id\n" )
29
+ gsub_file(Dir['db/migrate/*_create_tags.rb'][0], /\:tags\sdo\s.*/, ":tags, :id => false, :primary_key => :id do |t|\n\t\t\tt.string :id\n")
26
30
  id_model_setup = <<-EOF
27
31
  self.primary_key = :id
28
32
  before_create :set_id
@@ -71,3 +75,38 @@ route "root :to => 'admin/dashboard#index'"
71
75
  rake "db:migrate"
72
76
  rake "db:test:prepare"
73
77
  run "/usr/bin/env RAILS_ENV=cucumber rake db:migrate"
78
+
79
+ # Setup parallel_tests
80
+ def setup_parallel_tests_database(after, force_insert_same_content = false)
81
+ inject_into_file 'config/database.yml', "<%= ENV['TEST_ENV_NUMBER'] %>", :after => after, :force => force_insert_same_content
82
+ end
83
+
84
+ setup_parallel_tests_database "test.sqlite3"
85
+ setup_parallel_tests_database "cucumber.sqlite3", true
86
+
87
+ # Note: this is hack!
88
+ # Somehow, calling parallel_tests tasks from Rails generator using Thor does not work ...
89
+ # RAILS_ENV variable never makes it to parallel_tests tasks.
90
+ # We need to call these tasks in the after set up hook in order to creates cucumber DBs + run migrations on test & cucumber DBs
91
+ create_file 'lib/tasks/parallel.rake' do
92
+ <<'RAKE'
93
+ namespace :parallel do
94
+ def run_in_parallel(cmd, options)
95
+ count = "-n #{options[:count]}" if options[:count]
96
+ executable = 'parallel_test'
97
+ command = "#{executable} --exec '#{cmd}' #{count} #{'--non-parallel' if options[:non_parallel]}"
98
+ abort unless system(command)
99
+ end
100
+
101
+ desc "create cucumber databases via db:create --> parallel:create_cucumber_db[num_cpus]"
102
+ task :create_cucumber_db, :count do |t, args|
103
+ run_in_parallel("rake db:create RAILS_ENV=cucumber", args)
104
+ end
105
+
106
+ desc "load dumped schema for cucumber databases"
107
+ task :load_schema_cucumber_db, :count do |t,args|
108
+ run_in_parallel("rake db:schema:load RAILS_ENV=cucumber", args)
109
+ end
110
+ end
111
+ RAKE
112
+ end
@@ -51,7 +51,8 @@ append_file "db/seeds.rb", <<-EOF
51
51
  :body => "Blog post \#{i} is written by \#{user.username} about \#{cat.name}",
52
52
  :category => cat,
53
53
  :published_at => published_at,
54
- :author => user
54
+ :author => user,
55
+ :starred => true
55
56
  end
56
57
  EOF
57
58
 
@@ -4,3 +4,5 @@
4
4
  store:
5
5
  one: Bookstore
6
6
  other: Bookstores
7
+ active_admin:
8
+ download: "Download this:"
@@ -0,0 +1,53 @@
1
+ # Minimal example of a decorator
2
+ require_dependency 'post'
3
+
4
+ # DelegateClass(Post) does not delegate attribute methods
5
+ # in some environments:
6
+ # http://travis-ci.org/#!/gregbell/active_admin/jobs/2021466
7
+ #
8
+ class PostDecorator < SimpleDelegator
9
+ delegate :id, :to => :__getobj__
10
+
11
+ def self.decorate(collection_or_object)
12
+ if collection_or_object.respond_to?(:to_ary)
13
+ DecoratedEnumerableProxy.new(collection_or_object)
14
+ else
15
+ new(collection_or_object)
16
+ end
17
+ end
18
+
19
+ def self.model_name
20
+ ActiveModel::Name.new Post
21
+ end
22
+
23
+ def decorator_method
24
+ 'A method only available on the decorator'
25
+ end
26
+
27
+ # Minimal example of decorating a collection.
28
+ # A full example can be found in the draper project:
29
+ # https://github.com/jcasimir/draper/blob/master/lib/draper/decorated_enumerable_proxy.rb
30
+ class DecoratedEnumerableProxy < DelegateClass(ActiveRecord::Relation)
31
+ include Enumerable
32
+
33
+ delegate :as_json, :collect, :map, :each, :[], :all?, :include?, :first, :last, :shift, :to => :decorated_collection
34
+
35
+ def klass
36
+ PostDecorator
37
+ end
38
+
39
+ def wrapped_collection
40
+ __getobj__
41
+ end
42
+
43
+ def decorated_collection
44
+ @decorated_collection ||= wrapped_collection.collect { |member| klass.decorate(member) }
45
+ end
46
+ alias_method :to_ary, :decorated_collection
47
+
48
+ def each(&blk)
49
+ to_ary.each(&blk)
50
+ end
51
+ end
52
+ end
53
+