# Controller methods over instance variables?

**URL:** <https://www.ruby-forum.com/t/controller-methods-over-instance-variables/183106>\
**Category:** Rails\
**Created:** [February 8, 2010, 9:57am UTC](https://www.ruby-forum.com/t/controller-methods-over-instance-variables/183106 "2010-02-08T09:57:50Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![dukael](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c77e96/32.png) [@dukael](https://www.ruby-forum.com/u/dukael)\
**Post date:** [February 8, 2010, 9:57am UTC](https://www.ruby-forum.com/t/controller-methods-over-instance-variables/183106/1 "2010-02-08T09:57:50Z")

</div>

Hi,

I was thinking whether it would be more elegant for a view to call  
methods on the controller rather than rely on instance variables. I’m  
not really sure what the answer is so thought I would throw it out  
here.  
Perhaps with a basic DSL that makes it explicit what the controller is  
setting, like:

class BooksController \< ActionController::Base  
var :book do  
Book.find(params[:id])  
end  
end

where var:

class ApplicationController…  
def self.var(name, &block)  
define\_method(name, block)  
helper\_method(name)  
# Perhaps memoize too?  
end  
end

Does this violate the rule that the controller should be driving the  
view? Any major disadvantages you can see?

Regards,  
Andrew

---

<div class="post-metadata">

**Author:** ![dukael](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c77e96/32.png) [@dukael](https://www.ruby-forum.com/u/dukael)\
**Post date:** [February 8, 2010, 3:32pm UTC](https://www.ruby-forum.com/t/controller-methods-over-instance-variables/183106/2 "2010-02-08T15:32:55Z")

</div>

Andrew F. wrote:

> Hi,
> 
> I was thinking whether it would be more elegant for a view to call  
> methods on the controller rather than rely on instance variables.

The trouble with this is that controller methods are actions, not  
getters.

> I’m  
> not really sure what the answer is so thought I would throw it out  
> here.  
> Perhaps with a basic DSL that makes it explicit what the controller is  
> setting, like:
> 
> class BooksController \< ActionController::Base  
> var :book do  
> Book.find(params[:id])  
> end  
> end
> 
> where var:
> 
> class ApplicationController…  
> def self.var(name, &block)  
> define\_method(name, block)  
> helper\_method(name)  
> # Perhaps memoize too?  
> end  
> end
> 
> Does this violate the rule that the controller should be driving the  
> view?

Yes. The controller just passes variables to the view.

> Any major disadvantages you can see?

Lots. Does the view even have the controller object in scope? Should  
it need to? What if you want to use the same partial with different  
controllers?

If you want something like this done right, check out Mustache.

> Regards,  
> Andrew

Best,  
–Â  
Marnen Laibow-Koser  
[http://www.marnen.org](http://www.marnen.org)  
removed\_email\_address@domain.invalid

---

<div class="post-metadata">

**Author:** ![dukael](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c77e96/32.png) [@dukael](https://www.ruby-forum.com/u/dukael)\
**Post date:** [February 8, 2010, 3:49pm UTC](https://www.ruby-forum.com/t/controller-methods-over-instance-variables/183106/3 "2010-02-08T15:49:03Z")

</div>

On 09/02/10 01:32, Marnen Laibow-Koser wrote:

> Andrew F. wrote:
> 
> > Hi,
> > 
> > I was thinking whether it would be more elegant for a view to call  
> > methods on the controller rather than rely on instance variables.
> 
> The trouble with this is that controller methods are actions, not  
> getters.

It’s quite common for controllers to have methods which are not directly  
actions. By default they are accessible from URLs but it’s good practice  
to remove the default route anyway. Plus they could be set to protected  
(workaround probably required) or hidden with hide\_action.

> > end
> 
> controllers?

The code above already works, if that answers your question.

As for using partials, well one of reasons for using methods is that  
you’re making the contract between the view and the controller more  
explicit. You already have it with instance variables but I suppose  
using unset instance vars to determine logic in views is a little easier  
albeit less elegant.

Regards,  
Andrew

---

<div class="post-metadata">

**Author:** ![dukael](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c77e96/32.png) [@dukael](https://www.ruby-forum.com/u/dukael)\
**Post date:** [February 8, 2010, 4:09pm UTC](https://www.ruby-forum.com/t/controller-methods-over-instance-variables/183106/4 "2010-02-08T16:09:33Z")

</div>

On Feb 8, 4:44 am, Andrew F. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> var :book do  
> # Perhaps memoize too?  
> end  
> end
> 
> Does this violate the rule that the controller should be driving the  
> view? Any major disadvantages you can see?

I like the idea for several reasons, not the least of which is that we  
use methods in partials. This approach makes it easier to move stuff  
around.

FYI - there’s already a gem that does this with pretty much the same  
syntax you proposed: [GitHub - hashrocket/decent\_exposure: A helper for creating declarative interfaces in controllers](http://github.com/voxdolo/decent_exposure).

Cheers,  
David

---

<div class="post-metadata">

**Author:** ![dukael](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c77e96/32.png) [@dukael](https://www.ruby-forum.com/u/dukael)\
**Post date:** [February 8, 2010, 4:16pm UTC](https://www.ruby-forum.com/t/controller-methods-over-instance-variables/183106/5 "2010-02-08T16:16:02Z")

</div>

Andrew F. wrote:

> On 09/02/10 01:32, Marnen Laibow-Koser wrote:
> 
> > Andrew F. wrote:
> > 
> > > Hi,
> > > 
> > > I was thinking whether it would be more elegant for a view to call  
> > > methods on the controller rather than rely on instance variables.
> > 
> > The trouble with this is that controller methods are actions, not  
> > getters.
> 
> It’s quite common for controllers to have methods which are not directly  
> actions.

Not in my applications. It’s inappropriate to put that much logic in  
the controller.

The only exceptions are things like current\_user, which can’t really  
live anywhere else, and current\_object, which is simply a refactoring of  
controller code. Anything else belongs in a model or a helper.

> By default they are accessible from URLs but it’s good practice  
> to remove the default route anyway. Plus they could be set to protected  
> (workaround probably required) or hidden with hide\_action.

Just don’t have them. It’s conceptually wrong for the way Rails works.

> > > end
> > 
> > controllers?
> 
> The code above already works, if that answers your question.
> 
> As for using partials, well one of reasons for using methods is that  
> you’re making the contract between the view and the controller more  
> explicit.

Perhaps, but it couples the view to one controller, which is wrong.

> You already have it with instance variables but I suppose  
> using unset instance vars to determine logic in views is a little easier  
> albeit less elegant.

Don’t do that much either. Use a helper…

> Regards,  
> Andrew

Best,  
–Â  
Marnen Laibow-Koser  
[http://www.marnen.org](http://www.marnen.org)  
removed\_email\_address@domain.invalid

---

<div class="post-metadata">

**Author:** ![dukael](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c77e96/32.png) [@dukael](https://www.ruby-forum.com/u/dukael)\
**Post date:** [February 9, 2010, 2:10pm UTC](https://www.ruby-forum.com/t/controller-methods-over-instance-variables/183106/6 "2010-02-09T14:10:43Z")

</div>

On Feb 8, 9:16 am, Marnen Laibow-Koser [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > > getters.
> 
> > It’s quite common for controllers to have methods which are not directly  
> > actions.
> 
> Not in my applications. It’s inappropriate to put that much logic in  
> the controller.
> 
> The only exceptions are things like current\_user, which can’t really  
> live anywhere else, and current\_object, which is simply a refactoring of  
> controller code. Anything else belongs in a model or a helper.

I completely agree with Marnen. Fat models, skinny controllers.

Your example is a poor one - it’s certainly appropriate to have a  
@book instance variable in the BooksController. Your instinct is  
correct about lots of instance variables, but they should usually be  
replaced with model instance methods.

---

<div class="post-metadata">

**Author:** ![dukael](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c77e96/32.png) [@dukael](https://www.ruby-forum.com/u/dukael)\
**Post date:** [February 9, 2010, 2:41pm UTC](https://www.ruby-forum.com/t/controller-methods-over-instance-variables/183106/7 "2010-02-09T14:41:10Z")

</div>

On Feb 10, 12:09 am, Adam S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > > > The trouble with this is that controller methods are actions, not  
> > > > controller code. Anything else belongs in a model or a helper.
> 
> I completely agree with Marnen. Fat models, skinny controllers.
> 
> Your example is a poor one - it’s certainly appropriate to have a  
> @book instance variable in the BooksController. Your instinct is  
> correct about lots of instance variables, but they should usually be  
> replaced with model instance methods.

Which is a philosophy I try to subscribe to, but there are many  
instances where I wish to pass multiple values to a view. Perhaps  
because the data is not related in the database or I wish to control  
the dataset that is passed to the view.

For example, if I have a show action for Book, as a convenience I may  
wish to display all the authors on the system that the user can  
access:  
def show  
@book = Book.find(params[:id])  
@all\_authors = Author.all  
end

Is that not reasonable?  
It’s a contrived and simplified example of what I deal with in most  
apps, where I need to get data from unrelated models. Or sometimes I  
may create instance variables from related data (e.g. @authors =  
@book.authors) because I wish to re-use the view in other controllers.

So with my suggestion it could be written as (short block syntax):  
var(:book) { Book.find(params[:id]) }  
var(:all\_authors) { Author.all }  
var(:authors) { book.authors }

Is that better or worse? Harder to read or improves comprehension? Or  
has no purpose at all?

The problem with instance variables is that my view is not inside the  
controller class, so it’s reasonable to ask if it’s appropriate for  
these variables to appear ‘outside’ of their class. It is also easy to  
forget to set the variable in the controller, which is often done on  
purpose and checked for in view logic. But by replacing instance  
variables with methods you are creating a more explicit interface  
contract that you expect one or more controllers to adhere to.

Thanks,  
Andrew

---

<div class="post-metadata">

**Author:** ![dukael](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c77e96/32.png) [@dukael](https://www.ruby-forum.com/u/dukael)\
**Post date:** [February 9, 2010, 2:51pm UTC](https://www.ruby-forum.com/t/controller-methods-over-instance-variables/183106/8 "2010-02-09T14:51:03Z")

</div>

Andrew F. wrote:

> On Feb 10, 12:09ï¿½am, Adam S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:
> 
> > > > > The trouble with this is that controller methods are actions, not  
> > > > > controller code. ï¿½Anything else belongs in a model or a helper.
> > 
> > I completely agree with Marnen. Fat models, skinny controllers.
> > 
> > Your example is a poor one - it’s certainly appropriate to have a  
> > @book instance variable in the BooksController. Your instinct is  
> > correct about lots of instance variables, but they should usually be  
> > replaced with model instance methods.
> 
> Which is a philosophy I try to subscribe to, but there are many  
> instances where I wish to pass multiple values to a view. Perhaps  
> because the data is not related in the database or I wish to control  
> the dataset that is passed to the view.
> 
> For example, if I have a show action for Book, as a convenience I may  
> wish to display all the authors on the system that the user can  
> access:  
> def show  
> @book = Book.find(params[:id])  
> @all\_authors = Author.all  
> end
> 
> Is that not reasonable?

I think it is. You’re doing simple calls to model methods and  
displaying the results.

> It’s a contrived and simplified example of what I deal with in most  
> apps, where I need to get data from unrelated models. Or sometimes I  
> may create instance variables from related data (e.g. @authors =  
> @book.authors) because I wish to re-use the view in other controllers.

Right. If you do a lot of that, perhaps you should introduce a  
presenter.

> So with my suggestion it could be written as (short block syntax):  
> var(:book) { Book.find(params[:id]) }  
> var(:all\_authors) { Author.all }  
> var(:authors) { book.authors }
> 
> Is that better or worse? Harder to read or improves comprehension? Or  
> has no purpose at all?

No purpose at all, I’d say. It seems pretty well equivalent to the  
first form

> The problem with instance variables is that my view is not inside the  
> controller class, so it’s reasonable to ask if it’s appropriate for  
> these variables to appear ‘outside’ of their class.

It’s the Rails way, thanks to some magic. It’s not that the variables  
appear outside their class; rather, the values are copied from the  
controller to the view.

> It is also easy to  
> forget to set the variable in the controller, which is often done on  
> purpose and checked for in view logic.

And the same is true with your proposal.

> But by replacing instance  
> variables with methods you are creating a more explicit interface  
> contract that you expect one or more controllers to adhere to.

No. The two interfaces are equivalent, and created the same contract.  
However, your implementation puts methods in the controller that don’t  
belong there. This is a bad idea.

> Thanks,  
> Andrew

Best,  
–Â  
Marnen Laibow-Koser  
[http://www.marnen.org](http://www.marnen.org)  
removed\_email\_address@domain.invalid
