Module: Resourceful::Default::Accessors
- Included in:
- Base
- Defined in:
- lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb
Overview
This module contains all sorts of useful methods that allow access to the resources being worked with, metadata about the controller and action, and so forth.
Many of these accessors call other accessors and are called by the default make_resourceful actions. This means that overriding one method can affect everything else.
This can be dangerous, but it can also be very powerful. make_resourceful is designed to take advantage of overriding, so as long as the new methods accomplish the same purpose as the old ones, everything will just work. Even if you make a small mistake, it’s hard to break the controller in any unexpected ways.
For example, suppose your controller is called TagsController, but your model is called PhotoTag. All you have to do is override current_model_name:
def current_model_name
"PhotoTag"
end
Then current_model will return the PhotoTag model, current_object will call PhotoTag.find
, and so forth.
Overriding current_objects and current_object is particularly useful for providing customized model lookup logic.
Instance Method Summary collapse
-
#build_object ⇒ Object
Creates a new object of the type of the current model with the current object’s parameters.
-
#current_model ⇒ Object
The class of the current model.
-
#current_model_name ⇒ Object
The string name of the current model.
-
#current_object ⇒ Object
Returns the object referenced by the id parameter (or the newly-created object for the
new
andcreate
actions). -
#current_objects ⇒ Object
Returns an array of all the objects of the model corresponding to the controller.
-
#ensure_parent_exists ⇒ Object
Renders a 422 error if no parent id is given.
-
#instance_variable_name ⇒ Object
The name of the instance variable that load_object and load_objects should assign to.
-
#load_object ⇒ Object
Calls current_object and stores the result in an instance variable named after the controller.
-
#load_objects ⇒ Object
Calls current_objects and stores the result in an instance variable named after the controller.
-
#load_parent_object ⇒ Object
Assigns the current parent object, as given by parent_objects, to its proper instance variable, as given by parent_name.
-
#namespaces ⇒ Object
An array of namespaces under which the current controller is.
-
#object_parameters ⇒ Object
Returns the hash passed as HTTP parameters that defines the new (or updated) attributes of the current object.
-
#parent? ⇒ Boolean
Returns true if an appropriate parent id parameter has been supplied.
-
#parent_class_name ⇒ Object
Returns the class name of the current parent.
-
#parent_model ⇒ Object
Returns the model class of the current parent.
-
#parent_name ⇒ Object
Returns the name of the current parent object if a parent id is given, or nil otherwise.
-
#parent_names ⇒ Object
Returns a list of the names of all the potential parents of the current model.
-
#parent_object ⇒ Object
Returns the current parent object for the current object.
-
#plural? ⇒ Boolean
Returns whether the controller is a normal plural controller, implying that there are multiple resources for each parent resource.
-
#plural_action? ⇒ Boolean
Returns whether or not the current action acts upon multiple objects.
-
#polymorphic_parent? ⇒ Boolean
Returns whether the parent (if it exists) is polymorphic.
- #polymorphic_parent_name ⇒ Object
-
#save_failed! ⇒ Object
Declares that the current databse update was not completed successfully.
-
#save_succeeded! ⇒ Object
Declares that the current databse update was completed successfully.
-
#save_succeeded? ⇒ Boolean
Returns whether or not the database update in the
create
,update
, anddestroy
was completed successfully. -
#singular? ⇒ Boolean
Returns whether the controller is a singleton, implying that there is only one such resource for each parent resource.
-
#singular_action? ⇒ Boolean
Returns whether or not the current action acts upon a single object.
Instance Method Details
#build_object ⇒ Object
Creates a new object of the type of the current model with the current object’s parameters. current_object
then returns this object for this action instead of looking up a new object.
This is called automatically by the default make_resourceful actions. You shouldn’t need to use it directly unless you’re creating a new action.
Note that if a parent object exists, the newly created object will automatically be a child of the parent object. For example, on POST /people/4/things,
build_object
current_object.person.id #=> 4
124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 124 def build_object @current_object = if current_model.respond_to? :build current_model.build(object_parameters) else returning(current_model.new(object_parameters)) do |obj| if singular? && parent? obj.send("#{parent_name}_id=", parent_object.id) obj.send("#{parent_name}_type=", parent_object.class.to_s) if polymorphic_parent? end end end end |
#current_model ⇒ Object
The class of the current model. Note that if a parent object exists, this instead returns the association object. For example, in HatsController where Person has_many :hats,
current_model #=> Person.find(params[:person_id]).hats
This is useful because the association object uses duck typing to act like a model class. It supplies a find method that’s automatically scoped to ensure that the object returned is actually a child of the parent, and so forth.
169 170 171 172 173 174 175 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 169 def current_model if !parent? || singular? current_model_name.constantize else parent_object.send(instance_variable_name) end end |
#current_model_name ⇒ Object
The string name of the current model. By default, this is derived from the name of the controller.
139 140 141 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 139 def current_model_name controller_name.singularize.camelize end |
#current_object ⇒ Object
Returns the object referenced by the id parameter (or the newly-created object for the new
and create
actions). For UsersController, it essentially runs User.find(params[:id])
.
However, there are a few important differences. First, this method caches is results in the @current_objects
instance variable. That way, multiple calls won’t run multiple queries.
Second, this method uses the current_model accessor, which provides a lot of flexibility (see the documentation for current_model for details).
Note that this is different for a singleton controller, where there’s only one resource per parent resource. Then this just returns that resource. For example, if Person has_one Hat, then in HatsController current_object essentially runs Person.find(params[:person_id]).hat
.
87 88 89 90 91 92 93 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 87 def current_object @current_object ||= if !parent? || plural? current_model.find(params[:id]) if params[:id] else parent_object.send(instance_variable_name.singularize) end end |
#current_objects ⇒ Object
Returns an array of all the objects of the model corresponding to the controller. For UsersController, it essentially runs User.all
.
However, there are a few important differences. First, this method caches is results in the @current_objects
instance variable. That way, multiple calls won’t run multiple queries.
Second, this method uses the current_model accessor, which provides a lot of flexibility (see the documentation for current_model for details).
53 54 55 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 53 def current_objects @current_objects ||= current_model.all end |
#ensure_parent_exists ⇒ Object
Renders a 422 error if no parent id is given. This is meant to be used with before_filter to ensure that some actions are only called with a parent id. For example:
before_filter :ensure_parent_exists, :only => [:create, :update]
334 335 336 337 338 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 334 def ensure_parent_exists return true if parent? render :text => 'No parent id given', :status => 422 return false end |
#instance_variable_name ⇒ Object
The name of the instance variable that load_object and load_objects should assign to.
153 154 155 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 153 def instance_variable_name controller_name end |
#load_object ⇒ Object
Calls current_object and stores the result in an instance variable named after the controller.
This is called automatically by the default make_resourceful actions. You shouldn’t need to use it directly unless you’re creating a new action.
For example, in UsersController, calling load_object
sets @user = current_object
.
105 106 107 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 105 def load_object instance_variable_set("@#{instance_variable_name.singularize}", current_object) end |
#load_objects ⇒ Object
Calls current_objects and stores the result in an instance variable named after the controller.
This is called automatically by the default make_resourceful actions. You shouldn’t need to use it directly unless you’re creating a new action.
For example, in UsersController, calling load_objects
sets @users = current_objects
.
66 67 68 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 66 def load_objects instance_variable_set("@#{instance_variable_name}", current_objects) end |
#load_parent_object ⇒ Object
Assigns the current parent object, as given by parent_objects, to its proper instance variable, as given by parent_name.
This is automatically added as a before_filter. You shouldn’t need to use it directly unless you’re creating a new action.
322 323 324 325 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 322 def load_parent_object instance_variable_set("@#{parent_name}", parent_object) if parent? instance_variable_set("@#{polymorphic_parent_name}", parent_object) if polymorphic_parent? end |
#namespaces ⇒ Object
An array of namespaces under which the current controller is. For example, in Admin::Content::PagesController:
namespaces #=> [:admin, :content]
148 149 150 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 148 def namespaces @namespaces ||= self.class.name.split('::').slice(0...-1).map(&:underscore).map(&:to_sym) end |
#object_parameters ⇒ Object
Returns the hash passed as HTTP parameters that defines the new (or updated) attributes of the current object. This is only meaningful for create
or update
.
181 182 183 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 181 def object_parameters params[current_model_name.underscore] end |
#parent? ⇒ Boolean
Returns true if an appropriate parent id parameter has been supplied. For example, in HatsController where Rack has_many :hats and Person has_many :hats, if params[:rack_id]
or params[:person_id]
is given,
parent? #=> true
Otherwise, if both params[:rack_id]
and params[:rack_id]
are nil,
parent? #=> false
Note that parents must be declared via Builder#belongs_to.
207 208 209 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 207 def parent? !!parent_name end |
#parent_class_name ⇒ Object
Returns the class name of the current parent. For example, in HatsController where Person has_many :hats, if params[:person_id]
is given,
parent_class_name #=> 'Person'
Note that parents must be declared via Builder#belongs_to.
287 288 289 290 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 287 def parent_class_name parent_name # to init @parent_class_name @parent_class_name ||= parent_name.nil? ? nil : parent_name.camelize end |
#parent_model ⇒ Object
Returns the model class of the current parent. For example, in HatsController where Person has_many :hats, if params[:person_id]
is given,
parent_models #=> Person
Note that parents must be declared via Builder#belongs_to.
299 300 301 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 299 def parent_model parent_class_name.nil? ? nil : parent_class_name.constantize end |
#parent_name ⇒ Object
Returns the name of the current parent object if a parent id is given, or nil otherwise. For example, in HatsController where Rack has_many :hats and Person has_many :hats, if params[:rack_id]
is given,
parent_name #=> "rack"
If params[:person_id]
is given,
parent_name #=> "person"
If both params[:rack_id]
and params[:rack_id]
are nil,
parent_name #=> nil
There are several things to note about this method. First, make_resourceful only supports single-level model nesting. Thus, if neither params[:rack_id]
nor params[:rack_id]
are nil, the return value of parent_name
is undefined.
Second, don’t use parent_name to check whether a parent id is given. It’s better to use the more semantic parent? method.
Third, parent_name caches its return value in the @parent_name
variable, which you should keep in mind if you’re overriding it. However, because @parent_name == nil
could mean that there is no parent or that the method hasn’t been run yet, it uses defined?(@parent_name)
to do the caching rather than @parent_name ||=
. See the source code.
Finally, note that parents must be declared via Builder#belongs_to.
FIXME - Perhaps this logic should be moved to parent?() or another init method
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 248 def parent_name return @parent_name if defined?(@parent_name) @parent_name = parent_names.find { |name| params["#{name}_id"] } if @parent_name.nil? # get any polymorphic parents through :as association inspection names = params.reject { |key, value| key.to_s[/_id$/].nil? }.keys.map { |key| key.chomp("_id") } names.each do |name| begin klass = name.camelize.constantize id = params["#{name}_id"] object = klass.find(id) if association = object.class.reflect_on_all_associations.detect { |association| association.[:as] && parent_names.include?(association.[:as].to_s) } @parent_name = name @polymorphic_parent_name = association.[:as].to_s @parent_class_name = name.camelize @parent_object = object break end rescue end end else @parent_class_name = params["#{parent_name}_type"] @polymorphic_parent = !@parent_class_name.nil? end @parent_name end |
#parent_names ⇒ Object
Returns a list of the names of all the potential parents of the current model. For a non-nested controller, this is []
. For example, in HatsController where Rack has_many :hats and Person has_many :hats,
parents #=> ["rack", "person"]
Note that the parents must be declared via Builder#belongs_to.
192 193 194 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 192 def parent_names self.class.read_inheritable_attribute :parents end |
#parent_object ⇒ Object
Returns the current parent object for the current object. For example, in HatsController where Person has_many :hats, if params[:person_id]
is given,
parent_object #=> Person.find(params[:person_id])
Note that parents must be declared via Builder#belongs_to.
Note also that the results of this method are cached so that multiple calls don’t result in multiple SQL queries.
313 314 315 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 313 def parent_object @parent_object ||= parent_model.nil? ? nil : parent_model.find(params["#{parent_name}_id"]) end |
#plural? ⇒ Boolean
Returns whether the controller is a normal plural controller, implying that there are multiple resources for each parent resource.
Note that the way this is determined is based on the singularity of the controller name, so it may yield false negatives for oddly-named controllers. If this is the case, the singular? method should be overridden.
TODO: maybe we can define plural? and singular? as class_methods, so they are not visible to the world
397 398 399 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 397 def plural? !singular? end |
#plural_action? ⇒ Boolean
Returns whether or not the current action acts upon multiple objects. By default, the only such action is index
.
366 367 368 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 366 def plural_action? PLURAL_ACTIONS.include?(params[:action].to_sym) end |
#polymorphic_parent? ⇒ Boolean
Returns whether the parent (if it exists) is polymorphic
212 213 214 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 212 def polymorphic_parent? !!polymorphic_parent_name end |
#polymorphic_parent_name ⇒ Object
276 277 278 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 276 def polymorphic_parent_name @polymorphic_parent_name end |
#save_failed! ⇒ Object
Declares that the current databse update was not completed successfully. Causes subsequent calls to save_succeeded?
to return false
.
This is mostly meant to be used by the default actions, but it can be used by user-defined actions as well.
360 361 362 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 360 def save_failed! @save_succeeded = false end |
#save_succeeded! ⇒ Object
Declares that the current databse update was completed successfully. Causes subsequent calls to save_succeeded?
to return true
.
This is mostly meant to be used by the default actions, but it can be used by user-defined actions as well.
351 352 353 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 351 def save_succeeded! @save_succeeded = true end |
#save_succeeded? ⇒ Boolean
Returns whether or not the database update in the create
, update
, and destroy
was completed successfully.
342 343 344 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 342 def save_succeeded? @save_succeeded end |
#singular? ⇒ Boolean
Returns whether the controller is a singleton, implying that there is only one such resource for each parent resource.
Note that the way this is determined is based on the singularity of the controller name, so it may yield false positives for oddly-named controllers and need to be overridden.
TODO: maybe we can define plural? and singular? as class_methods, so they are not visible to the world
384 385 386 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 384 def singular? instance_variable_name.singularize == instance_variable_name end |
#singular_action? ⇒ Boolean
Returns whether or not the current action acts upon a single object. By default, this is the case for all actions but index
.
372 373 374 |
# File 'lib/vendor/plugins/make_resourceful/lib/resourceful/default/accessors.rb', line 372 def singular_action? !plural_action? end |