diff --git a/hobo/CHANGES-1.4.txt b/hobo/CHANGES-1.4.txt index 52e55abe6..98b019081 100644 --- a/hobo/CHANGES-1.4.txt +++ b/hobo/CHANGES-1.4.txt @@ -646,6 +646,14 @@ The signature for the function update_response and friends has changed. This s end end +## default controller actions now use respond_with + +All Hobo model controller actions now use [respond_with](http://apidock.com/rails/ActionController/MimeResponds/respond_with) where appropriate. This means that you can create an API interface for a controller simply by adding: + + respond_to :html, :json, :xml + +See [respond_to](http://apidock.com/rails/ActionController/MimeResponds/ClassMethods/respond_to) and Google for "respond_with" for more information. + ### before-unload `
` has gained a new option, before-unload, which adds an diff --git a/hobo/TODO-1.4.txt b/hobo/TODO-1.4.txt index bbd3111de..76c7a121c 100644 --- a/hobo/TODO-1.4.txt +++ b/hobo/TODO-1.4.txt @@ -45,9 +45,6 @@ you notice any such omissions, please let us know, it is easy to fix.. * multiple file support for AJAX uploads * cache: redis support * fixup deprecation warnings - * port to Rails 3.2 and/or 4.0 - * nuke any remaining prototype code - * add a sane default for non-AJAX JSON requests. * trawl the lighthouse && pull requests * steal the tags from Portal * fixup hobo-contrib @@ -59,4 +56,4 @@ you notice any such omissions, please let us know, it is easy to fix.. * create a bootstrap theme * add theme chooser to setup wizard * add support for has-one - * convert old Hobo plugins: imaginary-dryml, hoboyui + * convert old Hobo plugins: imaginary-dryml, hoboyui, nice theme diff --git a/hobo/lib/hobo/controller.rb b/hobo/lib/hobo/controller.rb index 424ac54bb..ae7451b64 100644 --- a/hobo/lib/hobo/controller.rb +++ b/hobo/lib/hobo/controller.rb @@ -107,15 +107,6 @@ def ajax_update_response(render_specs, results={}, options={}) render :js => page end - # use this function to send arbitrary bits of javascript - def ajax_response(response, options) - page = options[:preamble] || "var _update = typeof Hobo == 'undefined' ? Element.update : Hobo.updateElement;\n" - page << response - page << options[:postamble] if options[:postamble] - render :js => page - end - - # dryml does not use layouts def action_has_layout? false diff --git a/hobo/lib/hobo/controller/model.rb b/hobo/lib/hobo/controller/model.rb index ab862ce59..f3fc017f9 100644 --- a/hobo/lib/hobo/controller/model.rb +++ b/hobo/lib/hobo/controller/model.rb @@ -32,6 +32,8 @@ def included(base) rescue_from Hobo::PermissionDeniedError, :with => :permission_denied rescue_from Hobo::Model::Lifecycles::LifecycleKeyError, :with => :permission_denied + respond_to :html + alias_method_chain :render, :hobo_model end @@ -386,12 +388,25 @@ def re_render_form(default_action=nil) end - def destination_after_submit(record=this, destroyed=false) + def destination_after_submit(*args) + options = args.extract_options! + destroyed = args[1] after_submit = params[:after_submit] # The after_submit post parameter takes priority (after_submit == "stay-here" ? url_for_page_path : after_submit) || + # Then try options[:redirect] + ((o=options[:redirect]) && begin + if o.is_a?(Symbol) + object_url(@this, o) + elsif o.is_a?(String) || o.is_a?(Hash) + o + else + object_url(*Array(o)) + end + end) + # Then try the record's show page (!destroyed && object_url(@this)) || @@ -411,24 +426,6 @@ def owning_object end - def redirect_after_submit(*args) - options = args.extract_options! - o = options[:redirect] - if o - url = if o.is_a?(Symbol) - object_url(this, o) - elsif o.is_a?(String) || o.is_a?(Hash) - o - else - object_url(*Array(o)) - end - redirect_to url - else - redirect_to destination_after_submit(*args) - end - end - - def response_block(&b) if b respond_to do |format| @@ -521,6 +518,8 @@ def show_response if request.xhr? && params[:render] hobo_ajax_response render :nothing => true unless performed? + else + respond_with(self.this) end end @@ -528,6 +527,8 @@ def index_response if request.xhr? && params[:render] hobo_ajax_response(:page => :blah) render :nothing => true unless performed? + else + respond_with(self.this) end end @@ -547,6 +548,7 @@ def hobo_create(*args, &b) self.this = new_for_create(attributes) this.user_save(current_user) end + flash_notice (ht( :"#{@this.class.to_s.underscore}.messages.create.success", :default=>["The #{@this.class.model_name.human} was created successfully"])) if valid? response_block(&b) || create_response(:new, options) end @@ -561,6 +563,7 @@ def hobo_create_for(owner_association, *args, &b) self.this = association.new(attributes) this.save end + flash_notice (ht( :"#{@this.class.to_s.underscore}.messages.create.success", :default=>["The #{@this.class.model_name.human} was created successfully"])) if valid? response_block(&b) || create_response(:"new_for_#{name_of_auto_action_for(owner_association)}", options) end @@ -587,30 +590,31 @@ def flash_notice(message) end - def create_response(new_action, options={}, &b) - flash_notice (ht( :"#{@this.class.to_s.underscore}.messages.create.success", :default=>["The #{@this.class.model_name.human} was created successfully"])) if valid? + def create_response(new_action, options={}) + valid = valid? # valid? can be expensive + if params[:render] + if (params[:render_options] && params[:render_options][:errors_ok]) || valid + hobo_ajax_response - response_block(&b) or begin - valid = valid? # valid? can be expensive - if params[:render] - if (params[:render_options] && params[:render_options][:errors_ok]) || valid - hobo_ajax_response - - # Maybe no ajax requests were made - render :nothing => true unless performed? - else - errors = @this.errors.full_messages.join('\n') - message = ht( :"#{this.class.to_s.underscore}.messages.create.error", :errors=>errors,:default=>["Couldn't create the #{this.class.name.titleize.downcase}.\n #{errors}"]) - ajax_response("alert('#{message}');", params[:render_options]) - end - else - if valid - redirect_after_submit options - else - re_render_form(new_action) - end - end - end + # Maybe no ajax requests were made + render :nothing => true unless performed? + else + errors = @this.errors.full_messages.join('\n') + message = ht( :"#{this.class.to_s.underscore}.messages.create.error", :errors=>errors,:default=>["Couldn't create the #{this.class.name.titleize.downcase}.\n #{errors}"]) + render :js => "alert(#{message.to_json});\n" + end + else + location = destination_after_submit(options) + respond_with(self.this, :location => location) do |format| + format.html do + if valid + redirect_to location + else + re_render_form(new_action) + end + end + end + end end @@ -642,7 +646,7 @@ def hobo_update(*args, &b) # # parameters: # valid is a cache of valid? - # options is passed through to redirect_after_submit + # options is passed through to destination_after_submit def update_response(valid=nil, options={}) # valid? can be expensive, cache it valid = valid? if valid.nil? @@ -656,15 +660,19 @@ def update_response(valid=nil, options={}) errors = @this.errors.full_messages.join('\n') message = ht(:"#{@this.class.to_s.underscore}.messages.update.error", :default=>["There was a problem with that change\\n#{errors}"], :errors=>errors) - ajax_response("alert('#{message}');", params[:render_options]) + render :js => "alert(#{message.to_json});\n" end else - if valid - flash_notice (ht(:"#{@this.class.to_s.underscore}.messages.update.success", :default=>["Changes to the #{@this.class.model_name.human} were saved"])) - - redirect_after_submit options - else - re_render_form(:edit) + location = destination_after_submit(options) + respond_with(self.this, :location => location) do |format| + format.html do + if valid + flash_notice (ht(:"#{@this.class.to_s.underscore}.messages.update.success", :default=>["Changes to the #{@this.class.model_name.human} were saved"])) + redirect_to location + else + re_render_form(:edit) + end + end end end end @@ -674,16 +682,16 @@ def hobo_destroy(*args, &b) self.this ||= args.first || find_instance this.user_destroy(current_user) flash_notice ht( :"#{model.to_s.underscore}.messages.destroy.success", :default=>["The #{model.name.titleize.downcase} was deleted"]) - destroy_response(options, &b) + response_block(&b) || destroy_response(options, &b) end - def destroy_response(options={}, &b) - response_block(&b) or - respond_to do |wants| - wants.html { redirect_after_submit(this, true, options) } - wants.js { hobo_ajax_response || render(:nothing => true) } - end + def destroy_response(options={}) + if params[:render] + hobo_ajax_response || render(:nothing => true) + else + respond_with(self.this, :location => destination_after_submit(this, true, options)) + end end @@ -701,26 +709,32 @@ def creator_page_action(name, options={}, &b) def do_creator_action(name, options={}, &b) @creator = model::Lifecycle.creator(name) self.this = @creator.run!(current_user, attribute_parameters) - response_block(&b) or - if valid? - respond_to do |wants| - wants.html { redirect_after_submit(options) } - wants.js { hobo_ajax_response || render(:nothing => true) } - end + response_block(&b) || do_creator_response(name, options) + end + + def do_creator_response(name, options) + if valid? + if params[:render] + hobo_ajax_response || render(:nothing => true) else - this.exempt_from_edit_checks = true - respond_to do |wants| - # errors is used by the translation helper, ht, below. - errors = this.errors.full_messages.join("\n") + location = destination_after_submit(options) + respond_with(self.this, :location => location) + end + else + this.exempt_from_edit_checks = true + if params[:render] && params[:render_options] && params[:render_options][:errors_ok] + hobo_ajax_response + render :nothing => true unless performed? + else + # errors is used by the translation helper, ht, below. + errors = this.errors.full_messages.join("\n") + respond_with(self.this) do |wants| wants.html { re_render_form(name) } - wants.js { render(:status => 500, - :text => ht(:"#{@this.class.to_s.underscore}.messages.creator.error", :default=>["Couldn't do creator #{name}.\n#{errors}"], :name=>name, :errors=>errors) - )} end end + end end - def prepare_transition(name, options) key = options.delete(:key) || params[:key] @@ -744,25 +758,9 @@ def do_transition_action(name, *args, &b) options = args.extract_options! @transition = prepare_transition(name, options) @transition.run!(this, current_user, attribute_parameters) - response_block(&b) or - if valid? - respond_to do |wants| - wants.html { redirect_after_submit(options) } - wants.js { hobo_ajax_response || render(:nothing => true) } - end - else - respond_to do |wants| - # errors is used by the translation helper, ht, below. - errors = this.errors.full_messages.join("\n") - wants.html { re_render_form(name) } - wants.js { render(:status => 500, - :text => ht(:"#{@this.class.to_s.underscore}.messages.transition.error", :default=>["Couldn't do transition #{name}.\n#{errors}"], :name=>name, :errors=>errors) - )} - end - end + response_block(&b) || update_response(nil, options) end - # --- Miscelaneous Actions --- # # Hobo 1.3's name one uses params[:query], jQuery-UI's autocomplete