purpose
provide DRY solution for rendering (or redirecting) from controller on invalid request, such as failed validation on create/update
requirements
- jquery js framework
- notifications helper from my earlier post about custom ajax helper:
http://tech.maysora.com/2010/11/rails-custom-ajax-helper-for-jquery.html
codes
application_controller.rb
# render invalid request to show error message depend on request type # example: # render_invalid "Update failed." # ajax: show error notification with message "Update failed." # html: simply render text "Update failed." # render_invalid "Save failed.", :render => {:action => "new"} # ajax: show error notification with message "Save failed." # html: render action new with "Save failed." flash message # render_invalid "Save failed.", :render => {:action => "new"}, :flash => false # same as above but without flash for html # render_invalid "You can't do that.", :redirect_to => {:action => "index"}, :flash => false, :status => :unauthorized # same as above but redirecting to index instead of rendering new for html # and using unauthorized(401) status instead of not_acceptable(406) # render_invalid "Update failed.", :object => @user, :fields_wrapping => true # ajax: show error notification with addition of object's error messages and wrap error fields with div class fieldWithErrors # html: same as ajax minus fields wrapping def render_invalid message="Error.", options={:flash => true} options[:status] ||= :not_acceptable message += "#{options[:object].errors.full_messages.join(' ')}" if options[:object].present? respond_to do |format| format.js do render(:update, :status => options[:status]) do |page| page << notification_error(message) if options[:object].present? && options[:fields_wrapping] page.rjs_clean_error_fields request page.rjs_apply_error_fields options[:object], request end end end format.html do if options[:render].present? flash.now[:error] = message if options[:flash] render options[:render].try(:merge, {:status => options[:status]}) || {:text => message, :status => options[:status]} elsif options[:redirect_to].present? flash[:error] = message if options[:flash] redirect_to options[:redirect_to] else render :text => message, :status => options[:status] end end end end
application_helper.rb (only if you use ajax error fields wrapping)
def rjs_apply_error_fields object, request klass_name = object.class.name.underscore wrapper = "" object.errors.each do |attr, msg| attr = attr.split(".") page << "var $fields = $(), $container = $('\##{klass_name}_#{object.id || "new"}');" page << "if(!$container.length) $container = $('form[action=\\'#{request.request_uri}\\']');" page << "if(!$container.length) $container = $(document);" if attr.length > 1 object.send(attr.first).each_with_index do |x,i| page << "$fields = $fields.add('[id^=#{klass_name}_#{attr.first}_attributes][id$=#{attr.last}]:eq(#{i}),label[for^=#{klass_name}_#{attr.first}_attributes][for$=#{attr.last}]:eq(#{i})', $container)" if x.errors.on(attr.last) end else page << "$fields = $('label[for=#{klass_name}_#{attr}],\##{klass_name}_#{attr}', $container);" end page << "if(!$fields.parent('.fieldWithErrors').length)" page << "$fields.wrap('#{wrapper}')" end end def rjs_clean_error_fields request page << "$('.fieldWithErrors.rjs_#{request.request_method}_#{request.request_uri.gsub(/_=\d+($|&)/, "").parameterize} *').unwrap();" end
usage
users_controller.rb (using non ajax form)#... def create @user = User.new(params[:user]) unless @user.save render_invalid "Failed to register.", :object => @user, :render => {:action => "new"} else flash[:info] = "Registration success, please check your email to activate." redirect_to login_path end end #...users_controller.rb (using ajax form)
#... def update @user = current_user unless @user.update_attributes(params[:user]) render_invalid "Profile update failed.", :object => @user, :fields_wrapping => true end end #...and update.js.rjs (for success behavior)
page << notification_info "Profile updated." page.rjs_clean_error_fields request # used for cleaning error fields wrapping #... other necessary action ...
Tidak ada komentar:
Posting Komentar