Control your layout
April 22nd, 2008
Recently, I added jQuery ajax tabs to an application. To reuse the existing views, I moved the relevant view code to partials for each required action:
render :partial => "entry", :object => journal_entry
and using something like the following in all the relevant controller methods:
format.html { render :partial => 'index' if request.xhr? }
As I added more features to the ajax tabs, I was conditionally rendering partials in every relevant action, as well as creating a partial. Not DRY.
layout provides a much DRY-er solution without the need for the partials. In application.rb:
layout proc { |controller| controller.request.xhr? ? false : 'application' }
When a controller action is invoked, if it is an XHR, no layout will be used. Otherwise the default Rails layout, ‘application’, will be used1.
1 layout expects the name of a layout to be returned from the proc; in this case, I am returning the name of the default. Returning false indicates that no layout should be used.
include and extend
April 6th, 2008
include and extend are commonly used to add methods to Ruby classes, and sometimes, why we use one or the other is not clear. Both do similar operations, but they are not equivalent. extend is more parsimonious adding only methods, includealso includes constants and module variables.
A simple guideline is to include instance methods and to extend class methods.
Here is an example of a class with an instance method and a class method. We have reopened the class so that we can show the differences from the original empty class:
def list_diff(label, list1, list2)
puts "#{label}: #{(list1 - list2).sort.join ' '}"
end
class One
end
methods_from_new = One.new.methods
methods_from_class = One.methods
class One
def instance_method
end
def One.class_method
end
end
list_diff "Instance One.new diff", One.new.methods, methods_from_new
list_diff "Class One diff", One.methods, methods_from_class
when run shows the expected differences:
Instance One.new diff: instance_method
Class One diff: class_method
Now lets create and include a module:
module ModuleTwo
CONSTANT_TWO = "two"
def module_method
end
end
class One
include ModuleTwo
end
list_diff "Instance One.new diff", One.new.methods, methods_from_new
list_diff "Class One diff", One.methods, methods_from_class
puts "has constant? #{One.constants.sort.join ' '}"
when run shows that module_method and CONSTANT_TWO are now available:
Instance One.new diff: instance_method module_method
Class One diff: class_method
has constant? CONSTANT_TWO
And if we extend another module:
module ModuleThree
CONSTANT_THREE = 'three'
def another_module_method
end
end
class One
extend ModuleThree
end
list_diff "Instance One.new diff", One.new.methods, methods_from_new
list_diff "Class One diff", One.methods, methods_from_class
puts "has constant? #{One.constants.sort.join ' '}"
When run, shows that another_module_method is now available as a class method, but CONSTANT_THREE is not1:
Instance One.new diff: instance_method module_method
Class One diff: another_module_method class_method
has constant? CONSTANT_TWO
Finally, we can use include instead of extend to include class methods:
module ModuleFour
CONSTANT_FOUR = 'four'
def yet_another_module_method
end
end
class One
class << self
include ModuleFour
end
end
list_diff "Instance One.new diff", One.new.methods, methods_from_new
list_diff "Class One diff", One.methods, methods_from_class
puts "has constant? #{One.constants.sort.join ' '}"
When run, shows that yet_another_module_method is available as a class method, but CONSTANT_FOUR is not2
Instance One.new diff: instance_method module_method
Class One diff: another_module_method class_method yet_another_module_method
has constant? CONSTANT_TWO
1 Remember, include does more3 than extend.
2 For more details, check Programming Ruby: The Pragmatic Programmer’s Guide .
3 Bonus!
module ModuleFive
CONSTANT_FIVE = 'five'
def module_five
end
end
one = One.new
one.extend ModuleFive
list_diff "Instance extends module", one.methods, methods_from_new
puts "has constant? #{one.class.constants.sort.join ' '}"
Instance extends module: instance_method module_five module_method
has constant? CONSTANT_TWO