Use params, not @params

Posted by marcel April 25, 2006 @ 04:30 AM

I still frequently see people in the #rubyonrails channel using @params in their code. For a while now @params has been deprecated in favor of simply params. For those who just skim these blog posts:

Use params, not @params

Why? When you use the params method, it allows for the implementation details of the parameter hash to be changed without breaking existing code. If the implementation of params changed you wouldn’t have to change your code at all because the single point of access for the parameters would just remain the params method. So, the details of what is happening behind the scenes don’t matter. If, though, you use the @params instance variable directly, you’ve broken encapsulation and consequently the ability for the implementation to be easily modified. Methods can be refactored, but instance variables can’t. Today the params method just wraps the @params instance variable, so still using @params works, but that’s not guaranteed to always remain the case.

Same goes for request, response, session, headers, template, cookies and flash.

Basically, a good rule of thumb here is don’t use an instance variable in your controller or view unless you created that instance variable.

Even the old @content_for_layout in the layout is deprecated in favor of just using yield in its place. Also content_for('some_fragment') is now accessed with yield :some_fragment rather than @content_for_some_fragment.

Posted in Documentation, Tricks | 38 comments

Comments

  1. Daniel on 25 Apr 07:10:

    This was news for me. The “still” in your first sentence seems to imply that I ought to know this already. Where is information like this officially published?

    And I’m not sure from your explanation how I should use yield for the layout. Where can I find more information on this? Only the ”@content_for_layout” approach is present in the API docs.

  2. Sam Aaron on 25 Apr 07:45:

    You say:

    “Basically, a good rule of thumb here is don’t use an instance variable in your controller or view unless you created that instance variable.”

    Wouldn’t it make more sense to say:

    “Basically, a good rule of thumb here is to never use an instance variable in your controller. Use getter methods created in your controller instead.”

    As to my mind this will protect yourself from the same types of changes that you described may happen to @params, thus maintaining encapsulation.

    Or is there a case where you see that it’s actually beneficial to use in instance variable directly in your view?

  3. namxam on 25 Apr 09:17:

    Yeah, this is also kind of new. And there is a lot of “wrong”/depreciated code out there. so please post more often about these kind of changes, because otherwise updates will become more and more difficult in the future.

  4. Blu_Matt on 25 Apr 09:26:

    I’m glad to see that there’s ‘official’ word on the @params/params issue, although I do feel that the promotion of yield and the deprecation of content_for_* moves away from DSL into the realms of Rubyisms, a consequence of which might result in a steeper learning curve.

  5. murphy on 25 Apr 09:30:

    yield is a very nice hack for the layout.

    And: We’re all used to get our Rails documentation from everywhere but api.rubyonrails.org, don’t we? ;) Rails is not only the best, but also the most mystic framework in the world.

  6. maurycy on 25 Apr 09:46:

    For instance, there:

    http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/154903

  7. Gavin on 25 Apr 12:19:

    Shame… I kinda like params, etc. It gives them a visual indication that they're "special", both because of the and because of the syntax highlighting. “params” just doesn’t look as cool as ”@params”, but I’ll get used to it…

  8. Gavin on 25 Apr 12:57:

    Sigh… should have previewed. Should have read:

    Shame… I kinda like @params, etc. It gives them a visual indication that they’re “special”, both because of the @ and because of the syntax highlighting. params just doesn’t look as cool as @params, but I’ll get used to it…

  9. Seth on 25 Apr 13:06:

    On the yield issue…

    I like doing things like this:
    <% if @content_for_script %>
    <script type="text/javascript">
    //<![CDATA[
    <%= @content_for_script %>
    //]]>
    </script>
    <% end %>
    

    Using yield :script would require me to re-capture the output in order to check for its presence.

    Is there a best practice for this pattern using the preferred yield syntax?

  10. diego on 25 Apr 13:16:

    Well, altough I never used @params I always used @content_for_<your variable>. the yield thing is news to me. Maybe we can revise the api site to reflect this changes. http://api.rubyonrails.org/classes/ActionView/Helpers/CaptureHelper.html#M000528

  11. diego on 25 Apr 13:17:

    Well, altough I never used @params I always used @content_for_<your variable>. the yield thing is news to me. Maybe we can revise the api site to reflect this changes. http://api.rubyonrails.org/classes/ActionView/Helpers/CaptureHelper.html#M000528

  12. Sam G on 25 Apr 13:57:

    Once we get this cleared up, lets update the documentation and the rails books. More often then not, I use them as reference points, ruby newbie that I am

  13. Sam Leibowitz on 25 Apr 14:22:

    Actually, as much as I think that this change in convention wasn’t handled well, I think it’s probably a good idea, and not only because of what it does for future-proofing. “yield” isn’t terribly difficult to remember, but gives an important insight as to how @content_for_layout actually worked.

    For Ruby newbies: skip to the section on “blocks and iterators” to understand the yield method.

    http://ruby-doc.org/docs/ProgrammingRuby/html/tut_containers.html

  14. Marc Baumbach on 25 Apr 15:19:

    In Rails 1.1.2, doesn’t scaffold generate @content_for_layout in the layouts? I’ve heard of these best practices, but I think a lot of newcomers to Rails would be confused that this is good convention if the framework generates structure that tells them otherwise.

    Is there a plan to change this soon?

  15. zerohalo@gmail.com on 25 Apr 15:36:

    Rails is a great framework – the more I find out about it, the more I like it. The difficulty is finding out about it. You really have to mine to get the gems. Books like “Agile Development on Rails”, “Rails Recipies”, etc. are great for getting started, but what is needed is a more comprehensive documentation of all of Rails’ intricacies. Right now we have the api rdoc (which is okay but not updated and sometimes unclear), the Rails wiki (one of the best places to look for help), and the mailing list (tons of good stuff but hard to find). A team of people documenting the Rails language in all of its glory by gardening the Rails wiki so that it is as accurate and complete as possible and thus becomes the definitive pit-stop for all things Rails—could, in my opinion, help further Rails usage almost more than anything else. I realize I’m offering an idea rather than being part of the solution, but I don’t have enough deep understanding of Rails myself to edit documentation—I’m still very much in the learning stage.

  16. Alex Bunardzic on 25 Apr 16:22:

    I think this is bang on! I love any changes that relieve the burden on my short-term memory buffer (the one that’s installed in my brain).

    Using simple ‘params’ reduces the noise for me.

    As for ‘yield’, it’s beautiful, since it condenses longer ‘content_for’, and eliminates the underscore.

    These may seem like insignificant little things, but they are actually huge. It’s what makes Ruby so special—this painstaking attention to how humans work, think and play.

  17. Marc Baumbach on 25 Apr 16:39:

    Just noticed the changeset for the @content_for_layout to yield as of this morning. Thanks guys!

  18. Matt Pennig on 25 Apr 17:17:

    Seth, here’s how you check for @content_for_script using yield:

    <% if content = yield(:script) %>
    <script type="text/javascript">
    //<![CDATA[
    <%= content %>
    //]]>
    </script>
    <% end %>
    

    That will only capture the content once. The only objection I could see with this is the creation of variables in the view, but that’s pretty trivial in my opinion.

  19. Joe on 25 Apr 19:35:

    @content_for_layout in the layout is deprecated

    Where and when was that mentioned?!?

    And how is yield used instead? Where’s the docs?

  20. David on 25 Apr 19:47:

    Joe: Just use <%= yield %>

  21. David on 25 Apr 19:47:

    Ok that should have had the percents in there, sorry

  22. Kevin Marsh on 25 Apr 20:21:

    zerohalo@gmail.com: Agreed.

    The only thing holding back Rails right now (well, maybe not holding back but rather, slowing down an already speeding train!) is lack of clear, concise documentation.

    IMO, PHP does this the best, and has almost since the start. User-contributed comments, easy searching, and clear, relevant examples will be the trifecta that brings Rails into the “well-documentated” camp.

    Now, who will step up to the plate?

  23. Kevin Marsh on 25 Apr 20:23:

    I should add that clear documentation is especially relevant given the rapid rate Rails is progressing. Things that were kosher 6 months or even 1 month ago are suddenly taboo.

    And, the very beginning should be stuff like, “where to use :symbols in place of ‘single quotes’ or “double quotes” and how to use @instance variables, and so on.

  24. Steve V on 25 Apr 21:11:

    You say to use the params function, because what’s necessary for the implementation in the future may change. Why doesn’t the same stand for content_for? Using yield is not abstracted in any fashion. Shouldn’t there be a content_for(string) method that wraps yield in case something changes with that implementation?

  25. David Heinemeier Hansson on 25 Apr 21:22:

    We’d be happy to get some help getting better documentation out there. Please do find ways to help. Cleaning up the wiki, writing documentation patches, doing articles. Jump on board!

  26. Dagny Gromer on 25 Apr 22:04:

    I just replaced <%= @content_for_layout %> with <%= yield %> in my code and it worked fine. Note that <% yield %> does not produce the desired result. You need the <%= %> tag

    In my former favorite language, using a deprecated construct generated a warning. That might be useful here, but I’m a Ruby newbie and have no idea how this might be implemented.

  27. Reza Soekarno on 26 Apr 04:24:

    +1 to Steve V (#25). Yield doesn’t automatically understandable, not like content_for. Less beauty, then.

  28. Tonio on 26 Apr 10:30:

    <= yield > or <%= yield %> ?

    This is exactly the kind of things difficult to understand for a newbie. I agree with others claiming that books like “Agile Development on Rails�, “Rails Recipies�, etc. need an update to reflect these changes.

  29. Tonio on 26 Apr 10:34:

    Sorry, I understood: the from removed the % percent symbol so we should use <%= yield %>

  30. Tonio on 26 Apr 10:35:

    damn! I meant the form, not the from!

  31. Bob Aman on 26 Apr 12:12:

    Yay! Finally, someone is complaining about this. Been bothing me for a while.

  32. Marcello Nuccio on 26 Apr 14:25:

    How can I update http://ap.rubyonrails.org/classes/ActionController/Layout/ClassMethods.html ?

  33. Marcel Molina Jr. on 26 Apr 14:41:

    All the related documentation was updated before this post was made. The documentation at api.rubyonrails.org is updated when a new release is made. For those using edge rails, you see the updated documentation here: http://caboo.se/doc/

  34. Henning Pedersen on 27 Apr 19:16:

    Oh… Just one of those things I really wish I knew a while ago. Always wondered about this. Guess that’s why I should’ve really learned ruby before diving into rails :) /agree with a lot of posters here though. We really do need a “best practices” cheat sheet kind of thing. I don’t feel I have the “oomph” to write it, though.

  35. Khan on 29 Apr 05:10:

    All the related documentation was updated before this post was made.

    Wouldn’t that be nice. In fact, vendor/rails/actionpack/README.html still recommends @content_for_layout and @params.

  36. Jay on 02 May 12:49:

    For real Ruby/Rails newbies, will anyone please explains how the params (without @) works. I understand @params is an attribute of the controller, but what is params? A named parameter? Because I thought instance attributes always begin with "@”, so params/request/etc looks like a local variable.

  37. Mike van Lammeren on 03 May 15:19:

    Kevin Marsh’s comment about the PHP site is absolutely correct. I believe that the PHP documentation is just incredible. A similar site for both Ruby and Rails would lead to an explosion of developers. Whether you have an interest in PHP or not, if you have never visited the site, then you should definitely do so.

    (PHP Manual)

  38. foobario on 05 May 20:37:

    “All the related documentation was updated before this post was made. The documentation at api.rubyonrails.org is updated when a new release is made.”

    I agree with Marc Baumbach – for those of us just starting out (and getting our info from, for instance, Agile 1) changes to the API mean little when the generators are generating deprecated code. Some of us aren’t far enough up to speed for reading the raw API, and the learning curve will be even steeper since we’re establishing patterns of usage that have become outdated.