1 require 'will_paginate'
2 class Admin::ResourceController < ApplicationController
3 extend Radiant::ResourceResponses
4
5 helper_method :model, :current_object, :models, :current_objects, :model_symbol, :plural_model_symbol, :model_class, :model_name, :plural_model_name
6 before_filter :populate_format
7 before_filter :never_cache
8 before_filter :load_models, :only => :index
9 before_filter :load_model, :only => [:new, :create, :edit, :update, :remove, :destroy]
10 after_filter :clear_model_cache, :only => [:create, :update, :destroy]
11
12 cattr_reader :paginated
13 cattr_accessor :default_per_page, :will_paginate_options
14
15 responses do |r|
16 # Equivalent respond_to block for :plural responses:
17 # respond_to do |wants|
18 # wants.xml { render :xml => models }
19 # wants.json { render :json => models }
20 # wants.any
21 # end
22 r.plural.publish(:xml, :json) { render format_symbol => models }
23
24 r.singular.publish(:xml, :json) { render format_symbol => model }
25 r.singular.default { redirect_to edit_model_path if action_name == "show" }
26
27 r.not_found.publish(:xml, :json) { head :not_found }
28 r.not_found.default { announce_not_found; redirect_to :action => "index" }
29
30 r.invalid.publish(:xml, :json) { render format_symbol => model.errors, :status => :unprocessable_entity }
31 r.invalid.default { announce_validation_errors; render :action => template_name }
32
33 r.stale.publish(:xml, :json) { head :conflict }
34 r.stale.default { announce_update_conflict; render :action => template_name }
35
36 r.create.publish(:xml, :json) { render format_symbol => model, :status => :created, :location => url_for(:format => format_symbol, :id => model) }
37 r.create.default { redirect_to continue_url(params) }
38
39 r.update.publish(:xml, :json) { head :ok }
40 r.update.default { redirect_to continue_url(params) }
41
42 r.destroy.publish(:xml, :json) { head :deleted }
43 r.destroy.default { redirect_to continue_url(params) }
44 end
45
46 def index
47 response_for :plural
48 end
49
50 [:show, :new, :edit, :remove].each do |action|
51 class_eval %{
52 def #{action} # def show
53 response_for :singular # response_for :singular
54 end # end
55 }, __FILE__, __LINE__
56 end
57
58 [:create, :update].each do |action|
59 class_eval %{
60 def #{action} # def create
61 model.update_attributes!(params[model_symbol]) # model.update_attributes!(params[model_symbol])
62 response_for :#{action} # response_for :create
63 end # end
64 }, __FILE__, __LINE__
65 end
66
67 def destroy
68 model.destroy
69 response_for :destroy
70 end
71
72 def self.model_class(model_class = nil)
73 @model_class ||= (model_class || self.controller_name).to_s.singularize.camelize.constantize
74 end
75
76 # call paginate_models to declare that will_paginate should be used in the index view
77 # options specified here are accessible in the view by calling will_paginate_options
78 # eg.
79 #
80 # Class MyController < Admin::ResourceController
81 # paginate_models :per_page => 100
82
83 def self.paginate_models(options={})
84 @@paginated = true
85 @@will_paginate_options = options.slice(:class, :previous_label, :next_label, :inner_window, :outer_window, :separator, :container).merge(:param_name => :p)
86 @@default_per_page = options[:per_page]
87 end
88
89 # returns a hash of options that can be passed to will_paginate
90 # the @pagination_for@ helper method calls @will_paginate_options@ unless other options are supplied.
91 #
92 # pagination_for(@events)
93
94 def will_paginate_options
95 self.class.will_paginate_options || {}
96 end
97 helper_method :will_paginate_options
98
99 # a convenience method that returns true if paginate_models has been called on this controller class
100 # and can be used to make display decisions in controller and view
101 def paginated?
102 self.class.paginated == true && params[:pp] != 'all'
103 end
104 helper_method :paginated?
105
106 # return a hash of page and per_page that can be used to build a will_paginate collection
107 # the per_page figure can be set in several ways:
108 # request parameter > declared by paginate_models > default set in config entry @admin.pagination.per_page@ > overall default of 50
109 def pagination_parameters
110 pp = params[:pp] || Radiant.config['admin.pagination.per_page']
111 pp = (self.class.default_per_page || 50) if pp.blank?
112 {
113 :page => (params[:p] || 1).to_i,
114 :per_page => pp.to_i
115 }
116 end
117
118 protected
119
120 def rescue_action(exception)
121 case exception
122 when ActiveRecord::RecordInvalid
123 response_for :invalid
124 when ActiveRecord::StaleObjectError
125 response_for :stale
126 when ActiveRecord::RecordNotFound
127 response_for :not_found
128 else
129 super
130 end
131 end
132
133 def model_class
134 self.class.model_class
135 end
136
137 def model
138 instance_variable_get("@#{model_symbol}") || load_model
139 end
140 alias :current_object :model
141 def model=(object)
142 instance_variable_set("@#{model_symbol}", object)
143 end
144 def load_model
145 self.model = if params[:id]
146 model_class.find(params[:id])
147 else
148 model_class.new()
149 end
150 end
151
152 def models
153 instance_variable_get("@#{plural_model_symbol}") || load_models
154 end
155 alias :current_objects :models
156 def models=(objects)
157 instance_variable_set("@#{plural_model_symbol}", objects)
158 end
159 def load_models
160 self.models = paginated? ? model_class.paginate(pagination_parameters) : model_class.all
161 end
162
163 def model_name
164 model_class.name
165 end
166 def plural_model_name
167 model_name.pluralize
168 end
169 alias :models_name :plural_model_name
170
171 def model_symbol
172 model_name.underscore.intern
173 end
174 def plural_model_symbol
175 model_name.pluralize.underscore.intern
176 end
177 alias :models_symbol :plural_model_symbol
178
179 def humanized_model_name
180 t(model_name.underscore.downcase)
181 end
182
183 def continue_url(options)
184 options[:redirect_to] || (params[:continue] ? {:action => 'edit', :id => model.id} : index_page_for_model)
185 end
186
187 def index_page_for_model
188 parts = {:action => "index"}
189 if paginated? && model && i = model_class.all.index(model)
190 p = (i / pagination_parameters[:per_page].to_i) + 1
191 parts[:p] = p if p && p > 1
192 end
193 parts
194 end
195
196 def edit_model_path
197 method = "edit_admin_#{model_name.underscore}_path"
198 send method.to_sym, params[:id]
199 end
200
201 def announce_validation_errors
202 flash.now[:error] = t("resource_controller.validation_errors")
203 end
204
205 def announce_removed
206 ActiveSupport::Deprecation.warn("announce_removed is no longer encouraged in Radiant 0.9.x.", caller)
207 flash[:notice] = t("resource_controller.removed", :humanized_model_name => humanized_model_name)
208 end
209
210 def announce_not_found
211 flash[:notice] = t("resource_controller.not_found", :humanized_model_name => humanized_model_name)
212 end
213
214 def announce_update_conflict
215 flash.now[:error] = t("resource_controller.update_conflict", :humanized_model_name => humanized_model_name)
216 end
217
218 def clear_model_cache
219 Radiant::Cache.clear if defined?(Radiant::Cache)
220 end
221
222 def format_symbol
223 format.to_sym
224 end
225
226 def format
227 params[:format] || 'html'
228 end
229
230
231 # I would like to set this to expires_in(1.minute, :private => true) to allow for more fluid navigation
232 # but the annoyance for concurrent authors would be too great.
233 def never_cache
234 expires_now
235 end
236
237 # Assist with user agents that cause improper content-negotiation
238 # warn "Remove default HTML format, Accept header no longer used. (#{__FILE__}: #{__LINE__})" if Rails.version !~ /^2\.1/
239 def populate_format
240 params[:format] ||= 'html' unless request.xhr?
241 end
242
243
244 end