Referencing objects in extended views

quaternion edited this page Apr 19, 2012 · 4 revisions

If you're trying to DRY up your views, you may be extending views within other views. For example, you may have an index.rabl view that just references a show.rabl view.

# index.rabl
object @rosters

extends "rosters/show"
# show.rabl
object @roster

attributes :id, :first, :last, :number, :position

However, things get tricky if you need to reference the object within your layout, to provide conditional displays of data. For example, if you have a view like this:

# show.rabl
object @roster

attributes :id, :first, :last, :number, :position

child ((@current_roster == self || @current_roster.is_manager) ? @roster.roster_telephones : @roster.roster_telephones.pub) => :telephone_numbers do
  extends "telephone_numbers/index"
end

You will find that if you visit /rosters/show, you get the information that you expect. However, if you visit /rosters/index, you will get an error about "no such method roster_telephones for nil".

This is because, unlike you may expect, the @roster object is not getting set when the show.rabl template is extended from within the index.rabl view.

Instead, according to @nesquena, you should use the node operation, which will allow you to execute a block that references the object. This code works:

# show.rabl
object @roster

attributes :id, :first, :last, :number, :position

node :telephone_numbers do |roster|
 phone_numbers = ((@current_roster == roster || @current_roster.is_manager) ? roster.roster_telephones : roster.roster_telephones.pub)
 partial("telephone_numbers/index", :object => phone_numbers)
end

This method will allow you to access the primary object in your view, no matter where it's called from.