-
-
Save mudge/2007669 to your computer and use it in GitHub Desktop.
class MyController < ApplicationController | |
def show | |
@model = load_model | |
end | |
def edit | |
@model = load_model | |
end | |
private | |
def load_model | |
Model.find(params[:id]) | |
end | |
end |
class MyController < ApplicationController | |
before_filter :load_model, :only => [:show, :edit, :update, :destroy] | |
def show | |
end | |
def edit | |
end | |
private | |
def load_model | |
@model = Model.find(params[:id]) | |
end | |
end |
class MyController < ApplicationController | |
helper_method :model | |
def show | |
# Use +model+ freely | |
end | |
def edit | |
# Use +model+ freely | |
end | |
private | |
def model | |
@model ||= Model.find(params[:id]) | |
end | |
end |
class MyController < ApplicationController | |
def show | |
load_model | |
end | |
def edit | |
load_model | |
end | |
private | |
def load_model | |
@model = Model.find(params[:id]) | |
end | |
end |
@ohthatjames I agree that a test should fail in this case but I'm not sure about using the presence of a safety net as your sole way of informing developers of the design, viz. someone could ostensibly create a new action and you'd be entirely reliant on your test coverage to teach them how the system works. Can we not hope for greater clarity in the code itself?
I'm reminded of another comment of yours regarding avoiding deeply nested contexts in tests for this same reason: the lack of transparency about what set up is actually occurring.
Following the Ruby Rogues discussion about Objects in Rails, I've added another approach: using helper_method
to avoid exposing instance variables altogether. This has the added benefit of working across views.
In the common quest of a more better approach, the helper methods are a quite a interesting approach.
The helper methods though, as intended by Rails, break the encapsulation.
They also represent a problem for the single responsibility, because their presence is not always required by the controller instance, but dictated by the needs of the template.
As "cross object" instance variables which belong to 2 different objects at the same time, they are somehow pseudo-global entities instead of being injected.
When it comes to testing, they still need to be stubbed out as part of the context.
Also, if they assign instance variables, the latter will be again available in the view, representing a further temptation that only the developer's discipline can prevent :-)
Unfortunately all this is due to the very nature of how Rails works.
Furthermore, it's also related to the legacy of the original ERB implementation from the standard library. An ERB object only accepts a Binding object, and raises an error if the argument is of a different type. That probably encouraged this historical instance variable based approach in Rails.
Erubis (the default ERB engine as of Rails 3.0) does better in this respect, because you can also pass a Hash to the result
.
template = Erubis::Eruby.new("<%= omg %>, this is a <%= message %>!!!")
object_to_be_rendered = {omg: "ZOMG!", message: "different kind of template"}
template.result(object_to_be_rendered)
# => "ZOMG!, this is a different kind of template!!!"
This allows to decide to rely on only one simple context object for the view, and this encourages to build that object as dumb as possible, probably a presenter on top of a database-backed model in the Rails common scenario.
This approach seems closer to the one we find in the Javascript templating systems. For me it has the advantage that I can easily stub it out not as pseudo-global context (difficult) but as a parameter to pass to the subject under test (easy).
It's also interesting that in we can get something similar in Rails making explicit use of the :locals
option
render :template => "my/template", :locals => {omg: "ZOMG!", message: "different kind of template"}
The issue is how would you deal with global data. Like menu/cart etc if not using before filter
It's also interesting to see how Ramaze approaches the problem, namely relying on calls to
super
http://ramaze.net/documentation/file.controllers.htmlI make no mystery of my predilection for Ramaze over Sinatra.