— end filters — #
# File lib/hobo/controller/model.rb, line 883 def model self.class.model end
# File lib/hobo/controller/model.rb, line 574 def attribute_parameters params[(this ? this.class : model).name.underscore] end
# File lib/hobo/controller/model.rb, line 596 def create_response(new_action=:new, options={}) 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}"]) 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
— Lifecycle Actions — #
# File lib/hobo/controller/model.rb, line 703 def creator_page_action(name, options={}, &b) self.this ||= model.new this.exempt_from_edit_checks = true @creator = model::Lifecycle.creator(name) raise Hobo::PermissionDeniedError unless @creator.allowed?(current_user) response_block &b end
# File lib/hobo/controller/model.rb, line 393 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 && !@this.new_record? && object_url(@this)) || # Then the show page of the 'owning' object if there is one object_url(owning_object) || # Last try - the index page for this model object_url(@this.class) || # Give up home_page end
# File lib/hobo/controller/model.rb, line 692 def destroy_response(options={}) if params[:render] hobo_ajax_response || render(:nothing => true) else redirect_to destination_after_submit(this, true, options) end end
# File lib/hobo/controller/model.rb, line 712 def do_creator_action(name, options={}, &b) @creator = model::Lifecycle.creator(name) self.this = @creator.run!(current_user, attribute_parameters) response_block(&b) || do_creator_response(name, options) end
# File lib/hobo/controller/model.rb, line 718 def do_creator_response(name, options) if valid? if params[:render] hobo_ajax_response || render(:nothing => true) else location = destination_after_submit(options) respond_with(self.this) do |wants| wants.html { redirect_to location } end 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) } end end end end
# File lib/hobo/controller/model.rb, line 762 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) || update_response(nil, options) end
# File lib/hobo/controller/model.rb, line 856 def dryml_context this end
— Action implementation helpers — #
# File lib/hobo/controller/model.rb, line 360 def find_instance(options={}) model.user_find(current_user, params[:id]) do |record| yield record if block_given? end end
# File lib/hobo/controller/model.rb, line 450 def find_or_paginate(finder, options) options = options.reverse_merge(:paginate => request_requires_pagination?) do_pagination = options.delete(:paginate) && finder.respond_to?(:paginate) finder = Array.wrap(options.delete(:scope)).inject(finder) { |a, v| a.send(*Array.wrap(v).flatten) } options[:order] = finder.default_order unless options[:order] || finder.try.order_values.present? if do_pagination options.reverse_merge!(:page => params[:page] || 1) finder.paginate(options) else # Equivalent to the old finder.scoped (http://stackoverflow.com/a/18199294) finder.where(nil) end end
# File lib/hobo/controller/model.rb, line 467 def find_owner_and_association(owner_association) owner_name = name_of_auto_action_for(owner_association) refl = model.reflections[owner_association.to_s] id = params["#{owner_name}_id"] owner = refl.klass.find(id) instance_variable_set("@#{owner_association}", owner) [owner, owner.send(model.reverse_reflection(owner_association).name)] end
# File lib/hobo/controller/model.rb, line 591 def flash_notice(message) flash[:notice] = message unless request.xhr? end
Hobo 1.3’s name one uses params, jQuery-UI’s autocomplete uses params and jQuery Tokeninput uses params
# File lib/hobo/controller/model.rb, line 773 def hobo_completions(attribute, finder, options={}) options = options.reverse_merge(:limit => 10, :query_scope => "#{attribute}_contains") options[:param] ||= [:term, :q, :query].find{|k| !params[k].nil?} finder = finder.limit(options[:limit]) unless finder.try.limit_value begin finder = finder.send(options[:query_scope], params[options[:param]]) items = finder.select { |r| r.viewable_by?(current_user) } rescue TypeError # must be a list of methods instead items = [] options[:query_scope].each do |qscope| finder2 = finder.send(qscope, params[options[:param]]) items += finder2.all.select { |r| r.viewable_by?(current_user) } end end if request.xhr? if options[:param] == :q render :json => items.map {|i| {:id => "@#{i.send(i.class.primary_key)}", :name => i.send(attribute)}} else render :json => items.map {|i| i.send(attribute)} end else render :text => "<ul>\n" + items.map {|i| "<li>#{i.send(attribute)}</li>\n"}.join + "</ul>" end end
# File lib/hobo/controller/model.rb, line 545 def hobo_create(*args, &b) options = args.extract_options! attributes = options[:attributes] || attribute_parameters || {} if self.this ||= args.first this.user_update_attributes(current_user, attributes) else 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
# File lib/hobo/controller/model.rb, line 559 def hobo_create_for(owner_association, *args, &b) options = args.extract_options! owner, association = find_owner_and_association(owner_association) attributes = options[:attributes] || attribute_parameters || {} if self.this ||= args.first this.user_update_attributes(current_user, attributes) else 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
# File lib/hobo/controller/model.rb, line 683 def hobo_destroy(*args, &b) options = args.extract_options! 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"]) response_block(&b) || destroy_response(options, &b) end
# File lib/hobo/controller/model.rb, line 511 def hobo_edit(*args, &b) hobo_show(*args, &b) end
— Action implementations — #
# File lib/hobo/controller/model.rb, line 482 def hobo_index(*args, &b) options = args.extract_options! finder = args.first || model self.this ||= find_or_paginate(finder, options) response_block(&b) || index_response end
# File lib/hobo/controller/model.rb, line 490 def hobo_index_for(owner, *args, &b) options = args.extract_options! owner, association = find_owner_and_association(owner) finder = args.first || association self.this ||= find_or_paginate(finder, options) response_block(&b) || index_response end
# File lib/hobo/controller/model.rb, line 515 def hobo_new(record=nil, &b) self.this ||= record || model.user_new(current_user, attribute_parameters) response_block(&b) || show_response end
# File lib/hobo/controller/model.rb, line 538 def hobo_new_for(owner, record=nil, &b) owner, association = find_owner_and_association(owner) self.this ||= record || association.user_new(current_user, attribute_parameters) response_block(&b) || show_response end
# File lib/hobo/controller/model.rb, line 800 def hobo_reorder ordering = params["#{model.name.underscore}_ordering"] if ordering ordering.each_with_index do |id, position| object = model.find(id) object.user_update_attributes!(current_user, object.position_column => position+1) end hobo_ajax_response || render(:nothing => true) else render :nothing => true end end
# File lib/hobo/controller/model.rb, line 499 def hobo_show(*args, &b) options = args.extract_options! self.this ||= args.first if this.nil? self.this = find_instance(options) unless (parms=attribute_parameters).blank? this.with_acting_user(current_user) { this.attributes = parms } end end response_block(&b) || show_response end
# File lib/hobo/controller/model.rb, line 624 def hobo_update(*args, &b) options = args.extract_options! self.this ||= args.first || find_instance changes = options[:attributes] || attribute_parameters or raise RuntimeError, t("hobo.messages.update.no_attribute_error", :default=>["No update specified in params"]) if this.user_update_attributes(current_user, changes) # Ensure current_user isn't out of date @current_user = @this if @this == current_user end response_block(&b) || update_response(nil, options) end
# File lib/hobo/controller/model.rb, line 529 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
# File lib/hobo/controller/model.rb, line 367 def invalid?; !valid?; end
# File lib/hobo/controller/model.rb, line 476 def name_of_auto_action_for(owner_association) model.reflections[owner_association.to_s].macro == :has_many ? owner_association.to_s.singularize : owner_association end
# File lib/hobo/controller/model.rb, line 579 def new_for_create(attributes = {}) type_param = subtype_for_create create_model = type_param ? type_param.constantize : model create_model.user_new(current_user, attributes) end
# File lib/hobo/controller/model.rb, line 425 def owning_object method = @this.class.view_hints.parent method ? @this.send(method) : nil end
# File lib/hobo/controller/model.rb, line 337 def parse_sort_param(*args) _, desc, field = *params[:sort]._?.match(/^(-)?([a-z0-9_]+(?:\.[a-z0-9_]+)?)$/) if field hash = args.extract_options! db_sort_field = (hash[field] || hash[field.to_sym] || (field if field.in?(args) || field.to_sym.in?(args))).to_s unless db_sort_field.blank? if db_sort_field == field && field.match(/\./) fields = field.split(".", 2) db_sort_field = "#{fields[0].pluralize}.#{fields[1]}" end @sort_field = field @sort_direction = desc ? "desc" : "asc" "#{db_sort_field} #{@sort_direction}" end end end
— Response helpers — #
# File lib/hobo/controller/model.rb, line 817 def permission_denied(error) self.this = true # Otherwise this gets sent user_view logger.info "Hobo: Permission Denied! (#{error.inspect})" @permission_error = error if self.class.superclass.method_defined?("permission_denied") super else respond_to do |wants| wants.html do if render :permission_denied, :status => 403 # job done else render :text => t("hobo.messages.permission_denied", :default=>["Permission Denied"]), :status => 403 end end wants.js do render :text => t("hobo.messages.permission_denied", :default=>["Permission Denied"]), :status => 403 end end end end
# File lib/hobo/controller/model.rb, line 743 def prepare_transition(name, options) key = options.delete(:key) || params[:key] # we don't use find_instance here, as it fails for key_holder transitions on objects that Guest can't view record = model.find(params[:id]) record.exempt_from_edit_checks = true record.lifecycle.provided_key = key self.this = record this.lifecycle.find_transition(name, current_user) or raise Hobo::PermissionDeniedError end
# File lib/hobo/controller/model.rb, line 373 def re_render_form(default_action=nil) if params[:page_path] @invalid_record = this controller, action = controller_action_from_page_path # Hack fix for Bug 477. See also bug 489. if self.class.name == "#{controller.camelize}Controller" && action == "index" params['action'] = 'index' self.action_name = 'index' self.this = find_or_paginate(model, {}) index else render :template => "#{controller}/#{action}" end else render :action => default_action end end
# File lib/hobo/controller/model.rb, line 861 def render_with_hobo_model(*args, &block) options = args.extract_options! self.this = options[:object] if options[:object] # this causes more problems than it solves, and Tom says it's not supposed to be here # this.user_view(current_user) if this && this.respond_to?(:user_view) render_without_hobo_model(*args + [options], &block) end
# File lib/hobo/controller/model.rb, line 445 def request_requires_pagination? request.format.not_in?(DONT_PAGINATE_FORMATS) && model.view_hints.paginate? end
# File lib/hobo/controller/model.rb, line 431 def response_block(&b) if b if b.arity == 1 respond_to do |format| yield format end else yield end performed? end end
— filters — #
# File lib/hobo/controller/model.rb, line 871 def set_no_cache_headers headers["Pragma"] = "no-cache" #headers["Cache-Control"] = ["must-revalidate", "no-cache", "no-store"] #headers["Cache-Control"] = "no-cache" headers["Cache-Control"] = "no-store" headers["Expires"] ='0' end
# File lib/hobo/controller/model.rb, line 520 def show_response if request.xhr? && params[:render] hobo_ajax_response render :nothing => true unless performed? else respond_with(self.this) end end
# File lib/hobo/controller/model.rb, line 586 def subtype_for_create model.has_inheritance_column? && (t = params['type']) && t.in?(model.send(:descendants).*.name) and t end
# File lib/hobo/controller/model.rb, line 840 def this @this ||= (instance_variable_get("@#{model.name.demodulize.underscore}") || instance_variable_get("@#{model.name.demodulize.underscore.pluralize}")) end
# File lib/hobo/controller/model.rb, line 846 def this=(object) ivar = if object.is_a?(Array) || object.respond_to?(:member_class) (object.try.member_class || model).name.demodulize.underscore.pluralize else object.class.name.demodulize.underscore end @this = instance_variable_set("@#{ivar}", object) end
# File lib/hobo/controller/model.rb, line 756 def transition_page_action(name, options={}, &b) @transition = prepare_transition(name, options) response_block &b end
typically used like this: def update
hobo_update do if params[:foo]==17 render_my_way else update_response # let Hobo handle it all end end
end
parameters:
valid is a cache of valid? options is passed through to destination_after_submit
# File lib/hobo/controller/model.rb, line 653 def update_response(valid=nil, options={}) # valid? can be expensive, cache it valid = valid? if valid.nil? 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.update.error", :default=>["There was a problem with that change\\n#{errors}"], :errors=>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 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
# File lib/hobo/controller/model.rb, line 370 def valid?; this.errors.empty?; end
# File lib/hobo/controller/model.rb, line 56 def self.all_controllers(subsite=nil, force=false) controller_dirs = ["#{Rails.root}/app/controllers"] + Hobo.engines.map { |e| "#{e}/app/controllers" } # Load every controller in app/controllers/<subsite>... @controllers_loaded ||= {} if force || !@controllers_loaded[subsite] controller_dirs.each do |controller_dir| dir = "#{controller_dir}#{'/' + subsite if subsite}" if File.directory?(dir) Dir.entries(dir).each do |f| if f =~ /^[a-zA-Z_][a-zA-Z0-9_]*_controller\.rb$/ name = f.remove(/.rb$/).camelize name = "#{subsite.camelize}::#{name}" if subsite name.constantize end end end end @controllers_loaded[subsite] = true end # ...but only return the ones that registered themselves names = (@controller_names || []).select { |n| subsite ? n =~ /^#{subsite.camelize}::/ : n !~ /::/ } names.map do |name| name.safe_constantize || (@controller_names.delete name; nil) end.compact end
# File lib/hobo/controller/model.rb, line 17 def included(base) base.class_eval do @auto_actions ||= {} inheriting_cattr_reader :web_methods => [], :show_actions => [], :index_actions => [], :owner_actions => {} extend ClassMethods helper_method :model, :current_user before_filter :set_no_cache_headers rescue_from ActiveRecord::RecordNotFound, :with => :not_found unless Rails.env.development? 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 register_controller(base) subsite = base.name.include?("::") ? base.name.split("::").first.underscore : nil base.model.hobo_controller[subsite] = base Hobo::Controller.included_in_class(base) end
# File lib/hobo/controller/model.rb, line 50 def self.register_controller(controller) @controller_names ||= Set.new @controller_names << controller.name end